summaryrefslogtreecommitdiff
path: root/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'javascript')
-rw-r--r--javascript/Makefile34
-rw-r--r--javascript/WebIDL/Makefile57
-rw-r--r--javascript/WebIDL/console.idl24
-rw-r--r--javascript/WebIDL/cssom.idl157
-rw-r--r--javascript/WebIDL/dom-parsing.idl35
-rw-r--r--javascript/WebIDL/dom.idl479
-rw-r--r--javascript/WebIDL/html.idl2288
-rw-r--r--javascript/WebIDL/uievents.idl185
-rw-r--r--javascript/WebIDL/urlutils.idl65
-rw-r--r--javascript/content.c120
-rw-r--r--javascript/content.h1
-rw-r--r--javascript/duktape/Console.bnd177
-rw-r--r--javascript/duktape/Document.bnd445
-rw-r--r--javascript/duktape/Element.bnd379
-rw-r--r--javascript/duktape/Event.bnd150
-rw-r--r--javascript/duktape/HTMLAnchorElement.bnd39
-rw-r--r--javascript/duktape/HTMLAppletElement.bnd30
-rw-r--r--javascript/duktape/HTMLAreaElement.bnd26
-rw-r--r--javascript/duktape/HTMLBRElement.bnd14
-rw-r--r--javascript/duktape/HTMLBaseElement.bnd17
-rw-r--r--javascript/duktape/HTMLBodyElement.bnd24
-rw-r--r--javascript/duktape/HTMLButtonElement.bnd18
-rw-r--r--javascript/duktape/HTMLCollection.bnd24
-rw-r--r--javascript/duktape/HTMLDivElement.bnd14
-rw-r--r--javascript/duktape/HTMLElement.bnd162
-rw-r--r--javascript/duktape/HTMLFontElement.bnd20
-rw-r--r--javascript/duktape/HTMLFormElement.bnd26
-rw-r--r--javascript/duktape/HTMLFrameElement.bnd35
-rw-r--r--javascript/duktape/HTMLFrameSetElement.bnd17
-rw-r--r--javascript/duktape/HTMLHRElement.bnd24
-rw-r--r--javascript/duktape/HTMLHTMLElement.bnd14
-rw-r--r--javascript/duktape/HTMLHeadingElement.bnd14
-rw-r--r--javascript/duktape/HTMLIFrameElement.bnd41
-rw-r--r--javascript/duktape/HTMLImageElement.bnd47
-rw-r--r--javascript/duktape/HTMLInputElement.bnd64
-rw-r--r--javascript/duktape/HTMLLIElement.bnd17
-rw-r--r--javascript/duktape/HTMLLabelElement.bnd14
-rw-r--r--javascript/duktape/HTMLLegendElement.bnd14
-rw-r--r--javascript/duktape/HTMLLinkElement.bnd35
-rw-r--r--javascript/duktape/HTMLMapElement.bnd14
-rw-r--r--javascript/duktape/HTMLMarqueeElement.bnd11
-rw-r--r--javascript/duktape/HTMLMenuElement.bnd14
-rw-r--r--javascript/duktape/HTMLMetaElement.bnd23
-rw-r--r--javascript/duktape/HTMLOListElement.bnd18
-rw-r--r--javascript/duktape/HTMLObjectElement.bnd54
-rw-r--r--javascript/duktape/HTMLOptionElement.bnd28
-rw-r--r--javascript/duktape/HTMLParagraphElement.bnd14
-rw-r--r--javascript/duktape/HTMLParamElement.bnd23
-rw-r--r--javascript/duktape/HTMLPreElement.bnd15
-rw-r--r--javascript/duktape/HTMLQuoteElement.bnd14
-rw-r--r--javascript/duktape/HTMLScriptElement.bnd32
-rw-r--r--javascript/duktape/HTMLSelectElement.bnd26
-rw-r--r--javascript/duktape/HTMLStyleElement.bnd17
-rw-r--r--javascript/duktape/HTMLTableCaptionElement.bnd14
-rw-r--r--javascript/duktape/HTMLTableCellElement.bnd46
-rw-r--r--javascript/duktape/HTMLTableColElement.bnd26
-rw-r--r--javascript/duktape/HTMLTableElement.bnd38
-rw-r--r--javascript/duktape/HTMLTableRowElement.bnd30
-rw-r--r--javascript/duktape/HTMLTableSectionElement.bnd23
-rw-r--r--javascript/duktape/HTMLTextAreaElement.bnd30
-rw-r--r--javascript/duktape/HTMLTitleElement.bnd14
-rw-r--r--javascript/duktape/Location.bnd353
-rw-r--r--javascript/duktape/Makefile40
-rw-r--r--javascript/duktape/Navigator.bnd87
-rw-r--r--javascript/duktape/Node.bnd479
-rw-r--r--javascript/duktape/NodeList.bnd54
-rw-r--r--javascript/duktape/Window.bnd146
-rw-r--r--javascript/duktape/duk_config.h3753
-rw-r--r--javascript/duktape/duk_custom.h37
-rw-r--r--javascript/duktape/dukky.c1135
-rw-r--r--javascript/duktape/dukky.h45
-rw-r--r--javascript/duktape/duktape.c86513
-rw-r--r--javascript/duktape/duktape.h1567
-rw-r--r--javascript/duktape/netsurf.bnd200
-rw-r--r--javascript/fetcher.c217
-rw-r--r--javascript/fetcher.h28
-rw-r--r--javascript/js.h102
-rw-r--r--javascript/none/Makefile9
-rw-r--r--javascript/none/none.c70
79 files changed, 0 insertions, 100705 deletions
diff --git a/javascript/Makefile b/javascript/Makefile
deleted file mode 100644
index 36f123b64..000000000
--- a/javascript/Makefile
+++ /dev/null
@@ -1,34 +0,0 @@
-#
-# NetSurf javascript source file inclusion
-#
-# Included by Makefile
-#
-
-# Check if jsapi is required
-ifeq ($(NETSURF_USE_JS),YES)
-WANT_JS_SOURCE := YES
-else
-ifeq ($(NETSURF_USE_MOZJS),YES)
-WANT_JS_SOURCE := YES
-endif
-endif
-
-S_JAVASCRIPT_BINDING:=
-
-ifeq ($(WANT_JS_SOURCE),YES)
-# JSAPI (spidemonkey)
-include javascript/jsapi/Makefile
-else
-ifeq ($(NETSURF_USE_DUKTAPE),YES)
-# Duktape
-include javascript/duktape/Makefile
-else
-# None
-include javascript/none/Makefile
-endif
-endif
-
-# Fetcher for javascript scheme is always required
-S_JAVASCRIPT += fetcher.c
-
-S_JAVASCRIPT := $(addprefix javascript/,$(S_JAVASCRIPT)) $(S_JAVASCRIPT_BINDING)
diff --git a/javascript/WebIDL/Makefile b/javascript/WebIDL/Makefile
deleted file mode 100644
index 7d901cee1..000000000
--- a/javascript/WebIDL/Makefile
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/make
-#
-# Create the WebIDL for core DOM and HTML spec directly from
-# downloaded specifications. The resulting IDL is pretty close but
-# should be manually cleaned up and tagged with the retrival date and
-# source URL
-#
-# The dom spec has an index on the end that contains all the IDL a
-# second time! be aware htis needs removing or your IDL will have two
-# copies of all interfaces which is bad.
-#
-# needs debian packages: curl w3m tidy html-xml-utils
-#
-# Copyright 2012 Vincent Sanders
-# MIT licenced
-
-.PHONY:all clean
-
-all: dom.idl html.idl uievents.idl cssom.idl
-
-.INTERMEDIATE:dom-spec.html dom-spec.xml dom-idl.html
-.INTERMEDIATE:html-spec.html html-spec.xml html-idl.html
-.INTERMEDIATE:uievents-spec.html uievents-spec.xml uievents-idl.html
-.INTERMEDIATE:urlutils-spec.html urlutils-spec.xml urlutils-idl.html
-.INTERMEDIATE:cssom-spec.html cssom-spec.xml cssom-idl.html
-
-dom-spec.html:
- curl -s https://dom.spec.whatwg.org/ -o $@
-
-html-spec.html:
- curl -s https://html.spec.whatwg.org/ -o $@
-
-uievents-spec.html:
- curl -s http://www.w3.org/TR/uievents/ -o $@
-
-urlutils-spec.html:
- curl -s https://url.spec.whatwg.org/ -o $@
-
-cssom-spec.html:
- curl -s https://drafts.csswg.org/cssom-1/ -o $@
-
-%-spec.xml: %-spec.html
- -tidy -q -f $@.errors --new-blocklevel-tags header,hgroup,figure,time,main,nav,svg,rect,text,image,mark,figcaption,section,g,path,circle -o $@ -asxml $<
-
-%-idl.html: %-spec.xml
- hxselect 'pre[class="idl"]' < $< > $@
-
-%.idl: %-idl.html
- @echo "// Retrived from " >$@
- @echo "// $$(date)" >>$@
- @echo "" >>$@
- @echo "" >>$@
- cat $< | w3m -dump -T text/html >>$@
-
-
-clean:
- ${RM} dom.idl html.idl uievents.idl dom-spec.html dom-spec.xml dom-idl.html html-spec.html html-spec.xml html-idl.html uievents-spec.html uievents-spec.xml uievents-idl.html uievents-spec.xml.errors
diff --git a/javascript/WebIDL/console.idl b/javascript/WebIDL/console.idl
deleted file mode 100644
index 5a3d9eb27..000000000
--- a/javascript/WebIDL/console.idl
+++ /dev/null
@@ -1,24 +0,0 @@
-// de facto set of features for console object
-// https://developer.mozilla.org/en-US/docs/DOM/console
-// http://msdn.microsoft.com/en-us/library/dd565625%28v=vs.85%29.aspx#consolelogging
-// 31st October
-// Yay for non-standard standards
-
-interface Console {
- void debug(DOMString msg, Substitition... subst);
- void dir(JSObject object);
- void error(DOMString msg, Substitition... subst);
- void group();
- void groupCollapsed();
- void groupEnd();
- void info(DOMString msg, Substitition... subst);
- void log(DOMString msg, Substitition... subst);
- void time(DOMString timerName);
- void timeEnd(DOMString timerName);
- void trace();
- void warn(DOMString msg, Substitition... subst);
-};
-
-partial interface Window {
- readonly attribute Console console;
-}; \ No newline at end of file
diff --git a/javascript/WebIDL/cssom.idl b/javascript/WebIDL/cssom.idl
deleted file mode 100644
index 95c97e42a..000000000
--- a/javascript/WebIDL/cssom.idl
+++ /dev/null
@@ -1,157 +0,0 @@
-// Retrived from https://drafts.csswg.org/cssom-1/
-// Wed Nov 4 15:39:43 GMT 2015
-// Removed duplicate IDL from appendix
-
-
-[ArrayClass]interface MediaList {
- [TreatNullAs=EmptyString] stringifier attribute DOMString mediaText;
- readonly attribute unsigned long length;
- getter DOMString? item(unsigned long index );
- void appendMedium(DOMString medium );
- void deleteMedium(DOMString medium );
-};
-
-interface StyleSheet {
- readonly attribute DOMString type;
- readonly attribute DOMString? href;
- readonly attribute (Element or ProcessingInstruction)? ownerNode;
- readonly attribute StyleSheet? parentStyleSheet;
- readonly attribute DOMString? title;
- [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
- attribute boolean disabled;
-};
-
-interface CSSStyleSheet : StyleSheet {
- readonly attribute CSSRule? ownerRule;
- [SameObject] readonly attribute CSSRuleList cssRules;
- unsigned long insertRule(DOMString rule , unsigned long index );
- void deleteRule(unsigned long index );
-};
-
-[ArrayClass]interface StyleSheetList {
- getter StyleSheet? item(unsigned long index );
- readonly attribute unsigned long length;
-};
-
-partial interface Document {
- [SameObject] readonly attribute StyleSheetList styleSheets;
- attribute DOMString? selectedStyleSheetSet;
- readonly attribute DOMString? lastStyleSheetSet;
- readonly attribute DOMString? preferredStyleSheetSet;
- readonly attribute DOMString[] styleSheetSets;
- void enableStyleSheetsForSet(DOMString? name );
-};
-
-[NoInterfaceObject]interface LinkStyle {
- readonly attribute StyleSheet? sheet;
-};
-
-ProcessingInstruction implements LinkStyle;
-
-[ArrayClass]interface CSSRuleList {
- getter CSSRule? item(unsigned long index );
- readonly attribute unsigned long length;
-};
-
-interface CSSRule {
- const unsigned short STYLE_RULE = 1;
- const unsigned short CHARSET_RULE = 2; // historical
- const unsigned short IMPORT_RULE = 3;
- const unsigned short MEDIA_RULE = 4;
- const unsigned short FONT_FACE_RULE = 5;
- const unsigned short PAGE_RULE = 6;
- const unsigned short MARGIN_RULE = 9;
- const unsigned short NAMESPACE_RULE = 10;
- readonly attribute unsigned short type;
- attribute DOMString cssText;
- readonly attribute CSSRule? parentRule;
- readonly attribute CSSStyleSheet? parentStyleSheet;
-};
-
-interface CSSStyleRule : CSSRule {
- attribute DOMString selectorText;
- [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
-};
-
-interface CSSImportRule : CSSRule {
- readonly attribute DOMString href;
- [SameObject, PutForwards=mediaText] readonly attribute MediaList media;
- [SameObject] readonly attribute CSSStyleSheet styleSheet;
-};
-
-interface CSSGroupingRule : CSSRule {
- [SameObject] readonly attribute CSSRuleList cssRules;
- unsigned long insertRule(DOMString rule , unsigned long index );
- void deleteRule(unsigned long index );
-};
-
-interface CSSMediaRule : CSSGroupingRule {
- [SameObject, PutForwards=mediaText] readonly attribute MediaList media ;
-};
-
-interface CSSPageRule : CSSGroupingRule {
- attribute DOMString selectorText ;
- [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style ;
-};
-
-interface CSSMarginRule : CSSRule {
- readonly attribute DOMString name;
- [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
-};
-
-interface CSSNamespaceRule : CSSRule {
- readonly attribute DOMString namespaceURI;
- readonly attribute DOMString prefix;
-};
-
-interface CSSStyleDeclaration {
- attribute DOMString cssText;
- readonly attribute unsigned long length;
- getter DOMString item(unsigned long index );
- DOMString getPropertyValue(DOMString property );
- DOMString getPropertyPriority(DOMString property );
- void setProperty(DOMString property , [TreatNullAs=EmptyString] DOMString value , [TreatNullAs=EmptyString] optional DOMString priority = "");
- void setPropertyValue(DOMString property , [TreatNullAs=EmptyString] DOMString value );
- void setPropertyPriority(DOMString property , [TreatNullAs=EmptyString] DOMString priority );
- DOMString removeProperty(DOMString property );
- readonly attribute CSSRule? parentRule;
- [TreatNullAs=EmptyString] attribute DOMString cssFloat;
-};
-
-partial interface CSSStyleDeclaration {
- [TreatNullAs=EmptyString] attribute DOMString _dashed_attribute ;
-};
-
-[NoInterfaceObject]interface ElementCSSInlineStyle {
- [SameObject, PutForwards=cssText] readonly attribute CSSStyleDeclaration style;
-};
-
-HTMLElement implements ElementCSSInlineStyle;
-
-SVGElement implements ElementCSSInlineStyle;
-
-partial interface Window {
- [NewObject] CSSStyleDeclaration getComputedStyle(Element elt , optional DOMString? pseudoElt );
-};
-
-[NoInterfaceObject]interface GetStyleUtils {
- [SameObject] readonly attribute CSSStyleDeclaration cascadedStyle;
- [SameObject] readonly attribute CSSStyleDeclaration defaultStyle;
- [SameObject] readonly attribute CSSStyleDeclaration rawComputedStyle;
- [SameObject] readonly attribute CSSStyleDeclaration usedStyle;
-};
-
-partial interface Element {
- PseudoElement? pseudo(DOMString pseudoElt );
-};
-
-Element implements GetStyleUtils;
-
-interface PseudoElement {
-};
-
-PseudoElement implements GetStyleUtils;
-
-interface CSS {
- static DOMString escape(DOMString ident );
-};
diff --git a/javascript/WebIDL/dom-parsing.idl b/javascript/WebIDL/dom-parsing.idl
deleted file mode 100644
index d2581328e..000000000
--- a/javascript/WebIDL/dom-parsing.idl
+++ /dev/null
@@ -1,35 +0,0 @@
-// Retrived from http://www.w3.org/TR/DOM-Parsing/
-// Wed Nov 4 15:39:43 GMT 2015
-// Manually extracted IDL
-
-enum SupportedType {
- "text/html",
- "text/xml",
- "application/xml",
- "application/xhtml+xml",
- "image/svg+xml"
-};
-
-[Constructor]
-interface DOMParser {
- [NewObject]
- Document parseFromString (DOMString str, SupportedType type);
-};
-
-[Constructor]
-interface XMLSerializer {
- DOMString serializeToString (Node root);
-};
-
-partial interface Element {
- [TreatNullAs=EmptyString]
- attribute DOMString innerHTML;
- [TreatNullAs=EmptyString]
- attribute DOMString outerHTML;
- void insertAdjacentHTML (DOMString position, DOMString text);
-};
-
-partial interface Range {
- [NewObject]
- DocumentFragment createContextualFragment (DOMString fragment);
-};
diff --git a/javascript/WebIDL/dom.idl b/javascript/WebIDL/dom.idl
deleted file mode 100644
index 1c9e75bd8..000000000
--- a/javascript/WebIDL/dom.idl
+++ /dev/null
@@ -1,479 +0,0 @@
-// DOM web IDL
-// Retrived from https://dom.spec.whatwg.org/
-// Sat Jul 18 2015
-
-
-[Constructor(DOMString type, optional EventInit eventInitDict),
- Exposed=(Window,Worker)]
-interface Event {
- readonly attribute DOMString type;
- readonly attribute EventTarget? target;
- readonly attribute EventTarget? currentTarget;
-
- const unsigned short NONE = 0;
- const unsigned short CAPTURING_PHASE = 1;
- const unsigned short AT_TARGET = 2;
- const unsigned short BUBBLING_PHASE = 3;
- readonly attribute unsigned short eventPhase;
-
- void stopPropagation();
- void stopImmediatePropagation();
-
- readonly attribute boolean bubbles;
- readonly attribute boolean cancelable;
- void preventDefault();
- readonly attribute boolean defaultPrevented;
-
- [Unforgeable] readonly attribute boolean isTrusted;
- readonly attribute DOMTimeStamp timeStamp;
-
- void initEvent(DOMString type, boolean bubbles, boolean cancelable);
-};
-
-dictionary EventInit {
- boolean bubbles = false;
- boolean cancelable = false;
-};
-
-[Constructor(DOMString type, optional CustomEventInit eventInitDict),
- Exposed=(Window,Worker)]
-interface CustomEvent : Event {
- readonly attribute any detail;
-
- void initCustomEvent(DOMString type, boolean bubbles, boolean cancelable, any detail);
-};
-
-dictionary CustomEventInit : EventInit {
- any detail = null;
-};
-
-[Exposed=(Window,Worker)]
-interface EventTarget {
- void addEventListener(DOMString type, EventListener? callback, optional boolean capture = false);
- void removeEventListener(DOMString type, EventListener? callback, optional boolean capture = false);
- boolean dispatchEvent(Event event);
-};
-
-callback interface EventListener {
- void handleEvent(Event event);
-};
-
-[NoInterfaceObject,
- Exposed=Window]
-interface NonElementParentNode {
- Element? getElementById(DOMString elementId);
-};
-Document implements NonElementParentNode;
-DocumentFragment implements NonElementParentNode;
-
-[NoInterfaceObject,
- Exposed=Window]
-interface ParentNode {
- [SameObject] readonly attribute HTMLCollection children;
- readonly attribute Element? firstElementChild;
- readonly attribute Element? lastElementChild;
- readonly attribute unsigned long childElementCount;
-
- [Unscopeable] void prepend((Node or DOMString)... nodes);
- [Unscopeable] void append((Node or DOMString)... nodes);
-
- [Unscopeable] Element? query(DOMString relativeSelectors);
- [NewObject, Unscopeable] Elements queryAll(DOMString relativeSelectors);
- Element? querySelector(DOMString selectors);
- [NewObject] NodeList querySelectorAll(DOMString selectors);
-};
-Document implements ParentNode;
-DocumentFragment implements ParentNode;
-Element implements ParentNode;
-
-[NoInterfaceObject,
- Exposed=Window]
-interface NonDocumentTypeChildNode {
- readonly attribute Element? previousElementSibling;
- readonly attribute Element? nextElementSibling;
-};
-Element implements NonDocumentTypeChildNode;
-CharacterData implements NonDocumentTypeChildNode;
-
-[NoInterfaceObject,
- Exposed=Window]
-interface ChildNode {
- [Unscopeable] void before((Node or DOMString)... nodes);
- [Unscopeable] void after((Node or DOMString)... nodes);
- [Unscopeable] void replaceWith((Node or DOMString)... nodes);
- [Unscopeable] void remove();
-};
-DocumentType implements ChildNode;
-Element implements ChildNode;
-CharacterData implements ChildNode;
-
-//class Elements extends Array {
-// Element? query(DOMString relativeSelectors);
-// Elements queryAll(DOMString relativeSelectors);
-//};
-
-[Exposed=Window]
-interface NodeList {
- getter Node? item(unsigned long index);
- readonly attribute unsigned long length;
- iterable<Node>;
-};
-
-[Exposed=Window]
-interface HTMLCollection {
- readonly attribute unsigned long length;
- getter Element? item(unsigned long index);
- getter Element? namedItem(DOMString name);
-};
-
-[Constructor(MutationCallback callback)]
-interface MutationObserver {
- void observe(Node target, MutationObserverInit options);
- void disconnect();
- sequence<MutationRecord> takeRecords();
-};
-
-callback MutationCallback = void (sequence<MutationRecord> mutations, MutationObserver observer);
-
-dictionary MutationObserverInit {
- boolean childList = false;
- boolean attributes;
- boolean characterData;
- boolean subtree = false;
- boolean attributeOldValue;
- boolean characterDataOldValue;
- sequence<DOMString> attributeFilter;
-};
-
-[Exposed=Window]
-interface MutationRecord {
- readonly attribute DOMString type;
- readonly attribute Node target;
- [SameObject] readonly attribute NodeList addedNodes;
- [SameObject] readonly attribute NodeList removedNodes;
- readonly attribute Node? previousSibling;
- readonly attribute Node? nextSibling;
- readonly attribute DOMString? attributeName;
- readonly attribute DOMString? attributeNamespace;
- readonly attribute DOMString? oldValue;
-};
-
-[Exposed=Window]
-interface Node : EventTarget {
- const unsigned short ELEMENT_NODE = 1;
- const unsigned short ATTRIBUTE_NODE = 2; // historical
- const unsigned short TEXT_NODE = 3;
- const unsigned short CDATA_SECTION_NODE = 4; // historical
- const unsigned short ENTITY_REFERENCE_NODE = 5; // historical
- const unsigned short ENTITY_NODE = 6; // historical
- const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
- const unsigned short COMMENT_NODE = 8;
- const unsigned short DOCUMENT_NODE = 9;
- const unsigned short DOCUMENT_TYPE_NODE = 10;
- const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
- const unsigned short NOTATION_NODE = 12; // historical
- readonly attribute unsigned short nodeType;
- readonly attribute DOMString nodeName;
-
- readonly attribute DOMString? baseURI;
-
- readonly attribute Document? ownerDocument;
- readonly attribute Node? parentNode;
- readonly attribute Element? parentElement;
- boolean hasChildNodes();
- [SameObject] readonly attribute NodeList childNodes;
- readonly attribute Node? firstChild;
- readonly attribute Node? lastChild;
- readonly attribute Node? previousSibling;
- readonly attribute Node? nextSibling;
-
- attribute DOMString? nodeValue;
- attribute DOMString? textContent;
- void normalize();
-
- [NewObject] Node cloneNode(optional boolean deep = false);
- boolean isEqualNode(Node? otherNode);
-
- const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
- const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02;
- const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04;
- const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08;
- const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10;
- const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
- unsigned short compareDocumentPosition(Node other);
- boolean contains(Node? other);
-
- DOMString? lookupPrefix(DOMString? namespace);
- DOMString? lookupNamespaceURI(DOMString? prefix);
- boolean isDefaultNamespace(DOMString? namespace);
-
- Node insertBefore(Node node, Node? child);
- Node appendChild(Node node);
- Node replaceChild(Node node, Node child);
- Node removeChild(Node child);
-};
-
-[Constructor,
- Exposed=Window]
-interface Document : Node {
- [SameObject] readonly attribute DOMImplementation implementation;
- readonly attribute DOMString URL;
- readonly attribute DOMString documentURI;
- readonly attribute DOMString origin;
- readonly attribute DOMString compatMode;
- readonly attribute DOMString characterSet;
- readonly attribute DOMString inputEncoding; // legacy alias of .characterSet
- readonly attribute DOMString contentType;
-
- readonly attribute DocumentType? doctype;
- readonly attribute Element? documentElement;
- HTMLCollection getElementsByTagName(DOMString localName);
- HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
- HTMLCollection getElementsByClassName(DOMString classNames);
-
- [NewObject] Element createElement(DOMString localName);
- [NewObject] Element createElementNS(DOMString? namespace, DOMString qualifiedName);
- [NewObject] DocumentFragment createDocumentFragment();
- [NewObject] Text createTextNode(DOMString data);
- [NewObject] Comment createComment(DOMString data);
- [NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);
-
- [NewObject] Node importNode(Node node, optional boolean deep = false);
- Node adoptNode(Node node);
-
- [NewObject] Attr createAttribute(DOMString localName);
- [NewObject] Attr createAttributeNS(DOMString? namespace, DOMString name);
-
- [NewObject] Event createEvent(DOMString interface);
-
- [NewObject] Range createRange();
-
- // NodeFilter.SHOW_ALL = 0xFFFFFFFF
- [NewObject] NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
- [NewObject] TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
-};
-
-[Exposed=Window]
-interface XMLDocument : Document {};
-
-[Exposed=Window]
-interface DOMImplementation {
- [NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId);
- [NewObject] XMLDocument createDocument(DOMString? namespace, [TreatNullAs=EmptyString] DOMString qualifiedName, optional DocumentType? doctype = null);
- [NewObject] Document createHTMLDocument(optional DOMString title);
-
- boolean hasFeature(); // useless; always returns true
-};
-
-[Constructor,
- Exposed=Window]
-interface DocumentFragment : Node {
-};
-
-[Exposed=Window]
-interface DocumentType : Node {
- readonly attribute DOMString name;
- readonly attribute DOMString publicId;
- readonly attribute DOMString systemId;
-};
-
-[Exposed=Window]
-interface Element : Node {
- readonly attribute DOMString? namespaceURI;
- readonly attribute DOMString? prefix;
- readonly attribute DOMString localName;
- readonly attribute DOMString tagName;
-
- attribute DOMString id;
- attribute DOMString className;
- [SameObject] readonly attribute DOMTokenList classList;
-
- boolean hasAttributes();
- [SameObject] readonly attribute NamedNodeMap attributes;
- DOMString? getAttribute(DOMString name);
- DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
- void setAttribute(DOMString name, DOMString value);
- void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
- void removeAttribute(DOMString name);
- void removeAttributeNS(DOMString? namespace, DOMString localName);
- boolean hasAttribute(DOMString name);
- boolean hasAttributeNS(DOMString? namespace, DOMString localName);
-
- Attr? getAttributeNode(DOMString name);
- Attr? getAttributeNodeNS(DOMString? namespace, DOMString localName);
- Attr? setAttributeNode(Attr attr);
- Attr? setAttributeNodeNS(Attr attr);
- Attr removeAttributeNode(Attr attr);
-
- Element? closest(DOMString selectors);
- boolean matches(DOMString selectors);
-
- HTMLCollection getElementsByTagName(DOMString localName);
- HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
- HTMLCollection getElementsByClassName(DOMString classNames);
-};
-[Exposed=Window]
-interface NamedNodeMap {
- readonly attribute unsigned long length;
- getter Attr? item(unsigned long index);
- getter Attr? getNamedItem(DOMString name);
- Attr? getNamedItemNS(DOMString? namespace, DOMString localName);
- Attr? setNamedItem(Attr attr);
- Attr? setNamedItemNS(Attr attr);
- Attr removeNamedItem(DOMString name);
- Attr removeNamedItemNS(DOMString? namespace, DOMString localName);
-};
-
-[Exposed=Window]
-interface Attr {
- readonly attribute DOMString? namespaceURI;
- readonly attribute DOMString? prefix;
- readonly attribute DOMString localName;
- readonly attribute DOMString name;
- attribute DOMString value;
- [TreatNullAs=EmptyString] attribute DOMString nodeValue; // legacy alias of .value
- [TreatNullAs=EmptyString] attribute DOMString textContent; // legacy alias of .value
-
- readonly attribute Element? ownerElement;
-
- readonly attribute boolean specified; // useless; always returns true
-};
-[Exposed=Window]
-interface CharacterData : Node {
- [TreatNullAs=EmptyString] attribute DOMString data;
- readonly attribute unsigned long length;
- DOMString substringData(unsigned long offset, unsigned long count);
- void appendData(DOMString data);
- void insertData(unsigned long offset, DOMString data);
- void deleteData(unsigned long offset, unsigned long count);
- void replaceData(unsigned long offset, unsigned long count, DOMString data);
-};
-
-[Constructor(optional DOMString data = ""),
- Exposed=Window]
-interface Text : CharacterData {
- [NewObject] Text splitText(unsigned long offset);
- readonly attribute DOMString wholeText;
-};
-[Exposed=Window]
-interface ProcessingInstruction : CharacterData {
- readonly attribute DOMString target;
-};
-[Constructor(optional DOMString data = ""),
- Exposed=Window]
-interface Comment : CharacterData {
-};
-
-[Constructor,
- Exposed=Window]
-interface Range {
- readonly attribute Node startContainer;
- readonly attribute unsigned long startOffset;
- readonly attribute Node endContainer;
- readonly attribute unsigned long endOffset;
- readonly attribute boolean collapsed;
- readonly attribute Node commonAncestorContainer;
-
- void setStart(Node node, unsigned long offset);
- void setEnd(Node node, unsigned long offset);
- void setStartBefore(Node node);
- void setStartAfter(Node node);
- void setEndBefore(Node node);
- void setEndAfter(Node node);
- void collapse(optional boolean toStart = false);
- void selectNode(Node node);
- void selectNodeContents(Node node);
-
- const unsigned short START_TO_START = 0;
- const unsigned short START_TO_END = 1;
- const unsigned short END_TO_END = 2;
- const unsigned short END_TO_START = 3;
- short compareBoundaryPoints(unsigned short how, Range sourceRange);
-
- void deleteContents();
- [NewObject] DocumentFragment extractContents();
- [NewObject] DocumentFragment cloneContents();
- void insertNode(Node node);
- void surroundContents(Node newParent);
-
- [NewObject] Range cloneRange();
- void detach();
-
- boolean isPointInRange(Node node, unsigned long offset);
- short comparePoint(Node node, unsigned long offset);
-
- boolean intersectsNode(Node node);
-
- stringifier;
-};
-
-[Exposed=Window]
-interface NodeIterator {
- [SameObject] readonly attribute Node root;
- readonly attribute Node referenceNode;
- readonly attribute boolean pointerBeforeReferenceNode;
- readonly attribute unsigned long whatToShow;
- readonly attribute NodeFilter? filter;
-
- Node? nextNode();
- Node? previousNode();
-
- void detach();
-};
-
-[Exposed=Window]
-interface TreeWalker {
- [SameObject] readonly attribute Node root;
- readonly attribute unsigned long whatToShow;
- readonly attribute NodeFilter? filter;
- attribute Node currentNode;
-
- Node? parentNode();
- Node? firstChild();
- Node? lastChild();
- Node? previousSibling();
- Node? nextSibling();
- Node? previousNode();
- Node? nextNode();
-};
-[Exposed=Window]
-callback interface NodeFilter {
- // Constants for acceptNode()
- const unsigned short FILTER_ACCEPT = 1;
- const unsigned short FILTER_REJECT = 2;
- const unsigned short FILTER_SKIP = 3;
-
- // Constants for whatToShow
- const unsigned long SHOW_ALL = 0xFFFFFFFF;
- const unsigned long SHOW_ELEMENT = 0x1;
- const unsigned long SHOW_ATTRIBUTE = 0x2; // historical
- const unsigned long SHOW_TEXT = 0x4;
- const unsigned long SHOW_CDATA_SECTION = 0x8; // historical
- const unsigned long SHOW_ENTITY_REFERENCE = 0x10; // historical
- const unsigned long SHOW_ENTITY = 0x20; // historical
- const unsigned long SHOW_PROCESSING_INSTRUCTION = 0x40;
- const unsigned long SHOW_COMMENT = 0x80;
- const unsigned long SHOW_DOCUMENT = 0x100;
- const unsigned long SHOW_DOCUMENT_TYPE = 0x200;
- const unsigned long SHOW_DOCUMENT_FRAGMENT = 0x400;
- const unsigned long SHOW_NOTATION = 0x800; // historical
-
- unsigned short acceptNode(Node node);
-};
-
-interface DOMTokenList {
- readonly attribute unsigned long length;
- getter DOMString? item(unsigned long index);
- boolean contains(DOMString token);
- void add(DOMString... tokens);
- void remove(DOMString... tokens);
- boolean toggle(DOMString token, optional boolean force);
- stringifier;
- iterable<DOMString>;
-};
-
-interface DOMSettableTokenList : DOMTokenList {
- attribute DOMString value;
-};
-
-
diff --git a/javascript/WebIDL/html.idl b/javascript/WebIDL/html.idl
deleted file mode 100644
index 73112f002..000000000
--- a/javascript/WebIDL/html.idl
+++ /dev/null
@@ -1,2288 +0,0 @@
-// HTML web IDL
-// Retrived from https://html.spec.whatwg.org/
-// Mon Oct 5 2015
-
-
-typedef (Int8Array or Uint8Array or Uint8ClampedArray or
- Int16Array or Uint16Array or
- Int32Array or Uint32Array or
- Float32Array or Float64Array or
- DataView) ArrayBufferView;
-
-interface HTMLAllCollection {
- readonly attribute unsigned long length;
- getter Element? item(unsigned long index);
- (HTMLCollection or Element)? item(DOMString name);
- legacycaller getter (HTMLCollection or Element)? namedItem(DOMString name);
-};
-
-interface HTMLFormControlsCollection : HTMLCollection {
- // inherits length and item()
- getter (RadioNodeList or Element)? namedItem(DOMString name); // shadows inherited namedItem()
-};
-
-interface RadioNodeList : NodeList {
- attribute DOMString value;
-};
-
-interface HTMLOptionsCollection : HTMLCollection {
- // inherits item(), namedItem()
- attribute unsigned long length; // shadows inherited length
- setter void (unsigned long index, HTMLOptionElement? option);
- void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);
- void remove(long index);
- attribute long selectedIndex;
-};
-
-[OverrideBuiltins, Exposed=(Window,Worker)]
-interface DOMStringMap {
- getter DOMString (DOMString name);
- setter void (DOMString name, DOMString value);
- deleter void (DOMString name);
-};
-
-interface DOMElementMap {
- getter Element (DOMString name);
- setter void (DOMString name, Element value);
- deleter void (DOMString name);
-};
-
-typedef (ArrayBuffer or CanvasProxy or MessagePort) Transferable;
-
-callback FileCallback = void (File file);
-
-enum DocumentReadyState { "loading", "interactive", "complete" };
-
-[OverrideBuiltins]
-partial /*sealed*/ interface Document {
- // resource metadata management
- [PutForwards=href, Unforgeable] readonly attribute Location? location;
- attribute DOMString domain;
- readonly attribute DOMString referrer;
- attribute DOMString cookie;
- readonly attribute DOMString lastModified;
- readonly attribute DocumentReadyState readyState;
-
- // DOM tree accessors
- getter object (DOMString name);
- attribute DOMString title;
- attribute DOMString dir;
- attribute HTMLElement? body;
- readonly attribute HTMLHeadElement? head;
- [SameObject] readonly attribute HTMLCollection images;
- [SameObject] readonly attribute HTMLCollection embeds;
- [SameObject] readonly attribute HTMLCollection plugins;
- [SameObject] readonly attribute HTMLCollection links;
- [SameObject] readonly attribute HTMLCollection forms;
- [SameObject] readonly attribute HTMLCollection scripts;
- NodeList getElementsByName(DOMString elementName);
- [SameObject] readonly attribute DOMElementMap cssElementMap;
- readonly attribute HTMLScriptElement? currentScript;
-
- // dynamic markup insertion
- Document open(optional DOMString type = "text/html", optional DOMString replace = "");
- WindowProxy open(DOMString url, DOMString name, DOMString features, optional boolean replace = false);
- void close();
- void write(DOMString... text);
- void writeln(DOMString... text);
-
- // user interaction
- readonly attribute WindowProxy? defaultView;
- readonly attribute Element? activeElement;
- boolean hasFocus();
- attribute DOMString designMode;
- boolean execCommand(DOMString commandId, optional boolean showUI = false, optional DOMString value = "");
- boolean queryCommandEnabled(DOMString commandId);
- boolean queryCommandIndeterm(DOMString commandId);
- boolean queryCommandState(DOMString commandId);
- boolean queryCommandSupported(DOMString commandId);
- DOMString queryCommandValue(DOMString commandId);
- readonly attribute HTMLCollection commands;
-
- // special event handler IDL attributes that only apply to Document objects
- [LenientThis] attribute EventHandler onreadystatechange;
-
- // also has obsolete members
-};
-Document implements GlobalEventHandlers;
-
-partial interface XMLDocument {
- boolean load(DOMString url);
-};
-
-interface HTMLElement : Element {
- // metadata attributes
- attribute DOMString title;
- attribute DOMString lang;
- attribute boolean translate;
- attribute DOMString dir;
- [SameObject] readonly attribute DOMStringMap dataset;
-
- // user interaction
- attribute boolean hidden;
- void click();
- attribute long tabIndex;
- void focus();
- void blur();
- attribute DOMString accessKey;
- readonly attribute DOMString accessKeyLabel;
- attribute boolean draggable;
- [PutForwards=value] readonly attribute DOMSettableTokenList dropzone;
- attribute HTMLMenuElement? contextMenu;
- attribute boolean spellcheck;
- void forceSpellCheck();
-
- // command API
- readonly attribute DOMString? commandType;
- readonly attribute DOMString? commandLabel;
- readonly attribute DOMString? commandIcon;
- readonly attribute boolean? commandHidden;
- readonly attribute boolean? commandDisabled;
- readonly attribute boolean? commandChecked;
-};
-HTMLElement implements GlobalEventHandlers;
-HTMLElement implements ElementContentEditable;
-
-interface HTMLUnknownElement : HTMLElement { };
-
-interface HTMLHtmlElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLHeadElement : HTMLElement {};
-
-interface HTMLTitleElement : HTMLElement {
- attribute DOMString text;
-};
-
-interface HTMLBaseElement : HTMLElement {
- attribute DOMString href;
- attribute DOMString target;
-};
-
-interface HTMLLinkElement : HTMLElement {
- attribute DOMString href;
- attribute DOMString? crossOrigin;
- attribute DOMString rel;
- readonly attribute DOMTokenList relList;
- attribute DOMString media;
- attribute DOMString hreflang;
- attribute DOMString type;
- [PutForwards=value] readonly attribute DOMSettableTokenList sizes;
-
- // also has obsolete members
-};
-HTMLLinkElement implements LinkStyle;
-
-interface HTMLMetaElement : HTMLElement {
- attribute DOMString name;
- attribute DOMString httpEquiv;
- attribute DOMString content;
-
- // also has obsolete members
-};
-
-interface HTMLStyleElement : HTMLElement {
- attribute DOMString media;
- attribute DOMString nonce;
- attribute DOMString type;
- attribute boolean scoped;
-};
-HTMLStyleElement implements LinkStyle;
-
-interface HTMLBodyElement : HTMLElement {
-
- // also has obsolete members
-};
-HTMLBodyElement implements WindowEventHandlers;
-
-interface HTMLHeadingElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLParagraphElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLHRElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLPreElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLQuoteElement : HTMLElement {
- attribute DOMString cite;
-};
-
-interface HTMLOListElement : HTMLElement {
- attribute boolean reversed;
- attribute long start;
- attribute DOMString type;
-
- // also has obsolete members
-};
-
-interface HTMLUListElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLLIElement : HTMLElement {
- attribute long value;
-
- // also has obsolete members
-};
-
-interface HTMLDListElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLDivElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLAnchorElement : HTMLElement {
- attribute DOMString target;
- attribute DOMString download;
- [PutForwards=value] readonly attribute DOMSettableTokenList ping;
- attribute DOMString rel;
- readonly attribute DOMTokenList relList;
- attribute DOMString hreflang;
- attribute DOMString type;
-
- attribute DOMString text;
-
- // also has obsolete members
-};
-HTMLAnchorElement implements URLUtils;
-
-interface HTMLDataElement : HTMLElement {
- attribute DOMString value;
-};
-
-interface HTMLTimeElement : HTMLElement {
- attribute DOMString dateTime;
-};
-
-interface HTMLSpanElement : HTMLElement {};
-
-interface HTMLBRElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLModElement : HTMLElement {
- attribute DOMString cite;
- attribute DOMString dateTime;
-};
-
-interface HTMLPictureElement : HTMLElement {};
-
-partial interface HTMLSourceElement {
- attribute DOMString srcset;
- attribute DOMString sizes;
- attribute DOMString media;
-};
-
-[NamedConstructor=Image(optional unsigned long width, optional unsigned long height)]
-interface HTMLImageElement : HTMLElement {
- attribute DOMString alt;
- attribute DOMString src;
- attribute DOMString srcset;
- attribute DOMString sizes;
- attribute DOMString? crossOrigin;
- attribute DOMString useMap;
- attribute boolean isMap;
- attribute unsigned long width;
- attribute unsigned long height;
- readonly attribute unsigned long naturalWidth;
- readonly attribute unsigned long naturalHeight;
- readonly attribute boolean complete;
- readonly attribute DOMString currentSrc;
-
- // also has obsolete members
-};
-
-interface HTMLIFrameElement : HTMLElement {
- attribute DOMString src;
- attribute DOMString srcdoc;
- attribute DOMString name;
- [PutForwards=value] readonly attribute DOMSettableTokenList sandbox;
- attribute boolean seamless;
- attribute boolean allowFullscreen;
- attribute DOMString width;
- attribute DOMString height;
- readonly attribute Document? contentDocument;
- readonly attribute WindowProxy? contentWindow;
- Document? getSVGDocument();
-
- // also has obsolete members
-};
-
-interface HTMLEmbedElement : HTMLElement {
- attribute DOMString src;
- attribute DOMString type;
- attribute DOMString width;
- attribute DOMString height;
- Document? getSVGDocument();
- legacycaller any (any... arguments);
-
- // also has obsolete members
-};
-
-interface HTMLObjectElement : HTMLElement {
- attribute DOMString data;
- attribute DOMString type;
- attribute boolean typeMustMatch;
- attribute DOMString name;
- attribute DOMString useMap;
- readonly attribute HTMLFormElement? form;
- attribute DOMString width;
- attribute DOMString height;
- readonly attribute Document? contentDocument;
- readonly attribute WindowProxy? contentWindow;
- Document? getSVGDocument();
-
- readonly attribute boolean willValidate;
- readonly attribute ValidityState validity;
- readonly attribute DOMString validationMessage;
- boolean checkValidity();
- boolean reportValidity();
- void setCustomValidity(DOMString error);
-
- legacycaller any (any... arguments);
-
- // also has obsolete members
-};
-
-interface HTMLParamElement : HTMLElement {
- attribute DOMString name;
- attribute DOMString value;
-
- // also has obsolete members
-};
-
-interface HTMLVideoElement : HTMLMediaElement {
- attribute unsigned long width;
- attribute unsigned long height;
- readonly attribute unsigned long videoWidth;
- readonly attribute unsigned long videoHeight;
- attribute DOMString poster;
-};
-
-[NamedConstructor=Audio(optional DOMString src)]
-interface HTMLAudioElement : HTMLMediaElement {};
-
-interface HTMLSourceElement : HTMLElement {
- attribute DOMString src;
- attribute DOMString type;
-
- // also has obsolete members
-};
-
-interface HTMLTrackElement : HTMLElement {
- attribute DOMString kind;
- attribute DOMString src;
- attribute DOMString srclang;
- attribute DOMString label;
- attribute boolean default;
-
- const unsigned short NONE = 0;
- const unsigned short LOADING = 1;
- const unsigned short LOADED = 2;
- const unsigned short ERROR = 3;
- readonly attribute unsigned short readyState;
-
- readonly attribute TextTrack track;
-};
-
-enum CanPlayTypeResult { "" /* empty string */, "maybe", "probably" };
-typedef (MediaStream or MediaSource or Blob) MediaProvider;
-interface HTMLMediaElement : HTMLElement {
-
- // error state
- readonly attribute MediaError? error;
-
- // network state
- attribute DOMString src;
- attribute MediaProvider? srcObject;
- readonly attribute DOMString currentSrc;
- attribute DOMString? crossOrigin;
- const unsigned short NETWORK_EMPTY = 0;
- const unsigned short NETWORK_IDLE = 1;
- const unsigned short NETWORK_LOADING = 2;
- const unsigned short NETWORK_NO_SOURCE = 3;
- readonly attribute unsigned short networkState;
- attribute DOMString preload;
- readonly attribute TimeRanges buffered;
- void load();
- CanPlayTypeResult canPlayType(DOMString type);
-
- // ready state
- const unsigned short HAVE_NOTHING = 0;
- const unsigned short HAVE_METADATA = 1;
- const unsigned short HAVE_CURRENT_DATA = 2;
- const unsigned short HAVE_FUTURE_DATA = 3;
- const unsigned short HAVE_ENOUGH_DATA = 4;
- readonly attribute unsigned short readyState;
- readonly attribute boolean seeking;
-
- // playback state
- attribute double currentTime;
- void fastSeek(double time);
- readonly attribute unrestricted double duration;
- Date getStartDate();
- readonly attribute boolean paused;
- attribute double defaultPlaybackRate;
- attribute double playbackRate;
- readonly attribute TimeRanges played;
- readonly attribute TimeRanges seekable;
- readonly attribute boolean ended;
- attribute boolean autoplay;
- attribute boolean loop;
- void play();
- void pause();
-
- // media controller
- attribute DOMString mediaGroup;
- attribute MediaController? controller;
-
- // controls
- attribute boolean controls;
- attribute double volume;
- attribute boolean muted;
- attribute boolean defaultMuted;
-
- // tracks
- [SameObject] readonly attribute AudioTrackList audioTracks;
- [SameObject] readonly attribute VideoTrackList videoTracks;
- [SameObject] readonly attribute TextTrackList textTracks;
- TextTrack addTextTrack(TextTrackKind kind, optional DOMString label = "", optional DOMString language = "");
-};
-
-interface MediaError {
- const unsigned short MEDIA_ERR_ABORTED = 1;
- const unsigned short MEDIA_ERR_NETWORK = 2;
- const unsigned short MEDIA_ERR_DECODE = 3;
- const unsigned short MEDIA_ERR_SRC_NOT_SUPPORTED = 4;
- readonly attribute unsigned short code;
-};
-
-interface AudioTrackList : EventTarget {
- readonly attribute unsigned long length;
- getter AudioTrack (unsigned long index);
- AudioTrack? getTrackById(DOMString id);
-
- attribute EventHandler onchange;
- attribute EventHandler onaddtrack;
- attribute EventHandler onremovetrack;
-};
-
-interface AudioTrack {
- readonly attribute DOMString id;
- readonly attribute DOMString kind;
- readonly attribute DOMString label;
- readonly attribute DOMString language;
- attribute boolean enabled;
-};
-
-interface VideoTrackList : EventTarget {
- readonly attribute unsigned long length;
- getter VideoTrack (unsigned long index);
- VideoTrack? getTrackById(DOMString id);
- readonly attribute long selectedIndex;
-
- attribute EventHandler onchange;
- attribute EventHandler onaddtrack;
- attribute EventHandler onremovetrack;
-};
-
-interface VideoTrack {
- readonly attribute DOMString id;
- readonly attribute DOMString kind;
- readonly attribute DOMString label;
- readonly attribute DOMString language;
- attribute boolean selected;
-};
-
-enum MediaControllerPlaybackState { "waiting", "playing", "ended" };
-[Constructor]
-interface MediaController : EventTarget {
- readonly attribute unsigned short readyState; // uses HTMLMediaElement.readyState's values
-
- readonly attribute TimeRanges buffered;
- readonly attribute TimeRanges seekable;
- readonly attribute unrestricted double duration;
- attribute double currentTime;
-
- readonly attribute boolean paused;
- readonly attribute MediaControllerPlaybackState playbackState;
- readonly attribute TimeRanges played;
- void pause();
- void unpause();
- void play(); // calls play() on all media elements as well
-
- attribute double defaultPlaybackRate;
- attribute double playbackRate;
-
- attribute double volume;
- attribute boolean muted;
-
- attribute EventHandler onemptied;
- attribute EventHandler onloadedmetadata;
- attribute EventHandler onloadeddata;
- attribute EventHandler oncanplay;
- attribute EventHandler oncanplaythrough;
- attribute EventHandler onplaying;
- attribute EventHandler onended;
- attribute EventHandler onwaiting;
-
- attribute EventHandler ondurationchange;
- attribute EventHandler ontimeupdate;
- attribute EventHandler onplay;
- attribute EventHandler onpause;
- attribute EventHandler onratechange;
- attribute EventHandler onvolumechange;
-};
-
-interface TextTrackList : EventTarget {
- readonly attribute unsigned long length;
- getter TextTrack (unsigned long index);
- TextTrack? getTrackById(DOMString id);
-
- attribute EventHandler onchange;
- attribute EventHandler onaddtrack;
- attribute EventHandler onremovetrack;
-};
-
-enum TextTrackMode { "disabled", "hidden", "showing" };
-enum TextTrackKind { "subtitles", "captions", "descriptions", "chapters", "metadata" };
-interface TextTrack : EventTarget {
- readonly attribute TextTrackKind kind;
- readonly attribute DOMString label;
- readonly attribute DOMString language;
-
- readonly attribute DOMString id;
- readonly attribute DOMString inBandMetadataTrackDispatchType;
-
- attribute TextTrackMode mode;
-
- readonly attribute TextTrackCueList? cues;
- readonly attribute TextTrackCueList? activeCues;
-
- void addCue(TextTrackCue cue);
- void removeCue(TextTrackCue cue);
-
- attribute EventHandler oncuechange;
-};
-
-interface TextTrackCueList {
- readonly attribute unsigned long length;
- getter TextTrackCue (unsigned long index);
- TextTrackCue? getCueById(DOMString id);
-};
-
-interface TextTrackCue : EventTarget {
- readonly attribute TextTrack? track;
-
- attribute DOMString id;
- attribute double startTime;
- attribute double endTime;
- attribute boolean pauseOnExit;
-
- attribute EventHandler onenter;
- attribute EventHandler onexit;
-};
-
-interface TimeRanges {
- readonly attribute unsigned long length;
- double start(unsigned long index);
- double end(unsigned long index);
-};
-
-[Constructor(DOMString type, optional TrackEventInit eventInitDict)]
-interface TrackEvent : Event {
- readonly attribute (VideoTrack or AudioTrack or TextTrack)? track;
-};
-
-dictionary TrackEventInit : EventInit {
- (VideoTrack or AudioTrack or TextTrack)? track;
-};
-
-interface HTMLMapElement : HTMLElement {
- attribute DOMString name;
- readonly attribute HTMLCollection areas;
-};
-
-interface HTMLAreaElement : HTMLElement {
- attribute DOMString alt;
- attribute DOMString coords;
- attribute DOMString shape;
- attribute DOMString target;
- attribute DOMString download;
- [PutForwards=value] readonly attribute DOMSettableTokenList ping;
- attribute DOMString rel;
- readonly attribute DOMTokenList relList;
- attribute DOMString hreflang;
- attribute DOMString type;
-
- // also has obsolete members
-};
-HTMLAreaElement implements URLUtils;
-
-interface HTMLTableElement : HTMLElement {
- attribute HTMLTableCaptionElement? caption;
- HTMLElement createCaption();
- void deleteCaption();
- attribute HTMLTableSectionElement? tHead;
- HTMLElement createTHead();
- void deleteTHead();
- attribute HTMLTableSectionElement? tFoot;
- HTMLElement createTFoot();
- void deleteTFoot();
- readonly attribute HTMLCollection tBodies;
- HTMLElement createTBody();
- readonly attribute HTMLCollection rows;
- HTMLElement insertRow(optional long index = -1);
- void deleteRow(long index);
- attribute boolean sortable;
- void stopSorting();
-
- // also has obsolete members
-};
-
-interface HTMLTableCaptionElement : HTMLElement {
- // also has obsolete members
-};
-
-interface HTMLTableColElement : HTMLElement {
- attribute unsigned long span;
-
- // also has obsolete members
-};
-
-interface HTMLTableSectionElement : HTMLElement {
- readonly attribute HTMLCollection rows;
- HTMLElement insertRow(optional long index = -1);
- void deleteRow(long index);
-
- // also has obsolete members
-};
-
-interface HTMLTableRowElement : HTMLElement {
- readonly attribute long rowIndex;
- readonly attribute long sectionRowIndex;
- readonly attribute HTMLCollection cells;
- HTMLElement insertCell(optional long index = -1);
- void deleteCell(long index);
-
- // also has obsolete members
-};
-
-interface HTMLTableDataCellElement : HTMLTableCellElement {
- // also has obsolete members
-};
-
-interface HTMLTableHeaderCellElement : HTMLTableCellElement {
- attribute DOMString scope;
- attribute DOMString abbr;
- attribute DOMString sorted;
- void sort();
-};
-
-interface HTMLTableCellElement : HTMLElement {
- attribute unsigned long colSpan;
- attribute unsigned long rowSpan;
- [PutForwards=value] readonly attribute DOMSettableTokenList headers;
- readonly attribute long cellIndex;
-
- // also has obsolete members
-};
-
-[OverrideBuiltins]
-interface HTMLFormElement : HTMLElement {
- attribute DOMString acceptCharset;
- attribute DOMString action;
- attribute DOMString autocomplete;
- attribute DOMString enctype;
- attribute DOMString encoding;
- attribute DOMString method;
- attribute DOMString name;
- attribute boolean noValidate;
- attribute DOMString target;
-
- readonly attribute HTMLFormControlsCollection elements;
- readonly attribute long length;
- getter Element (unsigned long index);
- getter (RadioNodeList or Element) (DOMString name);
-
- void submit();
- void reset();
- boolean checkValidity();
- boolean reportValidity();
-
- void requestAutocomplete();
-};
-
-interface HTMLLabelElement : HTMLElement {
- readonly attribute HTMLFormElement? form;
- attribute DOMString htmlFor;
- readonly attribute HTMLElement? control;
-};
-
-interface HTMLInputElement : HTMLElement {
- attribute DOMString accept;
- attribute DOMString alt;
- attribute DOMString autocomplete;
- attribute boolean autofocus;
- attribute boolean defaultChecked;
- attribute boolean checked;
- attribute DOMString dirName;
- attribute boolean disabled;
- readonly attribute HTMLFormElement? form;
- readonly attribute FileList? files;
- attribute DOMString formAction;
- attribute DOMString formEnctype;
- attribute DOMString formMethod;
- attribute boolean formNoValidate;
- attribute DOMString formTarget;
- attribute unsigned long height;
- attribute boolean indeterminate;
- attribute DOMString inputMode;
- readonly attribute HTMLElement? list;
- attribute DOMString max;
- attribute long maxLength;
- attribute DOMString min;
- attribute long minLength;
- attribute boolean multiple;
- attribute DOMString name;
- attribute DOMString pattern;
- attribute DOMString placeholder;
- attribute boolean readOnly;
- attribute boolean required;
- attribute unsigned long size;
- attribute DOMString src;
- attribute DOMString step;
- attribute DOMString type;
- attribute DOMString defaultValue;
- [TreatNullAs=EmptyString] attribute DOMString value;
- attribute Date? valueAsDate;
- attribute unrestricted double valueAsNumber;
- attribute double valueLow;
- attribute double valueHigh;
- attribute unsigned long width;
-
- void stepUp(optional long n = 1);
- void stepDown(optional long n = 1);
-
- readonly attribute boolean willValidate;
- readonly attribute ValidityState validity;
- readonly attribute DOMString validationMessage;
- boolean checkValidity();
- boolean reportValidity();
- void setCustomValidity(DOMString error);
-
- readonly attribute NodeList labels;
-
- void select();
- attribute unsigned long selectionStart;
- attribute unsigned long selectionEnd;
- attribute DOMString selectionDirection;
- void setRangeText(DOMString replacement);
- void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve");
- void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction);
-
- // also has obsolete members
-};
-
-interface HTMLButtonElement : HTMLElement {
- attribute boolean autofocus;
- attribute boolean disabled;
- readonly attribute HTMLFormElement? form;
- attribute DOMString formAction;
- attribute DOMString formEnctype;
- attribute DOMString formMethod;
- attribute boolean formNoValidate;
- attribute DOMString formTarget;
- attribute DOMString name;
- attribute DOMString type;
- attribute DOMString value;
- attribute HTMLMenuElement? menu;
-
- readonly attribute boolean willValidate;
- readonly attribute ValidityState validity;
- readonly attribute DOMString validationMessage;
- boolean checkValidity();
- boolean reportValidity();
- void setCustomValidity(DOMString error);
-
- readonly attribute NodeList labels;
-};
-
-interface HTMLSelectElement : HTMLElement {
- attribute DOMString autocomplete;
- attribute boolean autofocus;
- attribute boolean disabled;
- readonly attribute HTMLFormElement? form;
- attribute boolean multiple;
- attribute DOMString name;
- attribute boolean required;
- attribute unsigned long size;
-
- readonly attribute DOMString type;
-
- readonly attribute HTMLOptionsCollection options;
- attribute unsigned long length;
- getter Element? item(unsigned long index);
- HTMLOptionElement? namedItem(DOMString name);
- void add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null);
- void remove(); // ChildNode overload
- void remove(long index);
- setter void (unsigned long index, HTMLOptionElement? option);
-
- readonly attribute HTMLCollection selectedOptions;
- attribute long selectedIndex;
- attribute DOMString value;
-
- readonly attribute boolean willValidate;
- readonly attribute ValidityState validity;
- readonly attribute DOMString validationMessage;
- boolean checkValidity();
- boolean reportValidity();
- void setCustomValidity(DOMString error);
-
- readonly attribute NodeList labels;
-};
-
-interface HTMLDataListElement : HTMLElement {
- readonly attribute HTMLCollection options;
-};
-
-interface HTMLOptGroupElement : HTMLElement {
- attribute boolean disabled;
- attribute DOMString label;
-};
-
-[NamedConstructor=Option(optional DOMString text = "", optional DOMString value, optional boolean defaultSelected = false, optional boolean selected = false)]
-interface HTMLOptionElement : HTMLElement {
- attribute boolean disabled;
- readonly attribute HTMLFormElement? form;
- attribute DOMString label;
- attribute boolean defaultSelected;
- attribute boolean selected;
- attribute DOMString value;
-
- attribute DOMString text;
- readonly attribute long index;
-};
-
-interface HTMLTextAreaElement : HTMLElement {
- attribute DOMString autocomplete;
- attribute boolean autofocus;
- attribute unsigned long cols;
- attribute DOMString dirName;
- attribute boolean disabled;
- readonly attribute HTMLFormElement? form;
- attribute DOMString inputMode;
- attribute long maxLength;
- attribute long minLength;
- attribute DOMString name;
- attribute DOMString placeholder;
- attribute boolean readOnly;
- attribute boolean required;
- attribute unsigned long rows;
- attribute DOMString wrap;
-
- readonly attribute DOMString type;
- attribute DOMString defaultValue;
- [TreatNullAs=EmptyString] attribute DOMString value;
- readonly attribute unsigned long textLength;
-
- readonly attribute boolean willValidate;
- readonly attribute ValidityState validity;
- readonly attribute DOMString validationMessage;
- boolean checkValidity();
- boolean reportValidity();
- void setCustomValidity(DOMString error);
-
- readonly attribute NodeList labels;
-
- void select();
- attribute unsigned long selectionStart;
- attribute unsigned long selectionEnd;
- attribute DOMString selectionDirection;
- void setRangeText(DOMString replacement);
- void setRangeText(DOMString replacement, unsigned long start, unsigned long end, optional SelectionMode selectionMode = "preserve");
- void setSelectionRange(unsigned long start, unsigned long end, optional DOMString direction);
-};
-
-interface HTMLKeygenElement : HTMLElement {
- attribute boolean autofocus;
- attribute DOMString challenge;
- attribute boolean disabled;
- readonly attribute HTMLFormElement? form;
- attribute DOMString keytype;
- attribute DOMString name;
-
- readonly attribute DOMString type;
-
- readonly attribute boolean willValidate;
- readonly attribute ValidityState validity;
- readonly attribute DOMString validationMessage;
- boolean checkValidity();
- boolean reportValidity();
- void setCustomValidity(DOMString error);
-
- readonly attribute NodeList labels;
-};
-
-interface HTMLOutputElement : HTMLElement {
- [PutForwards=value] readonly attribute DOMSettableTokenList htmlFor;
- readonly attribute HTMLFormElement? form;
- attribute DOMString name;
-
- readonly attribute DOMString type;
- attribute DOMString defaultValue;
- attribute DOMString value;
-
- readonly attribute boolean willValidate;
- readonly attribute ValidityState validity;
- readonly attribute DOMString validationMessage;
- boolean checkValidity();
- boolean reportValidity();
- void setCustomValidity(DOMString error);
-
- readonly attribute NodeList labels;
-};
-
-interface HTMLProgressElement : HTMLElement {
- attribute double value;
- attribute double max;
- readonly attribute double position;
- readonly attribute NodeList labels;
-};
-
-interface HTMLMeterElement : HTMLElement {
- attribute double value;
- attribute double min;
- attribute double max;
- attribute double low;
- attribute double high;
- attribute double optimum;
- readonly attribute NodeList labels;
-};
-
-interface HTMLFieldSetElement : HTMLElement {
- attribute boolean disabled;
- readonly attribute HTMLFormElement? form;
- attribute DOMString name;
-
- readonly attribute DOMString type;
-
- readonly attribute HTMLFormControlsCollection elements;
-
- readonly attribute boolean willValidate;
- [SameObject] readonly attribute ValidityState validity;
- readonly attribute DOMString validationMessage;
- boolean checkValidity();
- boolean reportValidity();
- void setCustomValidity(DOMString error);
-};
-
-interface HTMLLegendElement : HTMLElement {
- readonly attribute HTMLFormElement? form;
-
- // also has obsolete members
-};
-
-enum AutocompleteErrorReason { "" /* empty string */, "cancel", "disabled", "invalid" };
-
-[Constructor(DOMString type, optional AutocompleteErrorEventInit eventInitDict)]
-interface AutocompleteErrorEvent : Event {
- readonly attribute AutocompleteErrorReason reason;
-};
-
-dictionary AutocompleteErrorEventInit : EventInit {
- AutocompleteErrorReason reason;
-};
-
-enum SelectionMode {
- "select",
- "start",
- "end",
- "preserve", // default
-};
-
-interface ValidityState {
- readonly attribute boolean valueMissing;
- readonly attribute boolean typeMismatch;
- readonly attribute boolean patternMismatch;
- readonly attribute boolean tooLong;
- readonly attribute boolean tooShort;
- readonly attribute boolean rangeUnderflow;
- readonly attribute boolean rangeOverflow;
- readonly attribute boolean stepMismatch;
- readonly attribute boolean badInput;
- readonly attribute boolean customError;
- readonly attribute boolean valid;
-};
-
-interface HTMLDetailsElement : HTMLElement {
- attribute boolean open;
-};
-
-interface HTMLMenuElement : HTMLElement {
- attribute DOMString type;
- attribute DOMString label;
-
- // also has obsolete members
-};
-
-interface HTMLMenuItemElement : HTMLElement {
- attribute DOMString type;
- attribute DOMString label;
- attribute DOMString icon;
- attribute boolean disabled;
- attribute boolean checked;
- attribute DOMString radiogroup;
- attribute boolean default;
- readonly attribute HTMLElement? command;
-};
-
-[Constructor(DOMString type, optional RelatedEventInit eventInitDict)]
-interface RelatedEvent : Event {
- readonly attribute EventTarget? relatedTarget;
-};
-
-dictionary RelatedEventInit : EventInit {
- EventTarget? relatedTarget;
-};
-
-interface HTMLDialogElement : HTMLElement {
- attribute boolean open;
- attribute DOMString returnValue;
- void show(optional (MouseEvent or Element) anchor);
- void showModal(optional (MouseEvent or Element) anchor);
- void close(optional DOMString returnValue);
-};
-
-interface HTMLScriptElement : HTMLElement {
- attribute DOMString src;
- attribute DOMString type;
- attribute DOMString charset;
- attribute boolean async;
- attribute boolean defer;
- attribute DOMString? crossOrigin;
- attribute DOMString text;
- attribute DOMString nonce;
-
- // also has obsolete members
-};
-
-interface HTMLTemplateElement : HTMLElement {
- readonly attribute DocumentFragment content;
-};
-
-typedef (CanvasRenderingContext2D or WebGLRenderingContext) RenderingContext;
-
-interface HTMLCanvasElement : HTMLElement {
- attribute unsigned long width;
- attribute unsigned long height;
-
- RenderingContext? getContext(DOMString contextId, any... arguments);
- boolean probablySupportsContext(DOMString contextId, any... arguments);
-
- void setContext(RenderingContext context);
- CanvasProxy transferControlToProxy();
-
- DOMString toDataURL(optional DOMString type, any... arguments);
- void toBlob(FileCallback? _callback, optional DOMString type, any... arguments);
-};
-
-[Exposed=(Window,Worker)]
-interface CanvasProxy {
- void setContext(RenderingContext context);
-};
-// CanvasProxy implements Transferable;
-
-typedef (HTMLImageElement or
- HTMLVideoElement or
- HTMLCanvasElement or
- CanvasRenderingContext2D or
- ImageBitmap) CanvasImageSource;
-
-enum CanvasFillRule { "nonzero", "evenodd" };
-
-dictionary CanvasRenderingContext2DSettings {
- boolean alpha = true;
-};
-
-enum ImageSmoothingQuality { "low", "medium", "high" };
-
-[Constructor(),
- Constructor(unsigned long width, unsigned long height),
- Exposed=(Window,Worker)]
-interface CanvasRenderingContext2D {
-
- // back-reference to the canvas
- readonly attribute HTMLCanvasElement canvas;
-
- // canvas dimensions
- attribute unsigned long width;
- attribute unsigned long height;
-
- // for contexts that aren't directly fixed to a specific canvas
- void commit(); // push the image to the output bitmap
-
- // state
- void save(); // push state on state stack
- void restore(); // pop state stack and restore state
-
- // transformations (default transform is the identity matrix)
- attribute DOMMatrix currentTransform;
- void scale(unrestricted double x, unrestricted double y);
- void rotate(unrestricted double angle);
- void translate(unrestricted double x, unrestricted double y);
- void transform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
- void setTransform(unrestricted double a, unrestricted double b, unrestricted double c, unrestricted double d, unrestricted double e, unrestricted double f);
- void resetTransform();
-
- // compositing
- attribute unrestricted double globalAlpha; // (default 1.0)
- attribute DOMString globalCompositeOperation; // (default source-over)
-
- // image smoothing
- attribute boolean imageSmoothingEnabled; // (default true)
- attribute ImageSmoothingQuality imageSmoothingQuality; // (default low)
-
- // colours and styles (see also the CanvasDrawingStyles interface)
- attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black)
- attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black)
- CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
- CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
- CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
-
- // shadows
- attribute unrestricted double shadowOffsetX; // (default 0)
- attribute unrestricted double shadowOffsetY; // (default 0)
- attribute unrestricted double shadowBlur; // (default 0)
- attribute DOMString shadowColor; // (default transparent black)
-
- // rects
- void clearRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
- void fillRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
- void strokeRect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
-
- // path API (see also CanvasPathMethods)
- void beginPath();
- void fill(optional CanvasFillRule fillRule = "nonzero");
- void fill(Path2D path, optional CanvasFillRule fillRule = "nonzero");
- void stroke();
- void stroke(Path2D path);
- void drawFocusIfNeeded(Element element);
- void drawFocusIfNeeded(Path2D path, Element element);
- void scrollPathIntoView();
- void scrollPathIntoView(Path2D path);
- void clip(optional CanvasFillRule fillRule = "nonzero");
- void clip(Path2D path, optional CanvasFillRule fillRule = "nonzero");
- void resetClip();
- boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasFillRule fillRule = "nonzero");
- boolean isPointInPath(Path2D path, unrestricted double x, unrestricted double y, optional CanvasFillRule fillRule = "nonzero");
- boolean isPointInStroke(unrestricted double x, unrestricted double y);
- boolean isPointInStroke(Path2D path, unrestricted double x, unrestricted double y);
-
- // text (see also the CanvasDrawingStyles interface)
- void fillText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
- void strokeText(DOMString text, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
- TextMetrics measureText(DOMString text);
-
- // drawing images
- void drawImage(CanvasImageSource image, unrestricted double dx, unrestricted double dy);
- void drawImage(CanvasImageSource image, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh);
- void drawImage(CanvasImageSource image, unrestricted double sx, unrestricted double sy, unrestricted double sw, unrestricted double sh, unrestricted double dx, unrestricted double dy, unrestricted double dw, unrestricted double dh);
-
- // hit regions
- void addHitRegion(optional HitRegionOptions options);
- void removeHitRegion(DOMString id);
- void clearHitRegions();
-
- // pixel manipulation
- ImageData createImageData(double sw, double sh);
- ImageData createImageData(ImageData imagedata);
- ImageData getImageData(double sx, double sy, double sw, double sh);
- void putImageData(ImageData imagedata, double dx, double dy);
- void putImageData(ImageData imagedata, double dx, double dy, double dirtyX, double dirtyY, double dirtyWidth, double dirtyHeight);
-};
-CanvasRenderingContext2D implements CanvasDrawingStyles;
-CanvasRenderingContext2D implements CanvasPathMethods;
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface CanvasDrawingStyles {
- // line caps/joins
- attribute unrestricted double lineWidth; // (default 1)
- attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
- attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
- attribute unrestricted double miterLimit; // (default 10)
-
- // dashed lines
- void setLineDash(sequence<unrestricted double> segments); // default empty
- sequence<unrestricted double> getLineDash();
- attribute unrestricted double lineDashOffset;
-
- // text
- attribute DOMString font; // (default 10px sans-serif)
- attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start")
- attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic")
- attribute DOMString direction; // "ltr", "rtl", "inherit" (default: "inherit")
-};
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface CanvasPathMethods {
- // shared path API methods
- void closePath();
- void moveTo(unrestricted double x, unrestricted double y);
- void lineTo(unrestricted double x, unrestricted double y);
- void quadraticCurveTo(unrestricted double cpx, unrestricted double cpy, unrestricted double x, unrestricted double y);
- void bezierCurveTo(unrestricted double cp1x, unrestricted double cp1y, unrestricted double cp2x, unrestricted double cp2y, unrestricted double x, unrestricted double y);
- void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radius);
- void arcTo(unrestricted double x1, unrestricted double y1, unrestricted double x2, unrestricted double y2, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation);
- void rect(unrestricted double x, unrestricted double y, unrestricted double w, unrestricted double h);
- void arc(unrestricted double x, unrestricted double y, unrestricted double radius, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false);
- void ellipse(unrestricted double x, unrestricted double y, unrestricted double radiusX, unrestricted double radiusY, unrestricted double rotation, unrestricted double startAngle, unrestricted double endAngle, optional boolean anticlockwise = false);
-};
-
-[Exposed=(Window,Worker)]
-interface CanvasGradient {
- // opaque object
- void addColorStop(double offset, DOMString color);
-};
-
-[Exposed=(Window,Worker)]
-interface CanvasPattern {
- // opaque object
- void setTransform(DOMMatrix transform);
-};
-
-[Exposed=(Window,Worker)]
-interface TextMetrics {
- // x-direction
- readonly attribute double width; // advance width
- readonly attribute double actualBoundingBoxLeft;
- readonly attribute double actualBoundingBoxRight;
-
- // y-direction
- readonly attribute double fontBoundingBoxAscent;
- readonly attribute double fontBoundingBoxDescent;
- readonly attribute double actualBoundingBoxAscent;
- readonly attribute double actualBoundingBoxDescent;
- readonly attribute double emHeightAscent;
- readonly attribute double emHeightDescent;
- readonly attribute double hangingBaseline;
- readonly attribute double alphabeticBaseline;
- readonly attribute double ideographicBaseline;
-};
-
-dictionary HitRegionOptions {
- Path2D? path = null;
- CanvasFillRule fillRule = "nonzero";
- DOMString id = "";
- DOMString? parentID = null;
- DOMString cursor = "inherit";
- // for control-backed regions:
- Element? control = null;
- // for unbacked regions:
- DOMString? label = null;
- DOMString? role = null;
-};
-
-[Constructor(unsigned long sw, unsigned long sh),
- Constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh),
- Exposed=(Window,Worker)]
-interface ImageData {
- readonly attribute unsigned long width;
- readonly attribute unsigned long height;
- readonly attribute Uint8ClampedArray data;
-};
-
-[Constructor(optional Element scope), Exposed=(Window,Worker)]
-interface DrawingStyle { };
-DrawingStyle implements CanvasDrawingStyles;
-
-[Constructor,
- Constructor(Path2D path),
- Constructor(sequence<Path2D> paths, optional CanvasFillRule fillRule = "nonzero"),
- Constructor(DOMString d), Exposed=(Window,Worker)]
-interface Path2D {
- void addPath(Path2D path, optional DOMMatrix? transformation = null);
- void addPathByStrokingPath(Path2D path, CanvasDrawingStyles styles, optional DOMMatrix? transformation = null);
- void addText(DOMString text, CanvasDrawingStyles styles, DOMMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
- void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, DOMMatrix? transformation, unrestricted double x, unrestricted double y, optional unrestricted double maxWidth);
- void addText(DOMString text, CanvasDrawingStyles styles, DOMMatrix? transformation, Path2D path, optional unrestricted double maxWidth);
- void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles, DOMMatrix? transformation, Path2D path, optional unrestricted double maxWidth);
-};
-Path2D implements CanvasPathMethods;
-
-partial interface MouseEvent {
- readonly attribute DOMString? region;
-};
-
-partial dictionary MouseEventInit {
- DOMString? region;
-};
-
-partial interface Touch {
- readonly attribute DOMString? region;
-};
-
-[NoInterfaceObject]
-interface ElementContentEditable {
- attribute DOMString contentEditable;
- readonly attribute boolean isContentEditable;
-};
-
-interface DataTransfer {
- attribute DOMString dropEffect;
- attribute DOMString effectAllowed;
-
- [SameObject] readonly attribute DataTransferItemList items;
-
- void setDragImage(Element image, long x, long y);
-
- /* old interface */
- [SameObject] readonly attribute DOMString[] types;
- DOMString getData(DOMString format);
- void setData(DOMString format, DOMString data);
- void clearData(optional DOMString format);
- [SameObject] readonly attribute FileList files;
-};
-
-interface DataTransferItemList {
- readonly attribute unsigned long length;
- getter DataTransferItem (unsigned long index);
- DataTransferItem? add(DOMString data, DOMString type);
- DataTransferItem? add(File data);
- void remove(unsigned long index);
- void clear();
-};
-
-interface DataTransferItem {
- readonly attribute DOMString kind;
- readonly attribute DOMString type;
- void getAsString(FunctionStringCallback? _callback);
- File? getAsFile();
-};
-
-callback FunctionStringCallback = void (DOMString data);
-
-[Constructor(DOMString type, optional DragEventInit eventInitDict)]
-interface DragEvent : MouseEvent {
- readonly attribute DataTransfer? dataTransfer;
-};
-
-dictionary DragEventInit : MouseEventInit {
- DataTransfer? dataTransfer = null;
-};
-
-[PrimaryGlobal]
-/*sealed*/ interface Window : EventTarget {
- // the current browsing context
- [Unforgeable] readonly attribute WindowProxy window;
- [Replaceable] readonly attribute WindowProxy self;
- [Unforgeable] readonly attribute Document document;
- attribute DOMString name;
- [PutForwards=href, Unforgeable] readonly attribute Location location;
- readonly attribute History history;
- [Replaceable] readonly attribute BarProp locationbar;
- [Replaceable] readonly attribute BarProp menubar;
- [Replaceable] readonly attribute BarProp personalbar;
- [Replaceable] readonly attribute BarProp scrollbars;
- [Replaceable] readonly attribute BarProp statusbar;
- [Replaceable] readonly attribute BarProp toolbar;
- attribute DOMString status;
- void close();
- readonly attribute boolean closed;
- void stop();
- void focus();
- void blur();
-
- // other browsing contexts
- [Replaceable] readonly attribute WindowProxy frames;
- [Replaceable] readonly attribute unsigned long length;
- [Unforgeable] readonly attribute WindowProxy top;
- attribute any opener;
- [Replaceable] readonly attribute WindowProxy parent;
- readonly attribute Element? frameElement;
- WindowProxy open(optional DOMString url = "about:blank", optional DOMString target = "_blank", [TreatNullAs=EmptyString] optional DOMString features = "", optional boolean replace = false);
- getter WindowProxy (unsigned long index);
- getter object (DOMString name);
-
- // the user agent
- readonly attribute Navigator navigator;
- [Replaceable, SameObject] readonly attribute External external;
- readonly attribute ApplicationCache applicationCache;
-
- // user prompts
- void alert();
- void alert(DOMString message);
- boolean confirm(optional DOMString message = "");
- DOMString? prompt(optional DOMString message = "", optional DOMString default = "");
- void print();
- any showModalDialog(DOMString url, optional any argument); // deprecated
-
- unsigned long requestAnimationFrame(FrameRequestCallback callback);
- void cancelAnimationFrame(unsigned long handle);
-
- void postMessage(any message, DOMString targetOrigin, optional sequence<Transferable> transfer);
-
- // also has obsolete members
-};
-Window implements GlobalEventHandlers;
-Window implements WindowEventHandlers;
-
-callback FrameRequestCallback = void (DOMHighResTimeStamp time);
-
-interface BarProp {
- readonly attribute boolean visible;
-};
-
-interface History {
- readonly attribute unsigned long length;
- readonly attribute any state;
- void go(optional long delta = 0);
- void back();
- void forward();
- void pushState(any data, DOMString title, optional DOMString? url = null);
- void replaceState(any data, DOMString title, optional DOMString? url = null);
-};
-
-[Unforgeable] interface Location {
- void assign(DOMString url);
- void replace(DOMString url);
- void reload();
-
- [SameObject] readonly attribute DOMString[] ancestorOrigins;
-};
-Location implements URLUtils;
-
-[Constructor(DOMString type, optional PopStateEventInit eventInitDict), Exposed=(Window,Worker)]
-interface PopStateEvent : Event {
- readonly attribute any state;
-};
-
-dictionary PopStateEventInit : EventInit {
- any state;
-};
-
-[Constructor(DOMString type, optional HashChangeEventInit eventInitDict), Exposed=(Window,Worker)]
-interface HashChangeEvent : Event {
- readonly attribute DOMString oldURL;
- readonly attribute DOMString newURL;
-};
-
-dictionary HashChangeEventInit : EventInit {
- DOMString oldURL;
- DOMString newURL;
-};
-
-[Constructor(DOMString type, optional PageTransitionEventInit eventInitDict), Exposed=(Window,Worker)]
-interface PageTransitionEvent : Event {
- readonly attribute boolean persisted;
-};
-
-dictionary PageTransitionEventInit : EventInit {
- boolean persisted;
-};
-
-interface BeforeUnloadEvent : Event {
- attribute DOMString returnValue;
-};
-
-[Exposed=(Window,SharedWorker)]
-interface ApplicationCache : EventTarget {
-
- // update status
- const unsigned short UNCACHED = 0;
- const unsigned short IDLE = 1;
- const unsigned short CHECKING = 2;
- const unsigned short DOWNLOADING = 3;
- const unsigned short UPDATEREADY = 4;
- const unsigned short OBSOLETE = 5;
- readonly attribute unsigned short status;
-
- // updates
- void update();
- void abort();
- void swapCache();
-
- // events
- attribute EventHandler onchecking;
- attribute EventHandler onerror;
- attribute EventHandler onnoupdate;
- attribute EventHandler ondownloading;
- attribute EventHandler onprogress;
- attribute EventHandler onupdateready;
- attribute EventHandler oncached;
- attribute EventHandler onobsolete;
-};
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface NavigatorOnLine {
- readonly attribute boolean onLine;
-};
-
-[Constructor(DOMString type, optional ErrorEventInit eventInitDict), Exposed=(Window,Worker)]
-interface ErrorEvent : Event {
- readonly attribute DOMString message;
- readonly attribute DOMString filename;
- readonly attribute unsigned long lineno;
- readonly attribute unsigned long colno;
- readonly attribute any error;
-};
-
-dictionary ErrorEventInit : EventInit {
- DOMString message;
- DOMString filename;
- unsigned long lineno;
- unsigned long colno;
- any error;
-};
-
-[TreatNonObjectAsNull]
-callback EventHandlerNonNull = any (Event event);
-typedef EventHandlerNonNull? EventHandler;
-
-[TreatNonObjectAsNull]
-callback OnErrorEventHandlerNonNull = any ((Event or DOMString) event, optional DOMString source, optional unsigned long lineno, optional unsigned long column, optional any error);
-typedef OnErrorEventHandlerNonNull? OnErrorEventHandler;
-
-[TreatNonObjectAsNull]
-callback OnBeforeUnloadEventHandlerNonNull = DOMString? (Event event);
-typedef OnBeforeUnloadEventHandlerNonNull? OnBeforeUnloadEventHandler;
-
-[NoInterfaceObject]
-interface GlobalEventHandlers {
- attribute EventHandler onabort;
- attribute EventHandler onautocomplete;
- attribute EventHandler onautocompleteerror;
- attribute EventHandler onblur;
- attribute EventHandler oncancel;
- attribute EventHandler oncanplay;
- attribute EventHandler oncanplaythrough;
- attribute EventHandler onchange;
- attribute EventHandler onclick;
- attribute EventHandler onclose;
- attribute EventHandler oncontextmenu;
- attribute EventHandler oncuechange;
- attribute EventHandler ondblclick;
- attribute EventHandler ondrag;
- attribute EventHandler ondragend;
- attribute EventHandler ondragenter;
- attribute EventHandler ondragexit;
- attribute EventHandler ondragleave;
- attribute EventHandler ondragover;
- attribute EventHandler ondragstart;
- attribute EventHandler ondrop;
- attribute EventHandler ondurationchange;
- attribute EventHandler onemptied;
- attribute EventHandler onended;
- attribute OnErrorEventHandler onerror;
- attribute EventHandler onfocus;
- attribute EventHandler oninput;
- attribute EventHandler oninvalid;
- attribute EventHandler onkeydown;
- attribute EventHandler onkeypress;
- attribute EventHandler onkeyup;
- attribute EventHandler onload;
- attribute EventHandler onloadeddata;
- attribute EventHandler onloadedmetadata;
- attribute EventHandler onloadstart;
- attribute EventHandler onmousedown;
- [LenientThis] attribute EventHandler onmouseenter;
- [LenientThis] attribute EventHandler onmouseleave;
- attribute EventHandler onmousemove;
- attribute EventHandler onmouseout;
- attribute EventHandler onmouseover;
- attribute EventHandler onmouseup;
- attribute EventHandler onwheel;
- attribute EventHandler onpause;
- attribute EventHandler onplay;
- attribute EventHandler onplaying;
- attribute EventHandler onprogress;
- attribute EventHandler onratechange;
- attribute EventHandler onreset;
- attribute EventHandler onresize;
- attribute EventHandler onscroll;
- attribute EventHandler onseeked;
- attribute EventHandler onseeking;
- attribute EventHandler onselect;
- attribute EventHandler onshow;
- attribute EventHandler onsort;
- attribute EventHandler onstalled;
- attribute EventHandler onsubmit;
- attribute EventHandler onsuspend;
- attribute EventHandler ontimeupdate;
- attribute EventHandler ontoggle;
- attribute EventHandler onvolumechange;
- attribute EventHandler onwaiting;
-};
-
-[NoInterfaceObject]
-interface WindowEventHandlers {
- attribute EventHandler onafterprint;
- attribute EventHandler onbeforeprint;
- attribute OnBeforeUnloadEventHandler onbeforeunload;
- attribute EventHandler onhashchange;
- attribute EventHandler onlanguagechange;
- attribute EventHandler onmessage;
- attribute EventHandler onoffline;
- attribute EventHandler ononline;
- attribute EventHandler onpagehide;
- attribute EventHandler onpageshow;
- attribute EventHandler onpopstate;
- attribute EventHandler onstorage;
- attribute EventHandler onunload;
-};
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface WindowBase64 {
- DOMString btoa(DOMString btoa);
- DOMString atob(DOMString atob);
-};
-Window implements WindowBase64;
-WorkerGlobalScope implements WindowBase64;
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface WindowTimers {
- long setTimeout(Function handler, optional long timeout = 0, any... arguments);
- long setTimeout(DOMString handler, optional long timeout = 0, any... arguments);
- void clearTimeout(optional long handle = 0);
- long setInterval(Function handler, optional long timeout = 0, any... arguments);
- long setInterval(DOMString handler, optional long timeout = 0, any... arguments);
- void clearInterval(optional long handle = 0);
-};
-Window implements WindowTimers;
-WorkerGlobalScope implements WindowTimers;
-
-[NoInterfaceObject]
-interface WindowModal {
- readonly attribute any dialogArguments;
- attribute any returnValue;
-};
-
-interface Navigator {
- // objects implementing this interface also implement the interfaces given below
-};
-Navigator implements NavigatorID;
-Navigator implements NavigatorLanguage;
-Navigator implements NavigatorOnLine;
-Navigator implements NavigatorContentUtils;
-Navigator implements NavigatorStorageUtils;
-Navigator implements NavigatorPlugins;
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface NavigatorID {
- [Exposed=Window] readonly attribute DOMString appCodeName; // constant "Mozilla"
- readonly attribute DOMString appName; // constant "Netscape"
- readonly attribute DOMString appVersion;
- readonly attribute DOMString platform;
- [Exposed=Window] readonly attribute DOMString product; // constant "Gecko"
- [Exposed=Window] readonly attribute DOMString productSub;
- readonly attribute DOMString userAgent;
- [Exposed=Window] readonly attribute DOMString vendor;
- [Exposed=Window] readonly attribute DOMString vendorSub; // constant ""
-
- // also has obsolete members
-};
-
-partial interface NavigatorID {
- [Exposed=Window] boolean taintEnabled(); // constant false
-};
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface NavigatorLanguage {
- readonly attribute DOMString? language;
- readonly attribute DOMString[] languages;
-};
-
-[NoInterfaceObject]
-interface NavigatorContentUtils {
- // content handler registration
- void registerProtocolHandler(DOMString scheme, DOMString url, DOMString title);
- void registerContentHandler(DOMString mimeType, DOMString url, DOMString title);
- DOMString isProtocolHandlerRegistered(DOMString scheme, DOMString url);
- DOMString isContentHandlerRegistered(DOMString mimeType, DOMString url);
- void unregisterProtocolHandler(DOMString scheme, DOMString url);
- void unregisterContentHandler(DOMString mimeType, DOMString url);
-};
-
-[NoInterfaceObject]
-interface NavigatorStorageUtils {
- readonly attribute boolean cookieEnabled;
- void yieldForStorageUpdates();
-};
-
-[NoInterfaceObject]
-interface NavigatorPlugins {
- [SameObject] readonly attribute PluginArray plugins;
- [SameObject] readonly attribute MimeTypeArray mimeTypes;
- readonly attribute boolean javaEnabled;
-};
-
-interface PluginArray {
- void refresh(optional boolean reload = false);
- readonly attribute unsigned long length;
- getter Plugin? item(unsigned long index);
- getter Plugin? namedItem(DOMString name);
-};
-
-interface MimeTypeArray {
- readonly attribute unsigned long length;
- getter MimeType? item(unsigned long index);
- getter MimeType? namedItem(DOMString name);
-};
-
-interface Plugin {
- readonly attribute DOMString name;
- readonly attribute DOMString description;
- readonly attribute DOMString filename;
- readonly attribute unsigned long length;
- getter MimeType? item(unsigned long index);
- getter MimeType? namedItem(DOMString name);
-};
-
-interface MimeType {
- readonly attribute DOMString type;
- readonly attribute DOMString description;
- readonly attribute DOMString suffixes; // comma-separated
- readonly attribute Plugin enabledPlugin;
-};
-
-interface External {
- void AddSearchProvider(DOMString engineURL);
- unsigned long IsSearchProviderInstalled(DOMString engineURL);
-};
-
-[Exposed=(Window,Worker)]
-interface ImageBitmap {
- readonly attribute unsigned long width;
- readonly attribute unsigned long height;
-};
-
-typedef (HTMLImageElement or
- HTMLVideoElement or
- HTMLCanvasElement or
- Blob or
- ImageData or
- CanvasRenderingContext2D or
- ImageBitmap) ImageBitmapSource;
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface ImageBitmapFactories {
- Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image);
- Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, long sx, long sy, long sw, long sh);
-};
-Window implements ImageBitmapFactories;
-WorkerGlobalScope implements ImageBitmapFactories;
-
-[Constructor(DOMString type, optional MessageEventInit eventInitDict), Exposed=(Window,Worker)]
-interface MessageEvent : Event {
- readonly attribute any data;
- readonly attribute DOMString origin;
- readonly attribute DOMString lastEventId;
- readonly attribute (WindowProxy or MessagePort)? source;
- readonly attribute MessagePort[]? ports;
-
- void initMessageEvent(DOMString type, boolean bubbles, boolean cancelable, any data, DOMString origin, DOMString lastEventId, (WindowProxy or MessagePort)? source, sequence<MessagePort>? ports);
-};
-
-dictionary MessageEventInit : EventInit {
- any data;
- DOMString origin;
- DOMString lastEventId;
- (WindowProxy or MessagePort)? source;
- sequence<MessagePort>? ports;
-};
-
-[Constructor(DOMString url, optional EventSourceInit eventSourceInitDict), Exposed=(Window,Worker)]
-interface EventSource : EventTarget {
- readonly attribute DOMString url;
- readonly attribute boolean withCredentials;
-
- // ready state
- const unsigned short CONNECTING = 0;
- const unsigned short OPEN = 1;
- const unsigned short CLOSED = 2;
- readonly attribute unsigned short readyState;
-
- // networking
- attribute EventHandler onopen;
- attribute EventHandler onmessage;
- attribute EventHandler onerror;
- void close();
-};
-
-dictionary EventSourceInit {
- boolean withCredentials = false;
-};
-
-enum BinaryType { "blob", "arraybuffer" };
-[Constructor(DOMString url, optional (DOMString or sequence<DOMString>) protocols), Exposed=(Window,Worker)]
-interface WebSocket : EventTarget {
- readonly attribute DOMString url;
-
- // ready state
- const unsigned short CONNECTING = 0;
- const unsigned short OPEN = 1;
- const unsigned short CLOSING = 2;
- const unsigned short CLOSED = 3;
- readonly attribute unsigned short readyState;
- readonly attribute unsigned long bufferedAmount;
-
- // networking
- attribute EventHandler onopen;
- attribute EventHandler onerror;
- attribute EventHandler onclose;
- readonly attribute DOMString extensions;
- readonly attribute DOMString protocol;
- void close([Clamp] optional unsigned short code, optional USVString reason);
-
- // messaging
- attribute EventHandler onmessage;
- attribute BinaryType binaryType;
- void send(USVString data);
- void send(Blob data);
- void send(ArrayBuffer data);
- void send(ArrayBufferView data);
-};
-
-[Constructor(DOMString type, optional CloseEventInit eventInitDict), Exposed=(Window,Worker)]
-interface CloseEvent : Event {
- readonly attribute boolean wasClean;
- readonly attribute unsigned short code;
- readonly attribute DOMString reason;
-};
-
-dictionary CloseEventInit : EventInit {
- boolean wasClean;
- unsigned short code;
- DOMString reason;
-};
-
-[Constructor, Exposed=(Window,Worker)]
-interface MessageChannel {
- readonly attribute MessagePort port1;
- readonly attribute MessagePort port2;
-};
-
-[Exposed=(Window,Worker)]
-interface MessagePort : EventTarget {
- void postMessage(any message, optional sequence<Transferable> transfer);
- void start();
- void close();
-
- // event handlers
- attribute EventHandler onmessage;
-};
-// MessagePort implements Transferable;
-
-[Constructor(DOMString name), Exposed=(Window,Worker)]
-interface BroadcastChannel : EventTarget {
- readonly attribute DOMString name;
- void postMessage(any message);
- void close();
- attribute EventHandler onmessage;
-};
-
-[Exposed=Worker]
-interface WorkerGlobalScope : EventTarget {
- readonly attribute WorkerGlobalScope self;
- readonly attribute WorkerLocation location;
- readonly attribute WorkerNavigator navigator;
- void importScripts(DOMString... urls);
-
- void close();
- attribute OnErrorEventHandler onerror;
- attribute EventHandler onlanguagechange;
- attribute EventHandler onoffline;
- attribute EventHandler ononline;
-};
-
-[Global=(Worker,DedicatedWorker),Exposed=DedicatedWorker]
-/*sealed*/ interface DedicatedWorkerGlobalScope : WorkerGlobalScope {
- void postMessage(any message, optional sequence<Transferable> transfer);
- attribute EventHandler onmessage;
-};
-
-[Global=(Worker,SharedWorker),Exposed=SharedWorker]
-/*sealed*/ interface SharedWorkerGlobalScope : WorkerGlobalScope {
- readonly attribute DOMString name;
- readonly attribute ApplicationCache applicationCache;
- attribute EventHandler onconnect;
-};
-
-[NoInterfaceObject, Exposed=(Window,Worker)]
-interface AbstractWorker {
- attribute EventHandler onerror;
-};
-
-[Constructor(DOMString scriptURL), Exposed=(Window,Worker)]
-interface Worker : EventTarget {
- void terminate();
-
- void postMessage(any message, optional sequence<Transferable> transfer);
- attribute EventHandler onmessage;
-};
-Worker implements AbstractWorker;
-
-[Constructor(DOMString scriptURL, optional DOMString name = ""), Exposed=(Window,Worker)]
-interface SharedWorker : EventTarget {
- readonly attribute MessagePort port;
-};
-SharedWorker implements AbstractWorker;
-
-[Exposed=Worker]
-interface WorkerNavigator {};
-WorkerNavigator implements NavigatorID;
-WorkerNavigator implements NavigatorLanguage;
-WorkerNavigator implements NavigatorOnLine;
-
-[Exposed=Worker]
-interface WorkerLocation {
- stringifier readonly attribute USVString href;
- readonly attribute USVString origin;
- readonly attribute USVString protocol;
- readonly attribute USVString host;
- readonly attribute USVString hostname;
- readonly attribute USVString port;
- readonly attribute USVString pathname;
- readonly attribute USVString search;
- readonly attribute USVString hash;
-};
-
-interface Storage {
- readonly attribute unsigned long length;
- DOMString? key(unsigned long index);
- getter DOMString? getItem(DOMString key);
- setter void setItem(DOMString key, DOMString value);
- deleter void removeItem(DOMString key);
- void clear();
-};
-
-[NoInterfaceObject]
-interface WindowSessionStorage {
- readonly attribute Storage sessionStorage;
-};
-Window implements WindowSessionStorage;
-
-[NoInterfaceObject]
-interface WindowLocalStorage {
- readonly attribute Storage localStorage;
-};
-Window implements WindowLocalStorage;
-
-[Constructor(DOMString type, optional StorageEventInit eventInitDict)]
-interface StorageEvent : Event {
- readonly attribute DOMString? key;
- readonly attribute DOMString? oldValue;
- readonly attribute DOMString? newValue;
- readonly attribute DOMString url;
- readonly attribute Storage? storageArea;
-};
-
-dictionary StorageEventInit : EventInit {
- DOMString? key;
- DOMString? oldValue;
- DOMString? newValue;
- DOMString url;
- Storage? storageArea;
-};
-
-interface HTMLAppletElement : HTMLElement {
- attribute DOMString align;
- attribute DOMString alt;
- attribute DOMString archive;
- attribute DOMString code;
- attribute DOMString codeBase;
- attribute DOMString height;
- attribute unsigned long hspace;
- attribute DOMString name;
- attribute DOMString _object; // the underscore is not part of the identifier
- attribute unsigned long vspace;
- attribute DOMString width;
-};
-
-interface HTMLMarqueeElement : HTMLElement {
- attribute DOMString behavior;
- attribute DOMString bgColor;
- attribute DOMString direction;
- attribute DOMString height;
- attribute unsigned long hspace;
- attribute long loop;
- attribute unsigned long scrollAmount;
- attribute unsigned long scrollDelay;
- attribute boolean trueSpeed;
- attribute unsigned long vspace;
- attribute DOMString width;
-
- attribute EventHandler onbounce;
- attribute EventHandler onfinish;
- attribute EventHandler onstart;
-
- void start();
- void stop();
-};
-
-interface HTMLFrameSetElement : HTMLElement {
- attribute DOMString cols;
- attribute DOMString rows;
-};
-HTMLFrameSetElement implements WindowEventHandlers;
-
-interface HTMLFrameElement : HTMLElement {
- attribute DOMString name;
- attribute DOMString scrolling;
- attribute DOMString src;
- attribute DOMString frameBorder;
- attribute DOMString longDesc;
- attribute boolean noResize;
- readonly attribute Document? contentDocument;
- readonly attribute WindowProxy? contentWindow;
-
- [TreatNullAs=EmptyString] attribute DOMString marginHeight;
- [TreatNullAs=EmptyString] attribute DOMString marginWidth;
-};
-
-partial interface HTMLAnchorElement {
- attribute DOMString coords;
- attribute DOMString charset;
- attribute DOMString name;
- attribute DOMString rev;
- attribute DOMString shape;
-};
-
-partial interface HTMLAreaElement {
- attribute boolean noHref;
-};
-
-partial interface HTMLBodyElement {
- [TreatNullAs=EmptyString] attribute DOMString text;
- [TreatNullAs=EmptyString] attribute DOMString link;
- [TreatNullAs=EmptyString] attribute DOMString vLink;
- [TreatNullAs=EmptyString] attribute DOMString aLink;
- [TreatNullAs=EmptyString] attribute DOMString bgColor;
- attribute DOMString background;
-};
-
-partial interface HTMLBRElement {
- attribute DOMString clear;
-};
-
-partial interface HTMLTableCaptionElement {
- attribute DOMString align;
-};
-
-partial interface HTMLTableColElement {
- attribute DOMString align;
- attribute DOMString ch;
- attribute DOMString chOff;
- attribute DOMString vAlign;
- attribute DOMString width;
-};
-
-interface HTMLDirectoryElement : HTMLElement {
- attribute boolean compact;
-};
-
-partial interface HTMLDivElement {
- attribute DOMString align;
-};
-
-partial interface HTMLDListElement {
- attribute boolean compact;
-};
-
-partial interface HTMLEmbedElement {
- attribute DOMString align;
- attribute DOMString name;
-};
-
-interface HTMLFontElement : HTMLElement {
- [TreatNullAs=EmptyString] attribute DOMString color;
- attribute DOMString face;
- attribute DOMString size;
-};
-
-partial interface HTMLHeadingElement {
- attribute DOMString align;
-};
-
-partial interface HTMLHRElement {
- attribute DOMString align;
- attribute DOMString color;
- attribute boolean noShade;
- attribute DOMString size;
- attribute DOMString width;
-};
-
-partial interface HTMLHtmlElement {
- attribute DOMString version;
-};
-
-partial interface HTMLIFrameElement {
- attribute DOMString align;
- attribute DOMString scrolling;
- attribute DOMString frameBorder;
- attribute DOMString longDesc;
-
- [TreatNullAs=EmptyString] attribute DOMString marginHeight;
- [TreatNullAs=EmptyString] attribute DOMString marginWidth;
-};
-
-partial interface HTMLImageElement {
- attribute DOMString name;
- attribute DOMString lowsrc;
- attribute DOMString align;
- attribute unsigned long hspace;
- attribute unsigned long vspace;
- attribute DOMString longDesc;
-
- [TreatNullAs=EmptyString] attribute DOMString border;
-};
-
-partial interface HTMLInputElement {
- attribute DOMString align;
- attribute DOMString useMap;
-};
-
-partial interface HTMLLegendElement {
- attribute DOMString align;
-};
-
-partial interface HTMLLIElement {
- attribute DOMString type;
-};
-
-partial interface HTMLLinkElement {
- attribute DOMString charset;
- attribute DOMString rev;
- attribute DOMString target;
-};
-
-partial interface HTMLMenuElement {
- attribute boolean compact;
-};
-
-partial interface HTMLMetaElement {
- attribute DOMString scheme;
-};
-
-partial interface HTMLObjectElement {
- attribute DOMString align;
- attribute DOMString archive;
- attribute DOMString code;
- attribute boolean declare;
- attribute unsigned long hspace;
- attribute DOMString standby;
- attribute unsigned long vspace;
- attribute DOMString codeBase;
- attribute DOMString codeType;
-
- [TreatNullAs=EmptyString] attribute DOMString border;
-};
-
-partial interface HTMLOListElement {
- attribute boolean compact;
-};
-
-partial interface HTMLParagraphElement {
- attribute DOMString align;
-};
-
-partial interface HTMLParamElement {
- attribute DOMString type;
- attribute DOMString valueType;
-};
-
-partial interface HTMLPreElement {
- attribute long width;
-};
-
-partial interface HTMLScriptElement {
- attribute DOMString event;
- attribute DOMString htmlFor;
-};
-
-partial interface HTMLTableElement {
- attribute DOMString align;
- attribute DOMString border;
- attribute DOMString frame;
- attribute DOMString rules;
- attribute DOMString summary;
- attribute DOMString width;
-
- [TreatNullAs=EmptyString] attribute DOMString bgColor;
- [TreatNullAs=EmptyString] attribute DOMString cellPadding;
- [TreatNullAs=EmptyString] attribute DOMString cellSpacing;
-};
-
-partial interface HTMLTableSectionElement {
- attribute DOMString align;
- attribute DOMString ch;
- attribute DOMString chOff;
- attribute DOMString vAlign;
-};
-
-partial interface HTMLTableCellElement {
- attribute DOMString align;
- attribute DOMString axis;
- attribute DOMString height;
- attribute DOMString width;
-
- attribute DOMString ch;
- attribute DOMString chOff;
- attribute boolean noWrap;
- attribute DOMString vAlign;
-
- [TreatNullAs=EmptyString] attribute DOMString bgColor;
-};
-
-partial interface HTMLTableDataCellElement {
- attribute DOMString abbr;
-};
-
-partial interface HTMLTableRowElement {
- attribute DOMString align;
- attribute DOMString ch;
- attribute DOMString chOff;
- attribute DOMString vAlign;
-
- [TreatNullAs=EmptyString] attribute DOMString bgColor;
-};
-
-partial interface HTMLUListElement {
- attribute boolean compact;
- attribute DOMString type;
-};
-
-partial interface Document {
- [TreatNullAs=EmptyString] attribute DOMString fgColor;
- [TreatNullAs=EmptyString] attribute DOMString linkColor;
- [TreatNullAs=EmptyString] attribute DOMString vlinkColor;
- [TreatNullAs=EmptyString] attribute DOMString alinkColor;
- [TreatNullAs=EmptyString] attribute DOMString bgColor;
-
- readonly attribute HTMLCollection anchors;
- readonly attribute HTMLCollection applets;
-
- void clear();
- void captureEvents();
- void releaseEvents();
-
- readonly attribute HTMLAllCollection all;
-};
-
-partial interface Window {
- void captureEvents();
- void releaseEvents();
-};
-
diff --git a/javascript/WebIDL/uievents.idl b/javascript/WebIDL/uievents.idl
deleted file mode 100644
index 3f339f381..000000000
--- a/javascript/WebIDL/uievents.idl
+++ /dev/null
@@ -1,185 +0,0 @@
-// Retrived from
-// Thu Jul 23 21:40:07 BST 2015
-
-
-[Constructor(DOMString type, optional UIEventInit eventInitDict)]
-interface UIEvent : Event {
- readonly attribute Window? view;
- readonly attribute long detail;
-};
-
-dictionary UIEventInit : EventInit {
- Window? view = null;
- long detail = 0;
-};
-
-[Constructor(DOMString typeArg, optional FocusEventInit focusEventInitDict)]
-interface FocusEvent : UIEvent {
- readonly attribute EventTarget? relatedTarget;
-};
-
-dictionary FocusEventInit : UIEventInit {
- EventTarget? relatedTarget = null;
-};
-
-[Constructor(DOMString typeArg, optional MouseEventInit mouseEventInitDict)]
-interface MouseEvent : UIEvent {
- readonly attribute long screenX;
- readonly attribute long screenY;
- readonly attribute long clientX;
- readonly attribute long clientY;
- readonly attribute boolean ctrlKey;
- readonly attribute boolean shiftKey;
- readonly attribute boolean altKey;
- readonly attribute boolean metaKey;
- readonly attribute short button;
- readonly attribute EventTarget? relatedTarget;
- // Introduced in this specification
- readonly attribute unsigned short buttons;
- boolean getModifierState (DOMString keyArg);
-};
-
-dictionary MouseEventInit : EventModifierInit {
- long screenX = 0;
- long screenY = 0;
- long clientX = 0;
- long clientY = 0;
- short button = 0;
- unsigned short buttons = 0;
- EventTarget? relatedTarget = null;
-};
-
-dictionary EventModifierInit : UIEventInit {
- boolean ctrlKey = false;
- boolean shiftKey = false;
- boolean altKey = false;
- boolean metaKey = false;
- boolean modifierAltGraph = false;
- boolean modifierCapsLock = false;
- boolean modifierFn = false;
- boolean modifierFnLock = false;
- boolean modifierHyper = false;
- boolean modifierNumLock = false;
- boolean modifierOS = false;
- boolean modifierScrollLock = false;
- boolean modifierSuper = false;
- boolean modifierSymbol = false;
- boolean modifierSymbolLock = false;
-};
-
-[Constructor(DOMString typeArg, optional WheelEventInit wheelEventInitDict)]
-interface WheelEvent : MouseEvent {
- // DeltaModeCode
- const unsigned long DOM_DELTA_PIXEL = 0x00;
- const unsigned long DOM_DELTA_LINE = 0x01;
- const unsigned long DOM_DELTA_PAGE = 0x02;
- readonly attribute double deltaX;
- readonly attribute double deltaY;
- readonly attribute double deltaZ;
- readonly attribute unsigned long deltaMode;
-};
-
-dictionary WheelEventInit : MouseEventInit {
- double deltaX = 0.0;
- double deltaY = 0.0;
- double deltaZ = 0.0;
- unsigned long deltaMode = 0;
-};
-
-[Constructor(DOMString typeArg, optional KeyboardEventInit keyboardEventInitDict)]
-interface KeyboardEvent : UIEvent {
- // KeyLocationCode
- const unsigned long DOM_KEY_LOCATION_STANDARD = 0x00;
- const unsigned long DOM_KEY_LOCATION_LEFT = 0x01;
- const unsigned long DOM_KEY_LOCATION_RIGHT = 0x02;
- const unsigned long DOM_KEY_LOCATION_NUMPAD = 0x03;
- readonly attribute DOMString key;
- readonly attribute DOMString code;
- readonly attribute unsigned long location;
- readonly attribute boolean ctrlKey;
- readonly attribute boolean shiftKey;
- readonly attribute boolean altKey;
- readonly attribute boolean metaKey;
- readonly attribute boolean repeat;
- readonly attribute boolean isComposing;
- boolean getModifierState (DOMString keyArg);
-};
-
-dictionary KeyboardEventInit : EventModifierInit {
- DOMString key = "";
- DOMString code = "";
- unsigned long location = 0;
- boolean repeat = false;
- boolean isComposing = false;
-};
-
-[Constructor(DOMString typeArg, optional CompositionEventInit compositionEventInitDict)]
-interface CompositionEvent : UIEvent {
- readonly attribute DOMString data;
-};
-
-dictionary CompositionEventInit : UIEventInit {
- DOMString data = "";
-};
-
-partial interface CustomEvent {
- // Originally introduced (and deprecated) in this specification
- void initCustomEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, any detailArg);
-};
-
-partial interface UIEvent {
- // Deprecated in this specification
- void initUIEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg);
-};
-
-partial interface FocusEvent {
- // Originally introduced (and deprecated) in this specification
- void initFocusEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg, EventTarget? relatedTargetArg);
-};
-
-partial interface MouseEvent {
- // Deprecated in this specification
- void initMouseEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, boolean ctrlKeyArg, boolean altKeyArg, boolean shiftKeyArg, boolean metaKeyArg, short buttonArg, EventTarget? relatedTargetArg);
-};
-
-partial interface WheelEvent {
- // Originally introduced (and deprecated) in this specification
- void initWheelEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, short buttonArg, EventTarget? relatedTargetArg, DOMString modifiersListArg, double deltaXArg, double deltaYArg, double deltaZArg, unsigned long deltaMode);
-};
-
-partial interface KeyboardEvent {
- // Originally introduced (and deprecated) in this specification
- void initKeyboardEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, DOMString keyArg, unsigned long locationArg, DOMString modifiersListArg, boolean repeat, DOMString locale);
-};
-
-partial interface CompositionEvent {
- // Originally introduced (and deprecated) in this specification
- void initCompositionEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Window? viewArg, DOMString dataArg, DOMString locale);
-};
-
-partial interface KeyboardEvent {
- // The following support legacy user agents
- readonly attribute unsigned long charCode;
- readonly attribute unsigned long keyCode;
- readonly attribute unsigned long which;
-};
-
-partial dictionary KeyboardEventInit {
- unsigned long charCode = 0;
- unsigned long keyCode = 0;
- unsigned long which = 0;
-};
-
-interface MutationEvent : Event {
- // attrChangeType
- const unsigned short MODIFICATION = 1;
- const unsigned short ADDITION = 2;
- const unsigned short REMOVAL = 3;
- readonly attribute Node? relatedNode;
- readonly attribute DOMString prevValue;
- readonly attribute DOMString newValue;
- readonly attribute DOMString attrName;
- readonly attribute unsigned short attrChange;
- void initMutationEvent (DOMString typeArg, boolean bubblesArg, boolean cancelableArg, Node? relatedNodeArg, DOMString prevValueArg, DOMString newValueArg, DOMString attrNameArg, unsigned short attrChangeArg);
-};
-
diff --git a/javascript/WebIDL/urlutils.idl b/javascript/WebIDL/urlutils.idl
deleted file mode 100644
index e79d4ad42..000000000
--- a/javascript/WebIDL/urlutils.idl
+++ /dev/null
@@ -1,65 +0,0 @@
-// Retrived from https://url.spec.whatwg.org
-// Tue Aug 11 12:11:31 BST 2015
-// Removed duplicate IDL from appendix
-
-[Constructor(USVString url, optional USVString base),
- Exposed=(Window,Worker)]
-interface URL {
- static USVString domainToASCII(USVString domain);
- static USVString domainToUnicode(USVString domain);
-};
-URL implements URLUtils;
-URL implements URLUtilsSearchParams;
-
-[NoInterfaceObject,
- Exposed=(Window,Worker)]
-interface URLUtils {
- stringifier attribute USVString href;
- readonly attribute USVString origin;
-
- attribute USVString protocol;
- attribute USVString username;
- attribute USVString password;
- attribute USVString host;
- attribute USVString hostname;
- attribute USVString port;
- attribute USVString pathname;
- attribute USVString search;
- attribute USVString hash;
-};
-
-[NoInterfaceObject,
- Exposed=(Window, Worker)]
-interface URLUtilsSearchParams {
- attribute URLSearchParams searchParams;
-};
-
-[NoInterfaceObject,
- Exposed=(Window,Worker)]
-interface URLUtilsReadOnly {
- stringifier readonly attribute USVString href;
- readonly attribute USVString origin;
-
- readonly attribute USVString protocol;
- readonly attribute USVString host;
- readonly attribute USVString hostname;
- readonly attribute USVString port;
- readonly attribute USVString pathname;
- readonly attribute USVString search;
- readonly attribute USVString hash;
-};
-
-[Constructor(optional (USVString or URLSearchParams) init = ""),
- Exposed=(Window,Worker)]
-interface URLSearchParams {
- void append(USVString name, USVString value);
- void delete(USVString name);
- USVString? get(USVString name);
- sequence<USVString> getAll(USVString name);
- boolean has(USVString name);
- void set(USVString name, USVString value);
- iterable<USVString, USVString>;
- stringifier;
-};
-
-
diff --git a/javascript/content.c b/javascript/content.c
deleted file mode 100644
index ef5614094..000000000
--- a/javascript/content.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2012 Vincent Sanders <vince@kyllikki.org>
- *
- * 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/>.
- */
-
-/** \file
- * Content for javascript (implementation)
- */
-
-#include <assert.h>
-#include <string.h>
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include "utils/config.h"
-#include "content/content_protected.h"
-#include "content/hlcache.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/utils.h"
-#include "javascript/content.h"
-
-typedef struct javascript_content {
- struct content base;
-} javascript_content;
-
-static nserror javascript_create(const content_handler *handler,
- lwc_string *imime_type, const struct http_parameter *params,
- llcache_handle *llcache, const char *fallback_charset,
- bool quirks, struct content **c)
-{
- javascript_content *script;
- nserror error;
-
- script = calloc(1, sizeof(javascript_content));
- if (script == NULL)
- return NSERROR_NOMEM;
-
- error = content__init(&script->base, handler, imime_type, params,
- llcache, fallback_charset, quirks);
- if (error != NSERROR_OK) {
- free(script);
- return error;
- }
-
- *c = (struct content *) script;
-
- return NSERROR_OK;
-}
-
-static bool javascript_convert(struct content *c)
-{
- content_set_ready(c);
- content_set_done(c);
-
- return true;
-}
-
-static nserror
-javascript_clone(const struct content *old, struct content **newc)
-{
- javascript_content *script;
- nserror error;
-
- script = calloc(1, sizeof(javascript_content));
- if (script == NULL)
- return NSERROR_NOMEM;
-
- error = content__clone(old, &script->base);
- if (error != NSERROR_OK) {
- content_destroy(&script->base);
- return error;
- }
-
- *newc = (struct content *) script;
-
- return NSERROR_OK;
-}
-
-static void javascript_destroy(struct content *c)
-{
-}
-
-static content_type javascript_content_type(void)
-{
- return CONTENT_JS;
-}
-
-
-static const content_handler javascript_content_handler = {
- .create = javascript_create,
- .data_complete = javascript_convert,
- .destroy = javascript_destroy,
- .clone = javascript_clone,
- .type = javascript_content_type,
- .no_share = false,
-};
-
-static const char *javascript_types[] = {
- "application/javascript", /* RFC 4329 */
- "application/ecmascript", /* RFC 4329 */
- "application/x-javascript", /* common usage */
- "text/javascript", /* common usage */
- "text/ecmascript", /* common usage */
-};
-
-CONTENT_FACTORY_REGISTER_TYPES(javascript, javascript_types, javascript_content_handler);
diff --git a/javascript/content.h b/javascript/content.h
deleted file mode 100644
index f8160b4b1..000000000
--- a/javascript/content.h
+++ /dev/null
@@ -1 +0,0 @@
-nserror javascript_init(void);
diff --git a/javascript/duktape/Console.bnd b/javascript/duktape/Console.bnd
deleted file mode 100644
index 734f0035a..000000000
--- a/javascript/duktape/Console.bnd
+++ /dev/null
@@ -1,177 +0,0 @@
-/* Console binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- * Copyright 2015 Daniel Silverstone <dsilvers@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-class Console {
- private unsigned int group;
- prologue %{
-#include <nsutils/time.h>
-
-#define CONSOLE_TIMERS MAGIC(ConsoleTimers)
-
-static void
-write_log_entry(duk_context *ctx, unsigned int group, char logtype)
-{
- /* objs... */
- for (int i = 0; i < duk_get_top(ctx); ++i) {
- (void)duk_safe_to_string(ctx, i);
- }
- /* strs... */
- duk_push_sprintf(ctx, "%c: ", logtype);
- duk_insert(ctx, 0);
- /* pfx strs... */
- for (unsigned int u = 0; u < group; ++u) {
- duk_push_lstring(ctx, " ", 1);
- duk_insert(ctx, 0);
- }
- /* spcs... pfx strs... */
- duk_concat(ctx, duk_get_top(ctx));
- /* str */
- LOG("%s", duk_safe_to_string(ctx, 0));
-}
-
-%};
-};
-
-init Console ()
-%{
- priv->group = 0;
- duk_push_object(ctx);
- duk_put_prop_string(ctx, 0, CONSOLE_TIMERS);
-%}
-
-method Console::group ()
-%{
- priv->group ++;
- return 0;
-%}
-
-method Console::groupCollapsed ()
-%{
- priv->group ++;
- return 0;
-%}
-
-method Console::groupEnd ()
-%{
- if (priv->group)
- priv->group --;
- return 0;
-%}
-
-method Console::info()
-%{
- write_log_entry(ctx, priv->group, 'I');
- return 0;
-%}
-
-method Console::debug()
-%{
- write_log_entry(ctx, priv->group, 'D');
- return 0;
-%}
-
-method Console::error()
-%{
- write_log_entry(ctx, priv->group, 'E');
- return 0;
-%}
-
-method Console::log()
-%{
- write_log_entry(ctx, priv->group, 'L');
- return 0;
-%}
-
-method Console::warn()
-%{
- write_log_entry(ctx, priv->group, 'W');
- return 0;
-%}
-
-method Console::dir()
-%{
- write_log_entry(ctx, priv->group, 'd');
- return 0;
-%}
-
-method Console::time()
-%{
- uint64_t time_ms = 0;
-
- if (nsu_getmonotonic_ms(&time_ms) != NSUERROR_OK)
- return 0;
-
- if (!duk_is_string(ctx, 0)) {
- duk_error(ctx, DUK_ERR_ERROR, "Console.time() takes a string");
- }
-
- duk_set_top(ctx, 1);
-
- duk_push_uint(ctx, (duk_uint_t)time_ms);
-
- duk_push_this(ctx);
- duk_get_prop_string(ctx, -1, CONSOLE_TIMERS);
- duk_insert(ctx, 0);
- duk_pop(ctx);
-
- duk_put_prop(ctx, 0);
-
- return 0;
-%}
-
-method Console::timeEnd()
-%{
- uint64_t time_ms = 0;
- uint64_t old_time_ms = 0;
-
- if (nsu_getmonotonic_ms(&time_ms) != NSUERROR_OK)
- return 0;
-
- if (!duk_is_string(ctx, 0)) {
- duk_error(ctx, DUK_ERR_ERROR, "Console.time() takes a string");
- }
-
- duk_set_top(ctx, 1);
-
- duk_push_this(ctx);
- duk_get_prop_string(ctx, -1, CONSOLE_TIMERS);
- duk_insert(ctx, 0);
- duk_pop(ctx);
-
- duk_dup(ctx, -1);
- duk_get_prop(ctx, 0);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_uint(ctx, (duk_uint_t)time_ms);
- }
- /* timers timername oldval */
- old_time_ms = duk_to_uint32(ctx, -1);
- duk_pop(ctx);
- duk_dup(ctx, -1);
- duk_insert(ctx, 0);
- duk_del_prop(ctx, 0);
- duk_push_string(ctx, "Timer elapsed: ");
- duk_insert(ctx, 0);
- duk_push_sprintf(ctx, "%lu ms", (duk_uint_t)(time_ms - old_time_ms));
- write_log_entry(ctx, priv->group, 'T');
- return 0;
-%}
-
-method Console::trace ()
-%{
- duk_idx_t i = duk_push_error_object(ctx, DUK_ERR_ERROR, "Dummy Error");
- duk_get_prop_string(ctx, i, "stack");
- duk_safe_to_string(ctx, -1);
- duk_insert(ctx, 0);
- duk_set_top(ctx, 1);
- write_log_entry(ctx, priv->group, 'S');
- return 0;
-%}
diff --git a/javascript/duktape/Document.bnd b/javascript/duktape/Document.bnd
deleted file mode 100644
index 8658aec45..000000000
--- a/javascript/duktape/Document.bnd
+++ /dev/null
@@ -1,445 +0,0 @@
-/* document binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-prologue Document()
-%{
-#include "utils/corestrings.h"
-#include "utils/libdom.h"
-#include "utils/utils.h"
-#include "content/hlcache.h"
-#include "render/html_internal.h"
-#include "content/urldb.h"
-
-#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
-%}
-
-
-init Document(struct dom_document *document::node);
-
-method Document::write()
-%{
- struct html_content *htmlc;
- duk_size_t text_len;
- dom_exception err;
- const char *text;
-
- for (int i = 0; i < duk_get_top(ctx); ++i) {
- duk_safe_to_string(ctx, i);
- }
- duk_concat(ctx, duk_get_top(ctx));
- text = duk_safe_to_lstring(ctx, 0, &text_len);
- JS_LOG("Writing %*s", (int)text_len, text);
-
- err = dom_node_get_user_data(priv->parent.node,
- corestring_dom___ns_key_html_content_data,
- &htmlc);
- if ((err != DOM_NO_ERR) || (htmlc == NULL)) {
- LOG("error getting htmlc. parent node:%p htmlc:%p",
- priv->parent.node, htmlc);
- return 0;
- } else if (htmlc->parser == NULL) {
- LOG("error; no parser for htmlc: %p", htmlc);
- return 0;
- }
-
- dom_hubbub_parser_insert_chunk(htmlc->parser,
- (uint8_t *)text, text_len);
-
- return 0;
-%}
-
-method Document::writeln()
-%{
- const char nl[] = "\n";
- struct html_content *htmlc;
- duk_size_t text_len;
- const char *text;
- dom_exception err;
-
- for (int i = 0; i < duk_get_top(ctx); ++i) {
- duk_safe_to_string(ctx, i);
- }
- duk_concat(ctx, duk_get_top(ctx));
- text = duk_safe_to_lstring(ctx, 0, &text_len);
-
- JS_LOG("Writeln %*s", (int)text_len, text);
- err = dom_node_get_user_data(priv->parent.node,
- corestring_dom___ns_key_html_content_data,
- &htmlc);
- if ((err != DOM_NO_ERR) || (htmlc == NULL)) {
- LOG("error getting htmlc. parent node:%p htmlc:%p",
- priv->parent.node, htmlc);
- return 0;
- } else if (htmlc->parser == NULL) {
- LOG("error; no parser for htmlc: %p", htmlc);
- return 0;
- }
-
- dom_hubbub_parser_insert_chunk(htmlc->parser, (uint8_t *)text, text_len);
- dom_hubbub_parser_insert_chunk(htmlc->parser, (uint8_t *)nl, SLEN(nl));
-
- return 0;
-%}
-
-method Document::createTextNode()
-%{
- dom_node *newnode;
- dom_exception err;
- duk_size_t text_len;
- const char *text = duk_safe_to_lstring(ctx, 0, &text_len);
- dom_string *text_str;
-
- err = dom_string_create((const uint8_t*)text, text_len, &text_str);
- if (err != DOM_NO_ERR) return 0; /* coerced to undefined */
-
- err = dom_document_create_text_node(priv->parent.node,
- text_str,
- &newnode);
- if (err != DOM_NO_ERR) {
- dom_string_unref(text_str);
- return 0; /* coerced to undefined */
- }
-
- dom_string_unref(text_str);
-
- dukky_push_node(ctx, newnode);
-
- dom_node_unref(newnode);
-
- return 1;
-%}
-
-method Document::createElement()
-%{
- dom_node *newnode;
- dom_exception err;
- duk_size_t text_len;
- const char *text = duk_safe_to_lstring(ctx, 0, &text_len);
- dom_string *text_str;
-
- err = dom_string_create((const uint8_t*)text, text_len, &text_str);
- if (err != DOM_NO_ERR) return 0; /* coerced to undefined */
-
- err = dom_document_create_element_ns(priv->parent.node,
- corestring_dom_html_namespace,
- text_str,
- &newnode);
- if (err != DOM_NO_ERR) {
- dom_string_unref(text_str);
- return 0; /* coerced to undefined */
- }
-
- dom_string_unref(text_str);
-
- dukky_push_node(ctx, newnode);
-
- dom_node_unref(newnode);
-
- return 1;
-%}
-
-getter Document::head()
-%{
- struct dom_nodelist *nodes;
- struct dom_node *retnode;
- dom_exception err;
- err = dom_document_get_elements_by_tag_name(priv->parent.node,
- corestring_dom_HEAD,
- &nodes);
- if (err != DOM_NO_ERR) return 0; /* coerced to undefined */
-
- err = dom_nodelist_item(nodes, 0, &retnode);
-
- if (err != DOM_NO_ERR) {
- dom_nodelist_unref(nodes);
- return 0; /* coerced to undefined */
- }
-
- dom_nodelist_unref(nodes);
-
- if (retnode == NULL) return 0; /* coerced to undefined */
-
- dukky_push_node(ctx, retnode);
-
- dom_node_unref(retnode);
-
- return 1;
-%}
-
-getter Document::body()
-%{
- struct dom_nodelist *nodes;
- struct dom_node *retnode;
- dom_exception err;
- err = dom_document_get_elements_by_tag_name(priv->parent.node,
- corestring_dom_BODY,
- &nodes);
- if (err != DOM_NO_ERR) {
- return 0; /* coerced to undefined */
- }
-
- err = dom_nodelist_item(nodes, 0, &retnode);
-
- if (err != DOM_NO_ERR) {
- dom_nodelist_unref(nodes);
- return 0; /* coerced to undefined */
- }
-
- dom_nodelist_unref(nodes);
-
- if (retnode != NULL) {
- dukky_push_node(ctx, retnode);
-
- dom_node_unref(retnode);
-
- return 1;
- }
-
- return 0; /* coerced to undefined */
-%}
-
-getter Document::location()
-%{
- /* retrieve the location object from the root object (window) */
- duk_push_global_object(ctx);
- duk_get_prop_string(ctx, -1, "location");
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- return 0;
- }
- return 1;
-%}
-
-
-method Document::getElementById()
-%{
- dom_string *elementId_dom;
- dom_element *element;
- dom_exception exc;
- duk_size_t text_len;
- const char *text = duk_safe_to_lstring(ctx, 0, &text_len);
-
- exc = dom_string_create((uint8_t*)text, text_len, &elementId_dom);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- exc = dom_document_get_element_by_id(((node_private_t *)priv)->node,
- elementId_dom, &element);
- dom_string_unref(elementId_dom);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- if (element != NULL) {
- dukky_push_node(ctx, (dom_node *)element);
- dom_node_unref(element);
- return 1;
- }
-
- return 0;
-%}
-
-getter Document::documentElement()
-%{
- dom_exception exc;
- dom_element *element;
-
- exc = dom_document_get_document_element(((node_private_t *)priv)->node,
- &element);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- if (element == NULL) {
- return 0;
- }
-
- dukky_push_node(ctx, (dom_node *)element);
- dom_node_unref(element);
-
- return 1;
-
-%}
-
-method Document::getElementsByTagName()
-%{
- dom_nodelist *nodes;
- dom_exception err;
- duk_size_t text_len;
- const char *text = duk_safe_to_lstring(ctx, 0, &text_len);
- dom_string *tag;
-
- err = dom_string_create((uint8_t*)text, text_len, &tag);
-
- if (err != DOM_NO_ERR) return 0; /* coerced to undefined */
-
- err = dom_document_get_elements_by_tag_name(((node_private_t *)priv)->node,
- tag, &nodes);
- dom_string_unref(tag);
- if (err != DOM_NO_ERR) return 0; /* coerced to undefined */
-
- if (nodes == NULL) return 0; /* coerced to undefined */
-
- duk_push_pointer(ctx, nodes);
- dukky_create_object(ctx, PROTO_NAME(NODELIST), 1);
- dom_nodelist_unref(nodes);
- return 1;
-%}
-
-getter Document::cookie()
-%{
- char *cookie_str;
- struct html_content *htmlc;
- dom_exception err;
-
- err = dom_node_get_user_data(priv->parent.node,
- corestring_dom___ns_key_html_content_data,
- &htmlc);
- if ((err == DOM_NO_ERR) && (htmlc != NULL)) {
- cookie_str = urldb_get_cookie(llcache_handle_get_url(htmlc->base.llcache), false);
- if (cookie_str != NULL) {
- duk_push_string(ctx, cookie_str);
- free(cookie_str);
- return 1;
- }
- } else {
- LOG("error getting htmlc. parent node:%p htmlc:%p",
- priv->parent.node, htmlc);
- }
- return 0;
-%}
-
-getter Document::onabort();
-setter Document::onabort();
-getter Document::onautocompleteerror();
-setter Document::onautocompleteerror();
-getter Document::onautocomplete();
-setter Document::onautocomplete();
-getter Document::onblur();
-setter Document::onblur();
-getter Document::oncancel();
-setter Document::oncancel();
-getter Document::oncanplaythrough();
-setter Document::oncanplaythrough();
-getter Document::oncanplay();
-setter Document::oncanplay();
-getter Document::onchange();
-setter Document::onchange();
-getter Document::onclick();
-setter Document::onclick();
-getter Document::onclose();
-setter Document::onclose();
-getter Document::oncontextmenu();
-setter Document::oncontextmenu();
-getter Document::oncuechange();
-setter Document::oncuechange();
-getter Document::ondblclick();
-setter Document::ondblclick();
-getter Document::ondragend();
-setter Document::ondragend();
-getter Document::ondragenter();
-setter Document::ondragenter();
-getter Document::ondragexit();
-setter Document::ondragexit();
-getter Document::ondragleave();
-setter Document::ondragleave();
-getter Document::ondragover();
-setter Document::ondragover();
-getter Document::ondragstart();
-setter Document::ondragstart();
-getter Document::ondrag();
-setter Document::ondrag();
-getter Document::ondrop();
-setter Document::ondrop();
-getter Document::ondurationchange();
-setter Document::ondurationchange();
-getter Document::onemptied();
-setter Document::onemptied();
-getter Document::onended();
-setter Document::onended();
-getter Document::onfocus();
-setter Document::onfocus();
-getter Document::oninput();
-setter Document::oninput();
-getter Document::oninvalid();
-setter Document::oninvalid();
-getter Document::onkeydown();
-setter Document::onkeydown();
-getter Document::onkeypress();
-setter Document::onkeypress();
-getter Document::onkeyup();
-setter Document::onkeyup();
-getter Document::onloadeddata();
-setter Document::onloadeddata();
-getter Document::onloadedmetadata();
-setter Document::onloadedmetadata();
-getter Document::onloadstart();
-setter Document::onloadstart();
-getter Document::onload();
-setter Document::onload();
-getter Document::onmousedown();
-setter Document::onmousedown();
-getter Document::onmouseenter();
-setter Document::onmouseenter();
-getter Document::onmouseleave();
-setter Document::onmouseleave();
-getter Document::onmousemove();
-setter Document::onmousemove();
-getter Document::onmouseout();
-setter Document::onmouseout();
-getter Document::onmouseover();
-setter Document::onmouseover();
-getter Document::onmouseup();
-setter Document::onmouseup();
-getter Document::onpause();
-setter Document::onpause();
-getter Document::onplaying();
-setter Document::onplaying();
-getter Document::onplay();
-setter Document::onplay();
-getter Document::onprogress();
-setter Document::onprogress();
-getter Document::onratechange();
-setter Document::onratechange();
-getter Document::onreadystatechange();
-setter Document::onreadystatechange();
-getter Document::onreset();
-setter Document::onreset();
-getter Document::onresize();
-setter Document::onresize();
-getter Document::onscroll();
-setter Document::onscroll();
-getter Document::onseeked();
-setter Document::onseeked();
-getter Document::onseeking();
-setter Document::onseeking();
-getter Document::onselect();
-setter Document::onselect();
-getter Document::onshow();
-setter Document::onshow();
-getter Document::onsort();
-setter Document::onsort();
-getter Document::onstalled();
-setter Document::onstalled();
-getter Document::onsubmit();
-setter Document::onsubmit();
-getter Document::onsuspend();
-setter Document::onsuspend();
-getter Document::ontimeupdate();
-setter Document::ontimeupdate();
-getter Document::ontoggle();
-setter Document::ontoggle();
-getter Document::onvolumechange();
-setter Document::onvolumechange();
-getter Document::onwaiting();
-setter Document::onwaiting();
-getter Document::onwheel();
-setter Document::onwheel();
diff --git a/javascript/duktape/Element.bnd b/javascript/duktape/Element.bnd
deleted file mode 100644
index d34e8c1eb..000000000
--- a/javascript/duktape/Element.bnd
+++ /dev/null
@@ -1,379 +0,0 @@
-/* document binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-class Element {
- prologue %{
-#include <utils/corestrings.h>
-%};
-};
-
-init Element(struct dom_element *element::node);
-
-getter Element::firstElementChild()
-%{
- dom_node *element;
- dom_exception exc;
- dom_node_type node_type;
- dom_node *next_node;
-
- exc = dom_node_get_first_child(((node_private_t*)priv)->node, &element);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- while (element != NULL) {
- exc = dom_node_get_node_type(element, &node_type);
- if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
- /* found it */
- break;
- }
-
- exc = dom_node_get_next_sibling(element, &next_node);
- dom_node_unref(element);
- if (exc == DOM_NO_ERR) {
- element = next_node;
- } else {
- element = NULL;
- }
- }
- if (dukky_push_node(ctx, (dom_node *)element) == false) {
- dom_node_unref(element);
- return 0;
- }
- dom_node_unref(element);
- return 1;
-%}
-
-getter Element::lastElementChild()
-%{
- dom_node *element;
- dom_exception exc;
- dom_node_type node_type;
- dom_node *next_node;
-
- exc = dom_node_get_last_child(((node_private_t*)priv)->node, &element);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- while (element != NULL) {
- exc = dom_node_get_node_type(element, &node_type);
- if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
- /* found it */
- break;
- }
-
- exc = dom_node_get_previous_sibling(element, &next_node);
- dom_node_unref(element);
- if (exc == DOM_NO_ERR) {
- element = next_node;
- } else {
- element = NULL;
- }
- }
- if (dukky_push_node(ctx, (dom_node *)element) == false) {
- dom_node_unref(element);
- return 0;
- }
- dom_node_unref(element);
- return 1;
-%}
-
-getter Element::previousElementSibling()
-%{
- dom_node *element;
- dom_exception exc;
- dom_node_type node_type;
- dom_node *sib_node;
-
- exc = dom_node_get_previous_sibling(((node_private_t *)priv)->node, &element);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- while (element != NULL) {
- exc = dom_node_get_node_type(element, &node_type);
- if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
- /* found it */
- break;
- }
-
- exc = dom_node_get_previous_sibling(element, &sib_node);
- dom_node_unref(element);
- if (exc == DOM_NO_ERR) {
- element = sib_node;
- } else {
- element = NULL;
- }
- }
- if (dukky_push_node(ctx, (dom_node *)element) == false) {
- dom_node_unref(element);
- return 0;
- }
- dom_node_unref(element);
- return 1;
-%}
-
-getter Element::nextElementSibling()
-%{
- dom_node *element;
- dom_exception exc;
- dom_node_type node_type;
- dom_node *sib_node;
-
- exc = dom_node_get_next_sibling(((node_private_t *)priv)->node, &element);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- while (element != NULL) {
- exc = dom_node_get_node_type(element, &node_type);
- if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
- /* found it */
- break;
- }
-
- exc = dom_node_get_next_sibling(element, &sib_node);
- dom_node_unref(element);
- if (exc == DOM_NO_ERR) {
- element = sib_node;
- } else {
- element = NULL;
- }
- }
- if (dukky_push_node(ctx, (dom_node *)element) == false) {
- dom_node_unref(element);
- return 0;
- }
- dom_node_unref(element);
- return 1;
-%}
-
-getter Element::childElementCount()
-%{
- dom_node *element;
- dom_exception exc;
- dom_node_type node_type;
- dom_node *next_node;
- duk_uint_t jsret = 0;
-
- exc = dom_node_get_first_child(((node_private_t *)priv)->node, &element);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- while (element != NULL) {
- exc = dom_node_get_node_type(element, &node_type);
- if ((exc == DOM_NO_ERR) && (node_type == DOM_ELEMENT_NODE)) {
- jsret += 1;
- }
-
- exc = dom_node_get_next_sibling(element, &next_node);
- dom_node_unref(element);
- if (exc == DOM_NO_ERR) {
- element = next_node;
- } else {
- element = NULL;
- }
- }
- LOG("I found %u of them", jsret);
- duk_push_uint(ctx, jsret);
- return 1;
-%}
-
-method Element::getElementsByTagName ()
-%{
- dom_nodelist *nlist = NULL;
- dom_exception exc;
- dom_string *tagname;
- duk_size_t len;
- const char *str = duk_to_lstring(ctx, 0, &len);
-
- exc = dom_string_create((const uint8_t *)str, len, &tagname);
-
- if (exc != DOM_NO_ERR) return 0;
-
- exc = dom_element_get_elements_by_tag_name(priv->parent.node,
- tagname, &nlist);
- dom_string_unref(tagname);
- if (exc != DOM_NO_ERR) return 0;
- duk_push_pointer(ctx, nlist);
- dukky_create_object(ctx, PROTO_NAME(NODELIST), 1);
- dom_nodelist_unref(nlist);
-
- return 1;
-%}
-
-getter Element::id ()
-%{
- dom_string *idstr = NULL;
- dom_exception exc;
-
- exc = dom_element_get_attribute(priv->parent.node,
- corestring_dom_id,
- &idstr);
- if (exc != DOM_NO_ERR) return 0;
- if (idstr == NULL) {
- duk_push_lstring(ctx, "", 0);
- } else {
- duk_push_lstring(ctx, dom_string_data(idstr),
- dom_string_length(idstr));
- dom_string_unref(idstr);
- }
- return 1;
-%}
-
-setter Element::id ()
-%{
- dom_string *idstr = NULL;
- dom_exception exc;
- duk_size_t slen;
- const char *s = duk_safe_to_lstring(ctx, 0, &slen);
-
- exc = dom_string_create((const uint8_t *)s, slen, &idstr);
- if (exc != DOM_NO_ERR) return 0;
-
- exc = dom_element_set_attribute(priv->parent.node,
- corestring_dom_id,
- idstr);
- dom_string_unref(idstr);
- if (exc != DOM_NO_ERR) return 0;
- return 0;
-%}
-
-
-method Element::removeAttribute()
-%{
- dom_string *attr = NULL;
- dom_exception exc;
- duk_size_t slen;
- const char *s = duk_safe_to_lstring(ctx, 0, &slen);
-
- exc = dom_string_create((const uint8_t *)s, slen, &attr);
- if (exc != DOM_NO_ERR) return 0;
-
- exc = dom_element_remove_attribute(priv->parent.node, attr);
- dom_string_unref(attr);
- if (exc != DOM_NO_ERR) return 0;
- return 0;
-%}
-
-method Element::getAttribute()
-%{
- dom_string *attr_name = NULL;
- dom_string *attr_value = NULL;
- dom_exception exc;
- duk_size_t slen;
-
- const char *s = duk_safe_to_lstring(ctx, 0, &slen);
- exc = dom_string_create((const uint8_t *)s, slen, &attr_name);
- duk_pop(ctx);
-
- exc = dom_element_get_attribute(priv->parent.node,
- attr_name, &attr_value);
- dom_string_unref(attr_name);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- if (attr_value == NULL) {
- duk_push_null(ctx);
- } else {
- duk_push_lstring(ctx, dom_string_data(attr_value),
- dom_string_length(attr_value));
- dom_string_unref(attr_value);
- }
- return 1;
-%}
-
-method Element::setAttribute()
-%{
- dom_exception exc;
- dom_string *attr_str, *value_str;
- duk_size_t attr_len, value_len;
- const char *attr = duk_safe_to_lstring(ctx, 0, &attr_len);
- const char *value = duk_safe_to_lstring(ctx, 1, &value_len);
-
- exc = dom_string_create((const uint8_t *)attr, attr_len, &attr_str);
- if (exc != DOM_NO_ERR) return 0;
-
- exc = dom_string_create((const uint8_t *)value, value_len, &value_str);
- if (exc != DOM_NO_ERR) {
- dom_string_unref(attr_str);
- return 0;
- }
-
- exc = dom_element_set_attribute(priv->parent.node,
- attr_str, value_str);
- dom_string_unref(attr_str);
- dom_string_unref(value_str);
- if (exc != DOM_NO_ERR) return 0;
- return 0;
-%}
-
-method Element::hasAttribute()
-%{
- dom_string *attr_name = NULL;
- dom_exception exc;
- duk_size_t slen;
- bool res;
-
- const char *s = duk_safe_to_lstring(ctx, 0, &slen);
- exc = dom_string_create((const uint8_t *)s, slen, &attr_name);
- duk_pop(ctx);
-
- exc = dom_element_has_attribute(priv->parent.node,
- attr_name, &res);
- dom_string_unref(attr_name);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- duk_push_boolean(ctx, res);
- return 1;
-%}
-
-getter Element::className ()
-%{
- dom_string *classstr = NULL;
- dom_exception exc;
-
- exc = dom_element_get_attribute(priv->parent.node,
- corestring_dom_class,
- &classstr);
- if (exc != DOM_NO_ERR) return 0;
- if (classstr == NULL) {
- duk_push_lstring(ctx, "", 0);
- } else {
- duk_push_lstring(ctx, dom_string_data(classstr),
- dom_string_length(classstr));
- dom_string_unref(classstr);
- }
- return 1;
-%}
-
-setter Element::className ()
-%{
- dom_string *classstr = NULL;
- dom_exception exc;
- duk_size_t slen;
- const char *s = duk_safe_to_lstring(ctx, 0, &slen);
-
- exc = dom_string_create((const uint8_t *)s, slen, &classstr);
- if (exc != DOM_NO_ERR) return 0;
-
- exc = dom_element_set_attribute(priv->parent.node,
- corestring_dom_class,
- classstr);
- dom_string_unref(classstr);
- if (exc != DOM_NO_ERR) return 0;
- return 0;
-%}
-
diff --git a/javascript/duktape/Event.bnd b/javascript/duktape/Event.bnd
deleted file mode 100644
index a0bc3c3e7..000000000
--- a/javascript/duktape/Event.bnd
+++ /dev/null
@@ -1,150 +0,0 @@
-/* Event binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- * Copyright 2015 Daniel Silverstone <dsilvers@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-class Event {
- private dom_event *evt;
-};
-
-init Event (struct dom_event *evt)
-%{
- priv->evt = evt;
- dom_event_ref(evt);
-%}
-
-fini Event ()
-%{
- dom_event_unref(priv->evt);
-%}
-
-/* Note: many of these could be automatics once nsgenbind gets there. */
-
-getter Event::type ()
-%{
- dom_string *ret;
- dom_exception exc;
-
- exc = dom_event_get_type(priv->evt, &ret);
- if (exc != DOM_NO_ERR) return 0;
- if (ret == NULL) {
- duk_push_lstring(ctx, "", 0);
- } else {
- duk_push_lstring(ctx, dom_string_data(ret),
- dom_string_length(ret));
- dom_string_unref(ret);
- }
-
- return 1;
-%}
-
-getter Event::target ()
-%{
- /** @todo Decide HTF this works wrt. Window as an event target */
- dom_node *et;
- dom_exception exc;
-
- exc = dom_event_get_target(priv->evt, &et);
- if (exc != DOM_NO_ERR) return 0;
-
- dukky_push_node(ctx, et);
- return 1;
-%}
-
-getter Event::currentTarget ()
-%{
- /** @todo Decide HTF this works wrt. Window as an event target */
- dom_node *et;
- dom_exception exc;
-
- exc = dom_event_get_current_target(priv->evt, &et);
- if (exc != DOM_NO_ERR) return 0;
-
- dukky_push_node(ctx, et);
- return 1;
-%}
-
-getter Event::eventPhase ()
-%{
- dom_exception exc;
- dom_event_flow_phase phase;
-
- exc = dom_event_get_event_phase(priv->evt, &phase);
- if (exc != DOM_NO_ERR) return 0;
-
- duk_push_uint(ctx, phase);
- return 1;
-%}
-
-method Event::stopPropagation ()
-%{
- dom_exception exc;
-
- exc = dom_event_stop_propagation(priv->evt);
- if (exc != DOM_NO_ERR) return 0;
-
- return 0;
-%}
-
-method Event::stopImmediatePropagation ()
-%{
- dom_exception exc;
-
- exc = dom_event_stop_immediate_propagation(priv->evt);
- if (exc != DOM_NO_ERR) return 0;
-
- return 0;
-%}
-
-getter Event::bubbles ()
-%{
- dom_exception exc;
- bool ret;
-
- exc = dom_event_get_bubbles(priv->evt, &ret);
- if (exc != DOM_NO_ERR) return 0;
-
- duk_push_boolean(ctx, ret);
- return 1;
-%}
-
-getter Event::cancelable ()
-%{
- dom_exception exc;
- bool ret;
-
- exc = dom_event_get_cancelable(priv->evt, &ret);
- if (exc != DOM_NO_ERR) return 0;
-
- duk_push_boolean(ctx, ret);
- return 1;
-%}
-
-method Event::preventDefault ()
-%{
- dom_exception exc;
-
- exc = dom_event_prevent_default(priv->evt);
- if (exc != DOM_NO_ERR) return 0;
-
- return 0;
-%}
-
-getter Event::defaultPrevented ()
-%{
- dom_exception exc;
- bool ret;
-
- exc = dom_event_is_default_prevented(priv->evt, &ret);
- if (exc != DOM_NO_ERR) return 0;
-
- duk_push_boolean(ctx, ret);
- return 1;
-%}
-
diff --git a/javascript/duktape/HTMLAnchorElement.bnd b/javascript/duktape/HTMLAnchorElement.bnd
deleted file mode 100644
index 3dcfef72e..000000000
--- a/javascript/duktape/HTMLAnchorElement.bnd
+++ /dev/null
@@ -1,39 +0,0 @@
-/* HTML anchor element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLAnchorElement(struct dom_html_element *html_anchor_element::html_element);
-
-getter HTMLAnchorElement::charset();
-setter HTMLAnchorElement::charset();
-
-getter HTMLAnchorElement::coords();
-setter HTMLAnchorElement::coords();
-
-getter HTMLAnchorElement::hreflang();
-setter HTMLAnchorElement::hreflang();
-
-getter HTMLAnchorElement::name();
-setter HTMLAnchorElement::name();
-
-getter HTMLAnchorElement::rel();
-setter HTMLAnchorElement::rel();
-
-getter HTMLAnchorElement::rev();
-setter HTMLAnchorElement::rev();
-
-getter HTMLAnchorElement::shape();
-setter HTMLAnchorElement::shape();
-
-getter HTMLAnchorElement::target();
-setter HTMLAnchorElement::target();
-
-
-
-
diff --git a/javascript/duktape/HTMLAppletElement.bnd b/javascript/duktape/HTMLAppletElement.bnd
deleted file mode 100644
index 8bf3ff2f7..000000000
--- a/javascript/duktape/HTMLAppletElement.bnd
+++ /dev/null
@@ -1,30 +0,0 @@
-/* HTML applet element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLAppletElement(struct dom_html_element *html_applet_element::html_element);
-
-getter HTMLAppletElement::align();
-setter HTMLAppletElement::align();
-getter HTMLAppletElement::alt();
-setter HTMLAppletElement::alt();
-getter HTMLAppletElement::archive();
-setter HTMLAppletElement::archive();
-getter HTMLAppletElement::codeBase();
-setter HTMLAppletElement::codeBase();
-getter HTMLAppletElement::code();
-setter HTMLAppletElement::code();
-getter HTMLAppletElement::height();
-setter HTMLAppletElement::height();
-getter HTMLAppletElement::name();
-setter HTMLAppletElement::name();
-getter HTMLAppletElement::object();
-setter HTMLAppletElement::object();
-getter HTMLAppletElement::width();
-setter HTMLAppletElement::width();
diff --git a/javascript/duktape/HTMLAreaElement.bnd b/javascript/duktape/HTMLAreaElement.bnd
deleted file mode 100644
index b6c17031c..000000000
--- a/javascript/duktape/HTMLAreaElement.bnd
+++ /dev/null
@@ -1,26 +0,0 @@
-/* HTML area element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLAreaElement(struct dom_html_element *html_area_element::html_element);
-
-getter HTMLAreaElement::alt();
-setter HTMLAreaElement::alt();
-
-getter HTMLAreaElement::coords();
-setter HTMLAreaElement::coords();
-
-getter HTMLAreaElement::noHref();
-setter HTMLAreaElement::noHref();
-
-getter HTMLAreaElement::shape();
-setter HTMLAreaElement::shape();
-
-getter HTMLAreaElement::target();
-setter HTMLAreaElement::target();
diff --git a/javascript/duktape/HTMLBRElement.bnd b/javascript/duktape/HTMLBRElement.bnd
deleted file mode 100644
index 3b44b9777..000000000
--- a/javascript/duktape/HTMLBRElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML br element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLBRElement(struct dom_html_element *html_br_element::html_element);
-
-getter HTMLBRElement::clear();
-setter HTMLBRElement::clear();
diff --git a/javascript/duktape/HTMLBaseElement.bnd b/javascript/duktape/HTMLBaseElement.bnd
deleted file mode 100644
index 143aefd36..000000000
--- a/javascript/duktape/HTMLBaseElement.bnd
+++ /dev/null
@@ -1,17 +0,0 @@
-/* HTML base element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLBaseElement(struct dom_html_element *html_base_element::html_element);
-
-getter HTMLBaseElement::href();
-setter HTMLBaseElement::href();
-
-getter HTMLBaseElement::target();
-setter HTMLBaseElement::target();
diff --git a/javascript/duktape/HTMLBodyElement.bnd b/javascript/duktape/HTMLBodyElement.bnd
deleted file mode 100644
index a283f897c..000000000
--- a/javascript/duktape/HTMLBodyElement.bnd
+++ /dev/null
@@ -1,24 +0,0 @@
-/* HTML body element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLBodyElement(struct dom_html_element *html_body_element::html_element);
-
-getter HTMLBodyElement::aLink();
-setter HTMLBodyElement::aLink();
-getter HTMLBodyElement::background();
-setter HTMLBodyElement::background();
-getter HTMLBodyElement::bgColor();
-setter HTMLBodyElement::bgColor();
-getter HTMLBodyElement::link();
-setter HTMLBodyElement::link();
-getter HTMLBodyElement::text();
-setter HTMLBodyElement::text();
-getter HTMLBodyElement::vLink();
-setter HTMLBodyElement::vLink();
diff --git a/javascript/duktape/HTMLButtonElement.bnd b/javascript/duktape/HTMLButtonElement.bnd
deleted file mode 100644
index 53431aa04..000000000
--- a/javascript/duktape/HTMLButtonElement.bnd
+++ /dev/null
@@ -1,18 +0,0 @@
-/* HTML button element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLButtonElement(struct dom_html_element *html_button_element::html_element);
-
-getter HTMLButtonElement::disabled();
-setter HTMLButtonElement::disabled();
-getter HTMLButtonElement::name();
-setter HTMLButtonElement::name();
-getter HTMLButtonElement::value();
-setter HTMLButtonElement::value();
diff --git a/javascript/duktape/HTMLCollection.bnd b/javascript/duktape/HTMLCollection.bnd
deleted file mode 100644
index 2ffe7027b..000000000
--- a/javascript/duktape/HTMLCollection.bnd
+++ /dev/null
@@ -1,24 +0,0 @@
-/* HTMLCollection binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-class HTMLCollection {
- private struct dom_html_collection *coll;
-};
-
-init HTMLCollection(struct dom_html_collection *coll)
-%{
- priv->coll = coll;
- dom_html_collection_ref(coll);
-%}
-
-fini HTMLCollection()
-%{
- dom_html_collection_unref(priv->coll);
-%}
diff --git a/javascript/duktape/HTMLDivElement.bnd b/javascript/duktape/HTMLDivElement.bnd
deleted file mode 100644
index 759e34d96..000000000
--- a/javascript/duktape/HTMLDivElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML div element binding using duktape and libdom
- *
- * Copyright 2015 Michael Drake <tlsa@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLDivElement(struct dom_html_element *html_div_element::html_element);
-
-getter HTMLDivElement::align();
-setter HTMLDivElement::align();
diff --git a/javascript/duktape/HTMLElement.bnd b/javascript/duktape/HTMLElement.bnd
deleted file mode 100644
index b3de9c8fe..000000000
--- a/javascript/duktape/HTMLElement.bnd
+++ /dev/null
@@ -1,162 +0,0 @@
-/* HTML element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-prologue HTMLElement()
-%{
-#include <utils/corestrings.h>
-#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
-%}
-
-init HTMLElement(struct dom_html_element *html_element::element);
-
-getter HTMLElement::dir();
-setter HTMLElement::dir();
-
-getter HTMLElement::lang();
-setter HTMLElement::lang();
-
-getter HTMLElement::title();
-setter HTMLElement::title();
-
-getter HTMLElement::onchange();
-setter HTMLElement::onchange();
-
-setter HTMLElement::onclick();
-getter HTMLElement::onclick();
-
-getter HTMLElement::onabort();
-setter HTMLElement::onabort();
-getter HTMLElement::onautocompleteerror();
-setter HTMLElement::onautocompleteerror();
-getter HTMLElement::onautocomplete();
-setter HTMLElement::onautocomplete();
-getter HTMLElement::onblur();
-setter HTMLElement::onblur();
-getter HTMLElement::oncancel();
-setter HTMLElement::oncancel();
-getter HTMLElement::oncanplaythrough();
-setter HTMLElement::oncanplaythrough();
-getter HTMLElement::oncanplay();
-setter HTMLElement::oncanplay();
-getter HTMLElement::onclose();
-setter HTMLElement::onclose();
-getter HTMLElement::oncontextmenu();
-setter HTMLElement::oncontextmenu();
-getter HTMLElement::oncuechange();
-setter HTMLElement::oncuechange();
-getter HTMLElement::ondblclick();
-setter HTMLElement::ondblclick();
-getter HTMLElement::ondragend();
-setter HTMLElement::ondragend();
-getter HTMLElement::ondragenter();
-setter HTMLElement::ondragenter();
-getter HTMLElement::ondragexit();
-setter HTMLElement::ondragexit();
-getter HTMLElement::ondragleave();
-setter HTMLElement::ondragleave();
-getter HTMLElement::ondragover();
-setter HTMLElement::ondragover();
-getter HTMLElement::ondragstart();
-setter HTMLElement::ondragstart();
-getter HTMLElement::ondrag();
-setter HTMLElement::ondrag();
-getter HTMLElement::ondrop();
-setter HTMLElement::ondrop();
-getter HTMLElement::ondurationchange();
-setter HTMLElement::ondurationchange();
-getter HTMLElement::onemptied();
-setter HTMLElement::onemptied();
-getter HTMLElement::onended();
-setter HTMLElement::onended();
-getter HTMLElement::onfocus();
-setter HTMLElement::onfocus();
-getter HTMLElement::oninput();
-setter HTMLElement::oninput();
-getter HTMLElement::oninvalid();
-setter HTMLElement::oninvalid();
-getter HTMLElement::onkeydown();
-setter HTMLElement::onkeydown();
-getter HTMLElement::onkeypress();
-setter HTMLElement::onkeypress();
-getter HTMLElement::onkeyup();
-setter HTMLElement::onkeyup();
-getter HTMLElement::onloadeddata();
-setter HTMLElement::onloadeddata();
-getter HTMLElement::onloadedmetadata();
-setter HTMLElement::onloadedmetadata();
-getter HTMLElement::onloadstart();
-setter HTMLElement::onloadstart();
-getter HTMLElement::onload();
-setter HTMLElement::onload();
-getter HTMLElement::onmousedown();
-setter HTMLElement::onmousedown();
-getter HTMLElement::onmouseenter();
-setter HTMLElement::onmouseenter();
-getter HTMLElement::onmouseleave();
-setter HTMLElement::onmouseleave();
-getter HTMLElement::onmousemove();
-setter HTMLElement::onmousemove();
-getter HTMLElement::onmouseout();
-setter HTMLElement::onmouseout();
-getter HTMLElement::onmouseover();
-setter HTMLElement::onmouseover();
-getter HTMLElement::onmouseup();
-setter HTMLElement::onmouseup();
-getter HTMLElement::onpause();
-setter HTMLElement::onpause();
-getter HTMLElement::onplaying();
-setter HTMLElement::onplaying();
-getter HTMLElement::onplay();
-setter HTMLElement::onplay();
-getter HTMLElement::onprogress();
-setter HTMLElement::onprogress();
-getter HTMLElement::onratechange();
-setter HTMLElement::onratechange();
-getter HTMLElement::onreset();
-setter HTMLElement::onreset();
-getter HTMLElement::onresize();
-setter HTMLElement::onresize();
-getter HTMLElement::onscroll();
-setter HTMLElement::onscroll();
-getter HTMLElement::onseeked();
-setter HTMLElement::onseeked();
-getter HTMLElement::onseeking();
-setter HTMLElement::onseeking();
-getter HTMLElement::onselect();
-setter HTMLElement::onselect();
-getter HTMLElement::onshow();
-setter HTMLElement::onshow();
-getter HTMLElement::onsort();
-setter HTMLElement::onsort();
-getter HTMLElement::onstalled();
-setter HTMLElement::onstalled();
-getter HTMLElement::onsubmit();
-setter HTMLElement::onsubmit();
-getter HTMLElement::onsuspend();
-setter HTMLElement::onsuspend();
-getter HTMLElement::ontimeupdate();
-setter HTMLElement::ontimeupdate();
-getter HTMLElement::ontoggle();
-setter HTMLElement::ontoggle();
-getter HTMLElement::onvolumechange();
-setter HTMLElement::onvolumechange();
-getter HTMLElement::onwaiting();
-setter HTMLElement::onwaiting();
-getter HTMLElement::onwheel();
-setter HTMLElement::onwheel();
-
-getter HTMLElement::style()
-%{
- /* Minimal implementation to avoid infinite-loop in Modernizr (c.f. #2413) */
- if (dukky_create_object(ctx, PROTO_NAME(CSSSTYLEDECLARATION), 0) != DUK_EXEC_SUCCESS) {
- return 0;
- }
- return 1;
-%}
diff --git a/javascript/duktape/HTMLFontElement.bnd b/javascript/duktape/HTMLFontElement.bnd
deleted file mode 100644
index e648a72e1..000000000
--- a/javascript/duktape/HTMLFontElement.bnd
+++ /dev/null
@@ -1,20 +0,0 @@
-/* HTML font element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLFontElement(struct dom_html_element *html_font_element::html_element);
-
-getter HTMLFontElement::color();
-setter HTMLFontElement::color();
-
-getter HTMLFontElement::face();
-setter HTMLFontElement::face();
-
-getter HTMLFontElement::size();
-setter HTMLFontElement::size();
diff --git a/javascript/duktape/HTMLFormElement.bnd b/javascript/duktape/HTMLFormElement.bnd
deleted file mode 100644
index 3906cf0b3..000000000
--- a/javascript/duktape/HTMLFormElement.bnd
+++ /dev/null
@@ -1,26 +0,0 @@
-/* HTML form element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLFormElement(struct dom_html_element *html_form_element::html_element);
-
-getter HTMLFormElement::acceptCharset();
-setter HTMLFormElement::acceptCharset();
-
-getter HTMLFormElement::action();
-setter HTMLFormElement::action();
-
-getter HTMLFormElement::enctype();
-setter HTMLFormElement::enctype();
-
-getter HTMLFormElement::method();
-setter HTMLFormElement::method();
-
-getter HTMLFormElement::target();
-setter HTMLFormElement::target();
diff --git a/javascript/duktape/HTMLFrameElement.bnd b/javascript/duktape/HTMLFrameElement.bnd
deleted file mode 100644
index ee5cfe3d0..000000000
--- a/javascript/duktape/HTMLFrameElement.bnd
+++ /dev/null
@@ -1,35 +0,0 @@
-/* HTML frame element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLFrameElement(struct dom_html_element *html_frame_element::html_element);
-
-getter HTMLFrameElement::frameBorder();
-setter HTMLFrameElement::frameBorder();
-
-getter HTMLFrameElement::longDesc();
-setter HTMLFrameElement::longDesc();
-
-getter HTMLFrameElement::marginHeight();
-setter HTMLFrameElement::marginHeight();
-
-getter HTMLFrameElement::marginWidth();
-setter HTMLFrameElement::marginWidth();
-
-getter HTMLFrameElement::name();
-setter HTMLFrameElement::name();
-
-getter HTMLFrameElement::noResize();
-setter HTMLFrameElement::noResize();
-
-getter HTMLFrameElement::scrolling();
-setter HTMLFrameElement::scrolling();
-
-getter HTMLFrameElement::src();
-setter HTMLFrameElement::src();
diff --git a/javascript/duktape/HTMLFrameSetElement.bnd b/javascript/duktape/HTMLFrameSetElement.bnd
deleted file mode 100644
index cc66e93d8..000000000
--- a/javascript/duktape/HTMLFrameSetElement.bnd
+++ /dev/null
@@ -1,17 +0,0 @@
-/* HTML frame set element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLFrameSetElement(struct dom_html_element *html_frame_set_element::html_element);
-
-getter HTMLFrameSetElement::cols();
-setter HTMLFrameSetElement::cols();
-
-getter HTMLFrameSetElement::rows();
-setter HTMLFrameSetElement::rows();
diff --git a/javascript/duktape/HTMLHRElement.bnd b/javascript/duktape/HTMLHRElement.bnd
deleted file mode 100644
index 421ec499b..000000000
--- a/javascript/duktape/HTMLHRElement.bnd
+++ /dev/null
@@ -1,24 +0,0 @@
-/* HTML hr element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLHRElement(struct dom_html_element *html_hr_element::html_element);
-
-getter HTMLHRElement::noShade();
-setter HTMLHRElement::noShade();
-
-getter HTMLHRElement::align();
-setter HTMLHRElement::align();
-
-getter HTMLHRElement::size();
-setter HTMLHRElement::size();
-
-getter HTMLHRElement::width();
-setter HTMLHRElement::width();
-
diff --git a/javascript/duktape/HTMLHTMLElement.bnd b/javascript/duktape/HTMLHTMLElement.bnd
deleted file mode 100644
index 01697d860..000000000
--- a/javascript/duktape/HTMLHTMLElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML html element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLHtmlElement(struct dom_html_element *html_html_element::html_element);
-
-getter HTMLHtmlElement::version();
-setter HTMLHtmlElement::version();
diff --git a/javascript/duktape/HTMLHeadingElement.bnd b/javascript/duktape/HTMLHeadingElement.bnd
deleted file mode 100644
index be51223c1..000000000
--- a/javascript/duktape/HTMLHeadingElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML heading element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLHeadingElement(struct dom_html_element *html_heading_element::html_element);
-
-getter HTMLHeadingElement::align();
-setter HTMLHeadingElement::align();
diff --git a/javascript/duktape/HTMLIFrameElement.bnd b/javascript/duktape/HTMLIFrameElement.bnd
deleted file mode 100644
index 64353769c..000000000
--- a/javascript/duktape/HTMLIFrameElement.bnd
+++ /dev/null
@@ -1,41 +0,0 @@
-/* HTML I frame element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLIFrameElement(struct dom_html_element *html_iframe_element::html_element);
-
-getter HTMLIFrameElement::align();
-setter HTMLIFrameElement::align();
-
-getter HTMLIFrameElement::frameBorder();
-setter HTMLIFrameElement::frameBorder();
-
-getter HTMLIFrameElement::height();
-setter HTMLIFrameElement::height();
-
-getter HTMLIFrameElement::longDesc();
-setter HTMLIFrameElement::longDesc();
-
-getter HTMLIFrameElement::marginHeight();
-setter HTMLIFrameElement::marginHeight();
-
-getter HTMLIFrameElement::marginWidth();
-setter HTMLIFrameElement::marginWidth();
-
-getter HTMLIFrameElement::name();
-setter HTMLIFrameElement::name();
-
-getter HTMLIFrameElement::scrolling();
-setter HTMLIFrameElement::scrolling();
-
-getter HTMLIFrameElement::src();
-setter HTMLIFrameElement::src();
-
-getter HTMLIFrameElement::width();
-setter HTMLIFrameElement::width();
diff --git a/javascript/duktape/HTMLImageElement.bnd b/javascript/duktape/HTMLImageElement.bnd
deleted file mode 100644
index 96b35b6f8..000000000
--- a/javascript/duktape/HTMLImageElement.bnd
+++ /dev/null
@@ -1,47 +0,0 @@
-/* HTML image element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLImageElement(struct dom_html_element *html_image_element::html_element);
-
-getter HTMLImageElement::align();
-setter HTMLImageElement::align();
-
-getter HTMLImageElement::alt();
-setter HTMLImageElement::alt();
-
-getter HTMLImageElement::border();
-setter HTMLImageElement::border();
-
-getter HTMLImageElement::isMap();
-setter HTMLImageElement::isMap();
-
-getter HTMLImageElement::longDesc();
-setter HTMLImageElement::longDesc();
-
-getter HTMLImageElement::name();
-setter HTMLImageElement::name();
-
-getter HTMLImageElement::src();
-setter HTMLImageElement::src();
-
-getter HTMLImageElement::useMap();
-setter HTMLImageElement::useMap();
-
-getter HTMLImageElement::height();
-setter HTMLImageElement::height();
-
-getter HTMLImageElement::hspace();
-setter HTMLImageElement::hspace();
-
-getter HTMLImageElement::vspace();
-setter HTMLImageElement::vspace();
-
-getter HTMLImageElement::width();
-setter HTMLImageElement::width();
diff --git a/javascript/duktape/HTMLInputElement.bnd b/javascript/duktape/HTMLInputElement.bnd
deleted file mode 100644
index 23645d0cd..000000000
--- a/javascript/duktape/HTMLInputElement.bnd
+++ /dev/null
@@ -1,64 +0,0 @@
-/* HTML input element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLInputElement(struct dom_html_element *html_input_element::html_element);
-
-getter HTMLInputElement::accept();
-setter HTMLInputElement::accept();
-
-getter HTMLInputElement::align();
-setter HTMLInputElement::align();
-
-getter HTMLInputElement::alt();
-setter HTMLInputElement::alt();
-
-getter HTMLInputElement::checked();
-setter HTMLInputElement::checked();
-
-getter HTMLInputElement::defaultChecked();
-setter HTMLInputElement::defaultChecked();
-
-getter HTMLInputElement::defaultValue();
-setter HTMLInputElement::defaultValue();
-
-getter HTMLInputElement::disabled();
-setter HTMLInputElement::disabled();
-
-getter HTMLInputElement::name();
-setter HTMLInputElement::name();
-
-getter HTMLInputElement::readOnly();
-setter HTMLInputElement::readOnly();
-
-getter HTMLInputElement::src();
-setter HTMLInputElement::src();
-
-getter HTMLInputElement::useMap();
-setter HTMLInputElement::useMap();
-
-getter HTMLInputElement::valueAsNumber();
-setter HTMLInputElement::valueAsNumber();
-
-getter HTMLInputElement::valueHigh();
-setter HTMLInputElement::valueHigh();
-
-getter HTMLInputElement::valueLow();
-setter HTMLInputElement::valueLow();
-
-getter HTMLInputElement::value();
-setter HTMLInputElement::value();
-
-getter HTMLInputElement::maxLength();
-setter HTMLInputElement::maxLength();
-
-getter HTMLInputElement::size();
-setter HTMLInputElement::size();
-
-getter HTMLInputElement::type();
diff --git a/javascript/duktape/HTMLLIElement.bnd b/javascript/duktape/HTMLLIElement.bnd
deleted file mode 100644
index a585693c0..000000000
--- a/javascript/duktape/HTMLLIElement.bnd
+++ /dev/null
@@ -1,17 +0,0 @@
-/* HTML li element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLLIElement(struct dom_html_element *html_li_element::html_element);
-
-getter HTMLLIElement::type();
-setter HTMLLIElement::type();
-
-getter HTMLLIElement::value();
-setter HTMLLIElement::value();
diff --git a/javascript/duktape/HTMLLabelElement.bnd b/javascript/duktape/HTMLLabelElement.bnd
deleted file mode 100644
index 018f798bd..000000000
--- a/javascript/duktape/HTMLLabelElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML label element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLLabelElement(struct dom_html_element *html_label_element::html_element);
-
-getter HTMLLabelElement::htmlFor();
-setter HTMLLabelElement::htmlFor();
diff --git a/javascript/duktape/HTMLLegendElement.bnd b/javascript/duktape/HTMLLegendElement.bnd
deleted file mode 100644
index 1bb95a94a..000000000
--- a/javascript/duktape/HTMLLegendElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML legend element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLLegendElement(struct dom_html_element *html_legend_element::html_element);
-
-getter HTMLLegendElement::align();
-setter HTMLLegendElement::align();
diff --git a/javascript/duktape/HTMLLinkElement.bnd b/javascript/duktape/HTMLLinkElement.bnd
deleted file mode 100644
index b215d76c0..000000000
--- a/javascript/duktape/HTMLLinkElement.bnd
+++ /dev/null
@@ -1,35 +0,0 @@
-/* HTML link element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLLinkElement(struct dom_html_element *html_link_element::html_element);
-
-getter HTMLLinkElement::charset();
-setter HTMLLinkElement::charset();
-
-getter HTMLLinkElement::hreflang();
-setter HTMLLinkElement::hreflang();
-
-getter HTMLLinkElement::href();
-setter HTMLLinkElement::href();
-
-getter HTMLLinkElement::media();
-setter HTMLLinkElement::media();
-
-getter HTMLLinkElement::rel();
-setter HTMLLinkElement::rel();
-
-getter HTMLLinkElement::rev();
-setter HTMLLinkElement::rev();
-
-getter HTMLLinkElement::target();
-setter HTMLLinkElement::target();
-
-getter HTMLLinkElement::type();
-setter HTMLLinkElement::type();
diff --git a/javascript/duktape/HTMLMapElement.bnd b/javascript/duktape/HTMLMapElement.bnd
deleted file mode 100644
index 0603f6f81..000000000
--- a/javascript/duktape/HTMLMapElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML map element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLMapElement(struct dom_html_element *html_map_element::html_element);
-
-getter HTMLMapElement::name();
-setter HTMLMapElement::name();
diff --git a/javascript/duktape/HTMLMarqueeElement.bnd b/javascript/duktape/HTMLMarqueeElement.bnd
deleted file mode 100644
index 16fbdc82c..000000000
--- a/javascript/duktape/HTMLMarqueeElement.bnd
+++ /dev/null
@@ -1,11 +0,0 @@
-/* HTML marquee element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLMarqueeElement(struct dom_html_element *html_marquee_element::html_element);
diff --git a/javascript/duktape/HTMLMenuElement.bnd b/javascript/duktape/HTMLMenuElement.bnd
deleted file mode 100644
index c7097b706..000000000
--- a/javascript/duktape/HTMLMenuElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML menu element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLMenuElement(struct dom_html_element *html_menu_element::html_element);
-
-getter HTMLMenuElement::compact();
-setter HTMLMenuElement::compact();
diff --git a/javascript/duktape/HTMLMetaElement.bnd b/javascript/duktape/HTMLMetaElement.bnd
deleted file mode 100644
index f9ecd4b07..000000000
--- a/javascript/duktape/HTMLMetaElement.bnd
+++ /dev/null
@@ -1,23 +0,0 @@
-/* HTML meta element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLMetaElement(struct dom_html_element *html_meta_element::html_element);
-
-getter HTMLMetaElement::content();
-setter HTMLMetaElement::content();
-
-getter HTMLMetaElement::httpEquiv();
-setter HTMLMetaElement::httpEquiv();
-
-getter HTMLMetaElement::name();
-setter HTMLMetaElement::name();
-
-getter HTMLMetaElement::scheme();
-setter HTMLMetaElement::scheme();
diff --git a/javascript/duktape/HTMLOListElement.bnd b/javascript/duktape/HTMLOListElement.bnd
deleted file mode 100644
index 8c12712a9..000000000
--- a/javascript/duktape/HTMLOListElement.bnd
+++ /dev/null
@@ -1,18 +0,0 @@
-/* HTML ol element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLOListElement(struct dom_html_element *html_o_list_element::html_element);
-
-getter HTMLOListElement::compact();
-setter HTMLOListElement::compact();
-getter HTMLOListElement::start();
-setter HTMLOListElement::start();
-getter HTMLOListElement::type();
-setter HTMLOListElement::type();
diff --git a/javascript/duktape/HTMLObjectElement.bnd b/javascript/duktape/HTMLObjectElement.bnd
deleted file mode 100644
index 2d07a7bb2..000000000
--- a/javascript/duktape/HTMLObjectElement.bnd
+++ /dev/null
@@ -1,54 +0,0 @@
-/* HTML object element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLObjectElement(struct dom_html_element *html_object_element::html_element);
-
-getter HTMLObjectElement::align();
-setter HTMLObjectElement::align();
-
-getter HTMLObjectElement::archive();
-setter HTMLObjectElement::archive();
-
-getter HTMLObjectElement::border();
-setter HTMLObjectElement::border();
-
-getter HTMLObjectElement::codeBase();
-setter HTMLObjectElement::codeBase();
-
-getter HTMLObjectElement::code();
-setter HTMLObjectElement::code();
-
-getter HTMLObjectElement::codeType();
-setter HTMLObjectElement::codeType();
-
-getter HTMLObjectElement::data();
-setter HTMLObjectElement::data();
-
-getter HTMLObjectElement::declare();
-setter HTMLObjectElement::declare();
-
-getter HTMLObjectElement::height();
-setter HTMLObjectElement::height();
-
-getter HTMLObjectElement::name();
-setter HTMLObjectElement::name();
-
-getter HTMLObjectElement::standby();
-setter HTMLObjectElement::standby();
-
-getter HTMLObjectElement::type();
-setter HTMLObjectElement::type();
-
-getter HTMLObjectElement::useMap();
-setter HTMLObjectElement::useMap();
-
-getter HTMLObjectElement::width();
-setter HTMLObjectElement::width();
-
diff --git a/javascript/duktape/HTMLOptionElement.bnd b/javascript/duktape/HTMLOptionElement.bnd
deleted file mode 100644
index d5094b7fa..000000000
--- a/javascript/duktape/HTMLOptionElement.bnd
+++ /dev/null
@@ -1,28 +0,0 @@
-/* HTML option element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLOptionElement(struct dom_html_element *html_option_element::html_element);
-
-getter HTMLOptionElement::defaultSelected();
-setter HTMLOptionElement::defaultSelected();
-
-getter HTMLOptionElement::disabled();
-setter HTMLOptionElement::disabled();
-
-getter HTMLOptionElement::label();
-setter HTMLOptionElement::label();
-
-getter HTMLOptionElement::selected();
-setter HTMLOptionElement::selected();
-
-getter HTMLOptionElement::text();
-
-getter HTMLOptionElement::value();
-setter HTMLOptionElement::value();
diff --git a/javascript/duktape/HTMLParagraphElement.bnd b/javascript/duktape/HTMLParagraphElement.bnd
deleted file mode 100644
index cc9ad83b5..000000000
--- a/javascript/duktape/HTMLParagraphElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML paragraph element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLParagraphElement(struct dom_html_element *html_paragraph_element::html_element);
-
-getter HTMLParagraphElement::align();
-setter HTMLParagraphElement::align();
diff --git a/javascript/duktape/HTMLParamElement.bnd b/javascript/duktape/HTMLParamElement.bnd
deleted file mode 100644
index 8fbe6fca6..000000000
--- a/javascript/duktape/HTMLParamElement.bnd
+++ /dev/null
@@ -1,23 +0,0 @@
-/* HTML param element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLParamElement(struct dom_html_element *html_param_element::html_element);
-
-getter HTMLParamElement::name();
-setter HTMLParamElement::name();
-
-getter HTMLParamElement::type();
-setter HTMLParamElement::type();
-
-getter HTMLParamElement::value();
-setter HTMLParamElement::value();
-
-getter HTMLParamElement::valueType();
-setter HTMLParamElement::valueType();
diff --git a/javascript/duktape/HTMLPreElement.bnd b/javascript/duktape/HTMLPreElement.bnd
deleted file mode 100644
index 06f6a76a9..000000000
--- a/javascript/duktape/HTMLPreElement.bnd
+++ /dev/null
@@ -1,15 +0,0 @@
-/* HTML li element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLPreElement(struct dom_html_element *html_pre_element::html_element);
-
-getter HTMLPreElement::width();
-setter HTMLPreElement::width();
-
diff --git a/javascript/duktape/HTMLQuoteElement.bnd b/javascript/duktape/HTMLQuoteElement.bnd
deleted file mode 100644
index 9e62f5d78..000000000
--- a/javascript/duktape/HTMLQuoteElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML quote element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLQuoteElement(struct dom_html_element *html_quote_element::html_element);
-
-getter HTMLQuoteElement::cite();
-setter HTMLQuoteElement::cite();
diff --git a/javascript/duktape/HTMLScriptElement.bnd b/javascript/duktape/HTMLScriptElement.bnd
deleted file mode 100644
index b3b22665a..000000000
--- a/javascript/duktape/HTMLScriptElement.bnd
+++ /dev/null
@@ -1,32 +0,0 @@
-/* HTML script element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLScriptElement(struct dom_html_element *html_script_element::html_element);
-
-getter HTMLScriptElement::charset();
-setter HTMLScriptElement::charset();
-
-getter HTMLScriptElement::defer();
-setter HTMLScriptElement::defer();
-
-getter HTMLScriptElement::event();
-setter HTMLScriptElement::event();
-
-getter HTMLScriptElement::htmlFor();
-setter HTMLScriptElement::htmlFor();
-
-getter HTMLScriptElement::src();
-setter HTMLScriptElement::src();
-
-getter HTMLScriptElement::text();
-setter HTMLScriptElement::text();
-
-getter HTMLScriptElement::type();
-setter HTMLScriptElement::type();
diff --git a/javascript/duktape/HTMLSelectElement.bnd b/javascript/duktape/HTMLSelectElement.bnd
deleted file mode 100644
index 36a5d1da4..000000000
--- a/javascript/duktape/HTMLSelectElement.bnd
+++ /dev/null
@@ -1,26 +0,0 @@
-/* HTML select element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLSelectElement(struct dom_html_element *html_select_element::html_element);
-
-getter HTMLSelectElement::disabled();
-setter HTMLSelectElement::disabled();
-
-getter HTMLSelectElement::multiple();
-setter HTMLSelectElement::multiple();
-
-getter HTMLSelectElement::name();
-setter HTMLSelectElement::name();
-
-getter HTMLSelectElement::type();
-
-getter HTMLSelectElement::value();
-setter HTMLSelectElement::value();
-
diff --git a/javascript/duktape/HTMLStyleElement.bnd b/javascript/duktape/HTMLStyleElement.bnd
deleted file mode 100644
index 45100876f..000000000
--- a/javascript/duktape/HTMLStyleElement.bnd
+++ /dev/null
@@ -1,17 +0,0 @@
-/* HTML style element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLStyleElement(struct dom_html_element *html_style_element::html_element);
-
-getter HTMLStyleElement::media();
-setter HTMLStyleElement::media();
-
-getter HTMLStyleElement::type();
-setter HTMLStyleElement::type();
diff --git a/javascript/duktape/HTMLTableCaptionElement.bnd b/javascript/duktape/HTMLTableCaptionElement.bnd
deleted file mode 100644
index 75754ccac..000000000
--- a/javascript/duktape/HTMLTableCaptionElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML table caption element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLTableCaptionElement(struct dom_html_element *html_table_caption_element::html_element);
-
-getter HTMLTableCaptionElement::align();
-setter HTMLTableCaptionElement::align();
diff --git a/javascript/duktape/HTMLTableCellElement.bnd b/javascript/duktape/HTMLTableCellElement.bnd
deleted file mode 100644
index 7040344c3..000000000
--- a/javascript/duktape/HTMLTableCellElement.bnd
+++ /dev/null
@@ -1,46 +0,0 @@
-/* HTML table cell element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLTableCellElement(struct dom_html_element *html_table_cell_element::html_element);
-
-getter HTMLTableCellElement::align();
-setter HTMLTableCellElement::align();
-
-getter HTMLTableCellElement::axis();
-setter HTMLTableCellElement::axis();
-
-getter HTMLTableCellElement::bgColor();
-setter HTMLTableCellElement::bgColor();
-
-getter HTMLTableCellElement::chOff();
-setter HTMLTableCellElement::chOff();
-
-getter HTMLTableCellElement::ch();
-setter HTMLTableCellElement::ch();
-
-getter HTMLTableCellElement::height();
-setter HTMLTableCellElement::height();
-
-getter HTMLTableCellElement::noWrap();
-setter HTMLTableCellElement::noWrap();
-
-getter HTMLTableCellElement::vAlign();
-setter HTMLTableCellElement::vAlign();
-
-getter HTMLTableCellElement::width();
-setter HTMLTableCellElement::width();
-
-getter HTMLTableCellElement::cellIndex();
-
-getter HTMLTableCellElement::colSpan();
-setter HTMLTableCellElement::colSpan();
-
-getter HTMLTableCellElement::rowSpan();
-setter HTMLTableCellElement::rowSpan();
diff --git a/javascript/duktape/HTMLTableColElement.bnd b/javascript/duktape/HTMLTableColElement.bnd
deleted file mode 100644
index ec7a954de..000000000
--- a/javascript/duktape/HTMLTableColElement.bnd
+++ /dev/null
@@ -1,26 +0,0 @@
-/* HTML table col element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLTableColElement(struct dom_html_element *html_table_col_element::html_element);
-
-getter HTMLTableColElement::align();
-setter HTMLTableColElement::align();
-
-getter HTMLTableColElement::chOff();
-setter HTMLTableColElement::chOff();
-
-getter HTMLTableColElement::ch();
-setter HTMLTableColElement::ch();
-
-getter HTMLTableColElement::vAlign();
-setter HTMLTableColElement::vAlign();
-
-getter HTMLTableColElement::width();
-setter HTMLTableColElement::width();
diff --git a/javascript/duktape/HTMLTableElement.bnd b/javascript/duktape/HTMLTableElement.bnd
deleted file mode 100644
index cd6d35769..000000000
--- a/javascript/duktape/HTMLTableElement.bnd
+++ /dev/null
@@ -1,38 +0,0 @@
-/* HTML table element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLTableElement(struct dom_html_element *html_table_element::html_element);
-
-getter HTMLTableElement::align();
-setter HTMLTableElement::align();
-
-getter HTMLTableElement::bgColor();
-setter HTMLTableElement::bgColor();
-
-getter HTMLTableElement::border();
-setter HTMLTableElement::border();
-
-getter HTMLTableElement::cellPadding();
-setter HTMLTableElement::cellPadding();
-
-getter HTMLTableElement::cellSpacing();
-setter HTMLTableElement::cellSpacing();
-
-getter HTMLTableElement::frame();
-setter HTMLTableElement::frame();
-
-getter HTMLTableElement::rules();
-setter HTMLTableElement::rules();
-
-getter HTMLTableElement::summary();
-setter HTMLTableElement::summary();
-
-getter HTMLTableElement::width();
-setter HTMLTableElement::width();
diff --git a/javascript/duktape/HTMLTableRowElement.bnd b/javascript/duktape/HTMLTableRowElement.bnd
deleted file mode 100644
index f736817b0..000000000
--- a/javascript/duktape/HTMLTableRowElement.bnd
+++ /dev/null
@@ -1,30 +0,0 @@
-/* HTML table row element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLTableRowElement(struct dom_html_element *html_table_row_element::html_element);
-
-getter HTMLTableRowElement::align();
-setter HTMLTableRowElement::align();
-
-getter HTMLTableRowElement::bgColor();
-setter HTMLTableRowElement::bgColor();
-
-getter HTMLTableRowElement::chOff();
-setter HTMLTableRowElement::chOff();
-
-getter HTMLTableRowElement::ch();
-setter HTMLTableRowElement::ch();
-
-getter HTMLTableRowElement::vAlign();
-setter HTMLTableRowElement::vAlign();
-
-getter HTMLTableRowElement::rowIndex();
-
-getter HTMLTableRowElement::sectionRowIndex();
diff --git a/javascript/duktape/HTMLTableSectionElement.bnd b/javascript/duktape/HTMLTableSectionElement.bnd
deleted file mode 100644
index 276533b3b..000000000
--- a/javascript/duktape/HTMLTableSectionElement.bnd
+++ /dev/null
@@ -1,23 +0,0 @@
-/* HTML table section element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLTableSectionElement(struct dom_html_element *html_table_section_element::html_element);
-
-getter HTMLTableSectionElement::align();
-setter HTMLTableSectionElement::align();
-
-getter HTMLTableSectionElement::chOff();
-setter HTMLTableSectionElement::chOff();
-
-getter HTMLTableSectionElement::ch();
-setter HTMLTableSectionElement::ch();
-
-getter HTMLTableSectionElement::vAlign();
-setter HTMLTableSectionElement::vAlign();
diff --git a/javascript/duktape/HTMLTextAreaElement.bnd b/javascript/duktape/HTMLTextAreaElement.bnd
deleted file mode 100644
index a0fc1bf7b..000000000
--- a/javascript/duktape/HTMLTextAreaElement.bnd
+++ /dev/null
@@ -1,30 +0,0 @@
-/* HTML text area element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLTextAreaElement(struct dom_html_element *html_text_area_element::html_element);
-
-getter HTMLTextAreaElement::defaultValue();
-setter HTMLTextAreaElement::defaultValue();
-
-getter HTMLTextAreaElement::disabled();
-setter HTMLTextAreaElement::disabled();
-
-getter HTMLTextAreaElement::name();
-setter HTMLTextAreaElement::name();
-
-getter HTMLTextAreaElement::readOnly();
-setter HTMLTextAreaElement::readOnly();
-
-getter HTMLTextAreaElement::type();
-
-getter HTMLTextAreaElement::value();
-setter HTMLTextAreaElement::value();
-
-
diff --git a/javascript/duktape/HTMLTitleElement.bnd b/javascript/duktape/HTMLTitleElement.bnd
deleted file mode 100644
index dee1c0749..000000000
--- a/javascript/duktape/HTMLTitleElement.bnd
+++ /dev/null
@@ -1,14 +0,0 @@
-/* HTML title element binding using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-init HTMLTitleElement(struct dom_html_element *html_title_element::html_element);
-
-getter HTMLTitleElement::text();
-setter HTMLTitleElement::text();
diff --git a/javascript/duktape/Location.bnd b/javascript/duktape/Location.bnd
deleted file mode 100644
index ca7e90509..000000000
--- a/javascript/duktape/Location.bnd
+++ /dev/null
@@ -1,353 +0,0 @@
-/* Location binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- * Copyright 2015 Daniel Silverstone <dsilvers@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-class Location {
- private nsurl *url;
-};
-
-prologue Location()
-%{
-#include "netsurf/browser_window.h"
-%}
-
-init Location(nsurl *url)
-%{
- priv->url = url;
- nsurl_ref(url);
-%}
-
-fini Location()
-%{
- nsurl_unref(priv->url);
-%}
-
-method Location::reload()
-%{
- /* retrieve the private data from the root object (window) */
- duk_push_global_object(ctx);
- duk_get_prop_string(ctx, -1, PRIVATE_MAGIC);
- window_private_t *priv_win = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- if (priv_win->win != NULL) {
- browser_window_reload(priv_win->win, false);
- } else {
- LOG("failed to get browser context");
- }
- return 0;
-%}
-
-method Location::assign()
-%{
- /* retrieve the private data from the root object (window) */
- duk_push_global_object(ctx);
- duk_get_prop_string(ctx, -1, PRIVATE_MAGIC);
- window_private_t *priv_win = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- if (priv_win == NULL || priv_win->win == NULL) {
- LOG("failed to get browser context");
- return 0;
- }
-
- nsurl *joined;
- duk_size_t slen;
- const char *url = duk_safe_to_lstring(ctx, 0, &slen);
-
- nsurl_join(priv->url, url, &joined);
- browser_window_navigate(priv_win->win,
- joined,
- NULL,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
- nsurl_unref(joined);
- return 0;
-%}
-
-method Location::replace()
-%{
- /* retrieve the private data from the root object (window) */
- duk_push_global_object(ctx);
- duk_get_prop_string(ctx, -1, PRIVATE_MAGIC);
- window_private_t *priv_win = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- if (priv_win == NULL || priv_win->win == NULL) {
- LOG("failed to get browser context");
- return 0;
- }
-
- nsurl *joined;
- duk_size_t slen;
- const char *url = duk_safe_to_lstring(ctx, 0, &slen);
-
- nsurl_join(priv->url, url, &joined);
- browser_window_navigate(priv_win->win,
- joined,
- NULL,
- BW_NAVIGATE_NONE,
- NULL,
- NULL,
- NULL);
- nsurl_unref(joined);
- return 0;
-%}
-
-getter Location::href()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_COMPLETE, &url_s, &url_l);
- if (url_s == NULL) {
- return 0;
- }
-
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-setter Location::href()
-%{
- /* retrieve the private data from the root object (window) */
- duk_push_global_object(ctx);
- duk_get_prop_string(ctx, -1, PRIVATE_MAGIC);
- window_private_t *priv_win = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- if (priv_win == NULL || priv_win->win == NULL) {
- LOG("failed to get browser context");
- return 0;
- }
-
- nsurl *joined;
- duk_size_t slen;
- const char *url = duk_safe_to_lstring(ctx, 0, &slen);
-
- nsurl_join(priv->url, url, &joined);
- browser_window_navigate(priv_win->win,
- joined,
- NULL,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
- nsurl_unref(joined);
- return 0;
-%}
-
-getter Location::origin()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_SCHEME | NSURL_HOST | NSURL_PORT, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-getter Location::protocol()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_SCHEME, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
-getter Location::username()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_USERNAME, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
-getter Location::password()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_PASSWORD, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
-getter Location::host()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_HOST, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
-getter Location::hostname()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_HOST, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
-
-getter Location::port()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_PORT, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
-getter Location::pathname()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_PATH, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
-getter Location::search()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_QUERY, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
-getter Location::hash()
-%{
- char *url_s = NULL;
- size_t url_l;
-
- nsurl_get(priv->url, NSURL_FRAGMENT, &url_s, &url_l);
-
- /* if url_s is NULL duk_push_lstring pushes an empty string
- * which is correct for this API
- */
- duk_push_lstring(ctx, url_s, url_l);
-
- if (url_s != NULL) {
- free(url_s);
- }
-
- return 1;
-%}
-
-
diff --git a/javascript/duktape/Makefile b/javascript/duktape/Makefile
deleted file mode 100644
index 89353c340..000000000
--- a/javascript/duktape/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# NetSurf javascript source file inclusion
-#
-# Included by javascript/Makefile
-#
-
-javascript/dukky.c: $(OBJROOT)/duktape/binding.h
-
-BINDINGS := $(wildcard javascript/duktape/*.bnd)
-
-# ensure genbind generates debugging files
-GBFLAGS+=-D
-
-$(OBJROOT)/duktape/binding.h $(OBJROOT)/duktape/Makefile: javascript/duktape/netsurf.bnd $(BINDINGS)
- $(Q)mkdir -p $(OBJROOT)/duktape
- $(VQ)echo " GENBIND: $<"
- $(Q)nsgenbind $(GBFLAGS) -I javascript/WebIDL $< $(OBJROOT)/duktape
- $(VQ)echo " GENBIND: completed"
-
-# create unimplemented report for doxygen
-Docs/UnimplementedJavascript.txt: javascript/duktape/netsurf.bnd $(BINDINGS)
- $(Q)mkdir -p $(OBJROOT)/duktape
- $(VQ)echo "/** \page unimplemented Unimplemented javascript bindings" > $@
- $(VQ)echo "This is a list of all the binding methods, getters and setters without an implementation in a binding." >> $@
- $(VQ)echo "" >> $@
- $(VQ)echo " GENBIND: $<"
- $(Q)nsgenbind $(GBFLAGS) -Wunimplemented -I javascript/WebIDL $< $(OBJROOT)/duktape 2>&1 >/dev/null | grep "Unimplemented" | cut -d' ' -f4- | sort -k 2 | awk '{print $$0"\\n" }' >> $@
- $(VQ)echo "*/" >> $@
-
-ifeq ($(filter $(MAKECMDGOALS),clean test coverage),)
--include $(OBJROOT)/duktape/Makefile
-endif
-
-S_JAVASCRIPT_BINDING:=$(addprefix $(OBJROOT)/duktape/,$(NSGENBIND_SOURCES))
-
-$(S_JAVASCRIPT_BINDING): $(BINDINGS)
-
-S_JAVASCRIPT += content.c duktape/dukky.c duktape/duktape.c
-
-CFLAGS += -DDUK_OPT_HAVE_CUSTOM_H
diff --git a/javascript/duktape/Navigator.bnd b/javascript/duktape/Navigator.bnd
deleted file mode 100644
index b18ca8e83..000000000
--- a/javascript/duktape/Navigator.bnd
+++ /dev/null
@@ -1,87 +0,0 @@
-/* Navigator binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-prologue Navigator()
-%{
-#include "utils/useragent.h"
-%}
-
-method Navigator::taintEnabled()
-%{
- duk_push_boolean(ctx, false);
- return 1;
-%}
-
-getter Navigator::appCodeName()
-%{
- duk_push_string(ctx, "Mozilla");
- return 1;
-%}
-
-getter Navigator::appName()
-%{
- duk_push_string(ctx, "Netscape");
- return 1;
-%}
-
-getter Navigator::appVersion()
-%{
- duk_push_string(ctx, "3.4");
- return 1;
-%}
-
-getter Navigator::platform()
-%{
- duk_push_string(ctx, NULL);
- return 1;
-%}
-
-getter Navigator::product()
-%{
- duk_push_string(ctx, "Gecko");
- return 1;
-%}
-
-getter Navigator::productSub()
-%{
- duk_push_string(ctx, "20100101");
- return 1;
-%}
-
-getter Navigator::vendor()
-%{
- duk_push_string(ctx, NULL);
- return 1;
-%}
-
-getter Navigator::vendorSub()
-%{
- duk_push_string(ctx, NULL);
- return 1;
-%}
-
-getter Navigator::cookieEnabled()
-%{
- duk_push_boolean(ctx, false);
- return 1;
-%}
-
-/* indicate there is no plugin for java installed */
-getter Navigator::javaEnabled()
-%{
- duk_push_boolean(ctx, false);
- return 1;
-%}
-
-getter Navigator::userAgent()
-%{
- duk_push_string(ctx, user_agent_string());
- return 1;
-%}
diff --git a/javascript/duktape/Node.bnd b/javascript/duktape/Node.bnd
deleted file mode 100644
index f237c876a..000000000
--- a/javascript/duktape/Node.bnd
+++ /dev/null
@@ -1,479 +0,0 @@
-/* Node binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-class Node {
- private dom_node *node;
-};
-
-init Node(struct dom_node *node)
-%{
- priv->node = node;
- dom_node_ref(node);
-%}
-
-fini Node()
-%{
- dom_node_unref(priv->node);
-%}
-
-getter Node::nodeType()
-%{
- dom_exception exc;
- dom_node_type ntype;
- exc = dom_node_get_node_type(priv->node, &ntype);
- if (exc != DOM_NO_ERR) return 0;
- duk_push_uint(ctx, (duk_uint_t)ntype);
- return 1;
-%}
-
-getter Node::nodeName()
-%{
- dom_exception exc;
- dom_string *str = NULL;
- exc = dom_node_get_node_name(priv->node, &str);
- if (exc != DOM_NO_ERR) return 0;
- duk_push_lstring(ctx, dom_string_data(str), dom_string_length(str));
- dom_string_unref(str);
- return 1;
-%}
-
-getter Node::baseURI()
-%{
- dom_exception exc;
- dom_string *base = NULL;
- exc = dom_node_get_base(priv->node, &base);
- if (exc != DOM_NO_ERR) return 0;
- assert(base != NULL);
- duk_push_lstring(ctx, dom_string_data(base), dom_string_length(base));
- dom_string_unref(base);
- return 1;
-%}
-
-getter Node::ownerDocument()
-%{
- dom_exception exc;
- dom_node *doc;
- exc = dom_node_get_owner_document(priv->node, &doc);
- if (exc != DOM_NO_ERR) return 0;
- if (doc == NULL) return 0;
- dukky_push_node(ctx, doc);
- dom_node_unref(doc);
- return 1;
-%}
-
-getter Node::parentNode()
-%{
- dom_exception exc;
- dom_node *pnode = NULL;
- exc = dom_node_get_parent_node(priv->node, &pnode);
- if (exc != DOM_NO_ERR) return 0;
- dukky_push_node(ctx, pnode);
- dom_node_unref(pnode);
- return 1;
-%}
-
-getter Node::parentElement()
-%{
- dom_exception exc;
- dom_node *pnode = NULL;
- dom_node_type ntype = DOM_NODE_TYPE_COUNT + 1;
- exc = dom_node_get_parent_node(priv->node, &pnode);
- if (exc != DOM_NO_ERR) return 0;
- if (pnode != NULL) {
- exc = dom_node_get_node_type(pnode, &ntype);
- if (exc != DOM_NO_ERR) { dom_node_unref(pnode); return 0; }
- }
- dukky_push_node(ctx, (ntype == DOM_ELEMENT_NODE) ? pnode : NULL);
- dom_node_unref(pnode);
- return 1;
-%}
-
-method Node::hasChildNodes()
-%{
- dom_exception exc;
- bool res;
- exc = dom_node_has_child_nodes(priv->node, &res);
- if (exc != DOM_NO_ERR) return 0;
- duk_push_boolean(ctx, res);
- return 1;
-%}
-
-getter Node::childNodes()
-%{
- dom_exception exc;
- dom_nodelist *nlist = NULL;
- duk_set_top(ctx, 0);
- duk_push_this(ctx);
- duk_get_prop_string(ctx, 0, MAGIC(childNodes));
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- exc = dom_node_get_child_nodes(priv->node, &nlist);
- if (exc != DOM_NO_ERR) return 0;
- duk_push_pointer(ctx, nlist);
- if (dukky_create_object(ctx, PROTO_NAME(NODELIST), 1) != DUK_EXEC_SUCCESS) {
- dom_nodelist_unref(nlist);
- return 0;
- }
- dom_nodelist_unref(nlist);
- duk_dup(ctx, -1);
- duk_put_prop_string(ctx, 0, MAGIC(childNodes));
- }
- return 1;
-%}
-
-getter Node::firstChild()
-%{
- dom_exception exc;
- dom_node *n;
- exc = dom_node_get_first_child(priv->node, &n);
- if (exc != DOM_NO_ERR) return 0;
- if (dukky_push_node(ctx, n) == false) {
- dom_node_unref(n);
- return 0;
- }
- dom_node_unref(n);
- return 1;
-%}
-
-getter Node::lastChild()
-%{
- dom_exception exc;
- dom_node *n;
- exc = dom_node_get_last_child(priv->node, &n);
- if (exc != DOM_NO_ERR) return 0;
- if (dukky_push_node(ctx, n) == false) {
- dom_node_unref(n);
- return 0;
- }
- dom_node_unref(n);
- return 1;
-%}
-
-getter Node::previousSibling()
-%{
- dom_exception exc;
- dom_node *n;
- exc = dom_node_get_previous_sibling(priv->node, &n);
- if (exc != DOM_NO_ERR) return 0;
- if (dukky_push_node(ctx, n) == false) {
- dom_node_unref(n);
- return 0;
- }
- dom_node_unref(n);
- return 1;
-%}
-
-getter Node::nextSibling()
-%{
- dom_exception exc;
- dom_node *n;
- exc = dom_node_get_next_sibling(priv->node, &n);
- if (exc != DOM_NO_ERR) return 0;
- if (dukky_push_node(ctx, n) == false) {
- dom_node_unref(n);
- return 0;
- }
- dom_node_unref(n);
- return 1;
-%}
-
-getter Node::nodeValue()
-%{
- dom_exception exc;
- dom_string *content;
-
- exc = dom_node_get_node_value(priv->node, &content);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- if (content != NULL) {
- duk_push_lstring(ctx, dom_string_data(content), dom_string_length(content));
- dom_string_unref(content);
- return 1;
- }
- return 0;
-%}
-
-setter Node::nodeValue()
-%{
- dom_exception exc;
- dom_string *content;
- duk_size_t slen;
- const char *s = duk_safe_to_lstring(ctx, 0, &slen);
- exc = dom_string_create((const uint8_t *)s, slen, &content);
- if (exc != DOM_NO_ERR) return 0;
- exc = dom_node_set_node_value(priv->node, content);
- dom_string_unref(content);
- return 0;
-%}
-
-getter Node::textContent()
-%{
- dom_exception exc;
- dom_string *content;
-
- exc = dom_node_get_text_content(priv->node, &content);
- if (exc != DOM_NO_ERR) {
- return 0;
- }
-
- if (content != NULL) {
- duk_push_lstring(ctx, dom_string_data(content), dom_string_length(content));
- dom_string_unref(content);
- return 1;
- }
- return 0;
-%}
-
-setter Node::textContent()
-%{
- dom_exception exc;
- dom_string *content;
- duk_size_t slen;
- const char *s = duk_safe_to_lstring(ctx, 0, &slen);
- exc = dom_string_create((const uint8_t *)s, slen, &content);
- if (exc != DOM_NO_ERR) return 0;
- exc = dom_node_set_text_content(priv->node, content);
- dom_string_unref(content);
- return 0;
-%}
-
-method Node::normalize()
-%{
- dom_exception exc;
- exc = dom_node_normalize(priv->node);
- if (exc != DOM_NO_ERR) return 0;
- return 0;
-%}
-
-method Node::cloneNode()
-%{
- dom_exception exc;
- bool deep;
- dom_node *clone;
-
- deep = duk_to_boolean(ctx, 0);
-
- exc = dom_node_clone_node(priv->node, deep, &clone);
- if (exc != DOM_NO_ERR) return 0;
- duk_set_top(ctx, 0);
- dukky_push_node(ctx, clone);
- dom_node_unref(clone);
- return 1;
-%}
-
-method Node::isEqualNode()
-%{
- dom_exception exc;
- bool result;
-
- if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0;
-
- duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
- node_private_t *other = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- exc = dom_node_is_equal(priv->node, other->node, &result);
- if (exc != DOM_NO_ERR) return 0;
- duk_push_boolean(ctx, result);
- return 1;
-%}
-
-method Node::compareDocumentPosition()
-%{
- dom_exception exc;
- uint16_t ret;
-
- if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0;
-
- duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
- node_private_t *other = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- exc = dom_node_compare_document_position(priv->node, other->node,
- &ret);
-
- if (exc != DOM_NO_ERR) return 0;
-
- duk_push_uint(ctx, ret);
-
- return 1;
-%}
-
-method Node::contains()
-%{
- dom_exception exc;
- uint16_t ret;
-
- if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0;
-
- duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
- node_private_t *other = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- /* Note that inclusive descendant says *IS* or *CONTAINED_BY* */
- if (priv->node == other->node) {
- duk_push_boolean(ctx, true);
- return 1;
- }
-
- exc = dom_node_compare_document_position(priv->node, other->node,
- &ret);
-
- if (exc != DOM_NO_ERR) return 0;
-
- duk_push_boolean(ctx, ret == DOM_DOCUMENT_POSITION_CONTAINED_BY);
-
- return 1;
-%}
-
-method Node::lookupPrefix()
-%{
- dom_exception exc;
- dom_string *ns, *pfx;
- duk_size_t size;
- const char *s = duk_safe_to_lstring(ctx, 0, &size);
- exc = dom_string_create((const uint8_t *)s, size, &ns);
- if (exc != DOM_NO_ERR) return 0;
- exc = dom_node_lookup_prefix(priv->node, ns, &pfx);
- dom_string_unref(ns);
- if (exc != DOM_NO_ERR) return 0;
- if (pfx == NULL) return 0;
- duk_push_lstring(ctx, dom_string_data(pfx), dom_string_length(pfx));
- dom_string_unref(pfx);
- return 0;
-%}
-
-method Node::lookupNamespaceURI()
-%{
- dom_exception exc;
- dom_string *ns, *pfx;
- duk_size_t size;
- const char *s = duk_safe_to_lstring(ctx, 0, &size);
- exc = dom_string_create((const uint8_t *)s, size, &pfx);
- if (exc != DOM_NO_ERR) return 0;
- exc = dom_node_lookup_namespace(priv->node, pfx, &ns);
- dom_string_unref(pfx);
- if (exc != DOM_NO_ERR) return 0;
- if (ns == NULL) return 0;
- duk_push_lstring(ctx, dom_string_data(ns), dom_string_length(ns));
- dom_string_unref(ns);
- return 0;
-%}
-
-
-method Node::isDefaultNamespace()
-%{
- dom_exception exc;
- dom_string *ns;
- duk_size_t size;
- const char *s = duk_safe_to_lstring(ctx, 0, &size);
- bool ret;
- exc = dom_string_create((const uint8_t *)s, size, &ns);
- if (exc != DOM_NO_ERR) return 0;
- exc = dom_node_is_default_namespace(priv->node, ns, &ret);
- dom_string_unref(ns);
- if (exc != DOM_NO_ERR) return 0;
- duk_push_boolean(ctx, ret);
- return 1;
-%}
-
-method Node::insertBefore()
-%{
- if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0;
-
- duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
- node_private_t *other = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- dom_node *before = NULL;
-
- if (duk_get_top(ctx) == 2) {
- if (!dukky_instanceof(ctx, 1, PROTO_NAME(NODE))) return 0;
- duk_get_prop_string(ctx, 1, PRIVATE_MAGIC);
- node_private_t *another = duk_get_pointer(ctx, -1);
- before = another->node;
- duk_pop(ctx);
- }
-
- dom_exception err;
- dom_node *spare;
-
- err = dom_node_insert_before(priv->node, other->node, before, &spare);
- if (err != DOM_NO_ERR) return 0;
- dukky_push_node(ctx, spare);
- dom_node_unref(spare);
-
- return 1;
-%}
-
-method Node::appendChild()
-%{
- if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0;
-
- duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
- node_private_t *other = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- dom_exception err;
- dom_node *spare;
-
- err = dom_node_append_child(priv->node, other->node, &spare);
- if (err != DOM_NO_ERR) return 0;
- dukky_push_node(ctx, spare);
- dom_node_unref(spare);
-
- return 1;
-%}
-
-method Node::replaceChild()
-%{
- if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0;
-
- duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
- node_private_t *other = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- if (!dukky_instanceof(ctx, 1, PROTO_NAME(NODE))) return 0;
-
- duk_get_prop_string(ctx, 1, PRIVATE_MAGIC);
- node_private_t *old = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- dom_exception err;
- dom_node *spare;
-
- err = dom_node_replace_child(priv->node, other->node, old->node, &spare);
- if (err != DOM_NO_ERR) return 0;
- dukky_push_node(ctx, spare);
- dom_node_unref(spare);
-
- return 1;
-%}
-
-method Node::removeChild()
-%{
- if (!dukky_instanceof(ctx, 0, PROTO_NAME(NODE))) return 0;
-
- duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
- node_private_t *other = duk_get_pointer(ctx, -1);
- duk_pop(ctx);
-
- dom_exception err;
- dom_node *spare;
-
- err = dom_node_remove_child(priv->node, other->node, &spare);
- if (err != DOM_NO_ERR) return 0;
- dukky_push_node(ctx, spare);
- dom_node_unref(spare);
-
- return 1;
-%}
diff --git a/javascript/duktape/NodeList.bnd b/javascript/duktape/NodeList.bnd
deleted file mode 100644
index 7ddf56d15..000000000
--- a/javascript/duktape/NodeList.bnd
+++ /dev/null
@@ -1,54 +0,0 @@
-/* NodeList binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-class NodeList {
- private struct dom_nodelist *nodes;
-};
-
-init NodeList(struct dom_nodelist *nodes)
-%{
- priv->nodes = nodes;
- dom_nodelist_ref(nodes);
-%}
-
-fini NodeList()
-%{
- dom_nodelist_unref(priv->nodes);
-%}
-
-getter NodeList::length()
-%{
- dom_exception err;
- uint32_t len;
-
- err = dom_nodelist_get_length(priv->nodes, &len);
-
- if (err != DOM_NO_ERR) return 0; /* coerced to undefined */
-
- duk_push_uint(ctx, (duk_uint_t)len);
-
- return 1;
-%}
-
-method NodeList::item()
-%{
- unsigned long i = duk_to_uint(ctx, 0);
- dom_exception err;
- dom_node *node;
-
- err = dom_nodelist_item(priv->nodes, i, &node);
-
- if (err != DOM_NO_ERR) return 0; /* coerced to undefied */
-
- dukky_push_node(ctx, node);
- dom_node_unref(node);
-
- return 1;
-%}
diff --git a/javascript/duktape/Window.bnd b/javascript/duktape/Window.bnd
deleted file mode 100644
index 489587899..000000000
--- a/javascript/duktape/Window.bnd
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Window binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-class Window {
- private struct browser_window * win;
- private struct html_content * htmlc;
- prologue %{
-#include "utils/nsurl.h"
-#include "netsurf/browser_window.h"
-#include "content/hlcache.h"
-#include "render/html.h"
-#include "render/html_internal.h"
-%};
-};
-
-init Window(struct browser_window *win, struct html_content *htmlc)
-%{
- /* element window */
- priv->win = win;
- priv->htmlc = htmlc;
- LOG("win=%p htmlc=%p", priv->win, priv->htmlc);
-
- LOG("URL is %s", nsurl_access(browser_window_get_url(priv->win)));
-%}
-
-prototype Window()
-%{
-#define EXPOSE(v) \
- duk_get_global_string(ctx, #v); \
- duk_put_prop_string(ctx, 0, #v)
- /* steal undefined */
- EXPOSE(undefined);
- EXPOSE(eval);
- EXPOSE(Object);
- EXPOSE(parseInt);
- EXPOSE(parseFloat);
- EXPOSE(Array);
- EXPOSE(Date);
- EXPOSE(RegExp);
- EXPOSE(Math);
- EXPOSE(Function);
- EXPOSE(Proxy);
- EXPOSE(String);
-#undef EXPOSE
-%}
-
-getter Window::document()
-%{
- JS_LOG("priv=%p", priv);
- dom_document *doc = priv->htmlc->document;
- dukky_push_node(ctx, (struct dom_node *)doc);
- return 1;
-%}
-
-getter Window::window()
-%{
- duk_push_this(ctx);
- return 1;
-%}
-
-getter Window::console()
-%{
- duk_push_this(ctx);
- duk_get_prop_string(ctx, -1, MAGIC(Console));
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- if (dukky_create_object(ctx, PROTO_NAME(CONSOLE), 0) != DUK_EXEC_SUCCESS) {
- duk_error(ctx, DUK_ERR_ERROR, "Unable to create console object");
- return 0;
- }
- duk_dup(ctx, -1);
- duk_put_prop_string(ctx, -3, MAGIC(Console));
- }
- return 1;
-%}
-
-getter Window::location()
-%{
- duk_push_this(ctx);
- duk_get_prop_string(ctx, -1, MAGIC(Location));
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
-
- duk_push_pointer(ctx, llcache_handle_get_url(priv->htmlc->base.llcache));
-
- if (dukky_create_object(ctx, PROTO_NAME(LOCATION), 1) != DUK_EXEC_SUCCESS) {
- duk_error(ctx, DUK_ERR_ERROR, "Unable to create location object");
- return 0;
- }
- duk_dup(ctx, -1);
- duk_put_prop_string(ctx, -3, MAGIC(Location));
- }
- return 1;
-%}
-
-getter Window::navigator()
-%{
- duk_push_this(ctx);
- duk_get_prop_string(ctx, -1, MAGIC(Navigator));
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
-
- if (dukky_create_object(ctx,
- PROTO_NAME(NAVIGATOR),
- 0) != DUK_EXEC_SUCCESS) {
- duk_error(ctx,
- DUK_ERR_ERROR,
- "Unable to create navigator object");
- return 0;
- }
- duk_dup(ctx, -1);
- duk_put_prop_string(ctx, -3, MAGIC(Navigator));
- }
- return 1;
-%}
-
-getter Window::name()
-%{
- const char *name;
- browser_window_get_name(priv->win, &name);
- duk_push_string(ctx, name);
- return 1;
-%}
-
-setter Window::name()
-%{
- const char *name;
- name = duk_to_string(ctx, -1);
- browser_window_set_name(priv->win, name);
- return 0;
-%}
-
-method Window::alert()
-%{
- duk_size_t msg_len;
- const char *msg = duk_safe_to_lstring(ctx, 0, &msg_len);
- LOG("JS ALERT: %*s", (int)msg_len, msg);
- return 0;
-%}
diff --git a/javascript/duktape/duk_config.h b/javascript/duktape/duk_config.h
deleted file mode 100644
index a3da70a3f..000000000
--- a/javascript/duktape/duk_config.h
+++ /dev/null
@@ -1,3753 +0,0 @@
-/*
- * duk_config.h configuration header generated by genconfig.py.
- *
- * Git commit: 83d557704ee63f68ab40b6fcb00995c9b3d6777c
- * Git describe: v1.5.0
- * Git branch: master
- *
- * Supported platforms:
- * - Mac OSX, iPhone, Darwin
- * - OpenBSD
- * - Generic BSD
- * - Atari ST TOS
- * - AmigaOS
- * - Windows
- * - Flashplayer (Crossbridge)
- * - QNX
- * - TI-Nspire
- * - Emscripten
- * - Linux
- * - Solaris
- * - Generic POSIX
- * - Cygwin
- * - Generic UNIX
- * - Generic fallback
- *
- * Supported architectures:
- * - x86
- * - x64
- * - x32
- * - ARM 32-bit
- * - ARM 64-bit
- * - MIPS 32-bit
- * - MIPS 64-bit
- * - PowerPC 32-bit
- * - PowerPC 64-bit
- * - SPARC 32-bit
- * - SPARC 64-bit
- * - SuperH
- * - Motorola 68k
- * - Emscripten
- * - Generic
- *
- * Supported compilers:
- * - Clang
- * - GCC
- * - MSVC
- * - Emscripten
- * - TinyC
- * - VBCC
- * - Bruce's C compiler
- * - Generic
- *
- */
-
-#if !defined(DUK_CONFIG_H_INCLUDED)
-#define DUK_CONFIG_H_INCLUDED
-
-/*
- * Intermediate helper defines
- */
-
-/* DLL build detection */
-#if defined(DUK_OPT_DLL_BUILD)
-#define DUK_F_DLL_BUILD
-#elif defined(DUK_OPT_NO_DLL_BUILD)
-#undef DUK_F_DLL_BUILD
-#else
-/* not configured for DLL build */
-#undef DUK_F_DLL_BUILD
-#endif
-
-/* Apple OSX, iOS */
-#if defined(__APPLE__)
-#define DUK_F_APPLE
-#endif
-
-/* OpenBSD */
-#if defined(__OpenBSD__) || defined(__OpenBSD)
-#define DUK_F_OPENBSD
-#endif
-
-/* NetBSD */
-#if defined(__NetBSD__) || defined(__NetBSD)
-#define DUK_F_NETBSD
-#endif
-
-/* FreeBSD */
-#if defined(__FreeBSD__) || defined(__FreeBSD)
-#define DUK_F_FREEBSD
-#endif
-
-/* BSD variant */
-#if defined(DUK_F_FREEBSD) || defined(DUK_F_NETBSD) || defined(DUK_F_OPENBSD) || \
- defined(__bsdi__) || defined(__DragonFly__)
-#define DUK_F_BSD
-#endif
-
-/* Atari ST TOS. __TOS__ defined by PureC. No platform define in VBCC
- * apparently, so to use with VBCC user must define __TOS__ manually.
- */
-#if defined(__TOS__)
-#define DUK_F_TOS
-#endif
-
-/* Motorola 68K. Not defined by VBCC, so user must define one of these
- * manually when using VBCC.
- */
-#if defined(__m68k__) || defined(M68000) || defined(__MC68K__)
-#define DUK_F_M68K
-#endif
-
-/* AmigaOS. Neither AMIGA nor __amigaos__ is defined on VBCC, so user must
- * define 'AMIGA' manually when using VBCC.
- */
-#if defined(AMIGA) || defined(__amigaos__)
-#define DUK_F_AMIGAOS
-#endif
-
-/* PowerPC */
-#if defined(__powerpc) || defined(__powerpc__) || defined(__PPC__)
-#define DUK_F_PPC
-#if defined(__PPC64__) || defined(__LP64__) || defined(_LP64)
-#define DUK_F_PPC64
-#else
-#define DUK_F_PPC32
-#endif
-#endif
-
-/* Windows, both 32-bit and 64-bit */
-#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) || \
- defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
-#define DUK_F_WINDOWS
-#if defined(_WIN64) || defined(WIN64)
-#define DUK_F_WIN64
-#else
-#define DUK_F_WIN32
-#endif
-#endif
-
-/* Flash player (e.g. Crossbridge) */
-#if defined(__FLASHPLAYER__)
-#define DUK_F_FLASHPLAYER
-#endif
-
-/* QNX */
-#if defined(__QNX__)
-#define DUK_F_QNX
-#endif
-
-/* TI-Nspire (using Ndless) */
-#if defined(_TINSPIRE)
-#define DUK_F_TINSPIRE
-#endif
-
-/* Emscripten (provided explicitly by user), improve if possible */
-#if defined(EMSCRIPTEN)
-#define DUK_F_EMSCRIPTEN
-#endif
-
-/* BCC (Bruce's C compiler): this is a "torture target" for compilation */
-#if defined(__BCC__) || defined(__BCC_VERSION__)
-#define DUK_F_BCC
-#endif
-
-/* Linux */
-#if defined(__linux) || defined(__linux__) || defined(linux)
-#define DUK_F_LINUX
-#endif
-
-/* illumos / Solaris */
-#if defined(__sun) && defined(__SVR4)
-#define DUK_F_SUN
-#endif
-
-/* POSIX */
-#if defined(__posix)
-#define DUK_F_POSIX
-#endif
-
-/* Cygwin */
-#if defined(__CYGWIN__)
-#define DUK_F_CYGWIN
-#endif
-
-/* Generic Unix (includes Cygwin) */
-#if defined(__unix) || defined(__unix__) || defined(unix) || \
- defined(DUK_F_LINUX) || defined(DUK_F_BSD)
-#define DUK_F_UNIX
-#endif
-
-/* stdint.h not available */
-#if defined(DUK_F_WINDOWS) && defined(_MSC_VER)
-#if (_MSC_VER < 1700)
-/* VS2012+ has stdint.h, < VS2012 does not (but it's available for download). */
-#define DUK_F_NO_STDINT_H
-#endif
-#endif
-#if !defined(DUK_F_NO_STDINT_H) && (defined(DUK_F_TOS) || defined(DUK_F_BCC))
-#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/
- */
-#if defined(__amd64__) || defined(__amd64) || \
- defined(__x86_64__) || defined(__x86_64) || \
- defined(_M_X64) || defined(_M_AMD64)
-#if defined(__ILP32__) || defined(_ILP32)
-#define DUK_F_X32
-#else
-#define DUK_F_X64
-#endif
-#elif defined(i386) || defined(__i386) || defined(__i386__) || \
- defined(__i486__) || defined(__i586__) || defined(__i686__) || \
- defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \
- defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__)
-#if defined(__LP64__) || defined(_LP64)
-/* This should not really happen, but would indicate x64. */
-#define DUK_F_X64
-#else
-#define DUK_F_X86
-#endif
-#endif
-
-/* ARM */
-#if defined(__arm__) || defined(__thumb__) || defined(_ARM) || defined(_M_ARM)
-#define DUK_F_ARM
-#if defined(__LP64__) || defined(_LP64) || defined(__arm64) || defined(__arm64__)
-#define DUK_F_ARM64
-#else
-#define DUK_F_ARM32
-#endif
-#endif
-
-/* MIPS. Related defines: __MIPSEB__, __MIPSEL__, __mips_isa_rev, __LP64__ */
-#if defined(__mips__) || defined(mips) || defined(_MIPS_ISA) || \
- defined(_R3000) || defined(_R4000) || defined(_R5900) || \
- defined(_MIPS_ISA_MIPS1) || defined(_MIPS_ISA_MIPS2) || \
- defined(_MIPS_ISA_MIPS3) || defined(_MIPS_ISA_MIPS4) || \
- defined(__mips) || defined(__MIPS__)
-#define DUK_F_MIPS
-#if defined(__LP64__) || defined(_LP64) || defined(__mips64) || \
- defined(__mips64__) || defined(__mips_n64)
-#define DUK_F_MIPS64
-#else
-#define DUK_F_MIPS32
-#endif
-#endif
-
-/* SPARC */
-#if defined(sparc) || defined(__sparc) || defined(__sparc__)
-#define DUK_F_SPARC
-#if defined(__LP64__) || defined(_LP64)
-#define DUK_F_SPARC64
-#else
-#define DUK_F_SPARC32
-#endif
-#endif
-
-/* SuperH */
-#if defined(__sh__) || \
- defined(__sh1__) || defined(__SH1__) || \
- defined(__sh2__) || defined(__SH2__) || \
- defined(__sh3__) || defined(__SH3__) || \
- defined(__sh4__) || defined(__SH4__) || \
- defined(__sh5__) || defined(__SH5__)
-#define DUK_F_SUPERH
-#endif
-
-/* Clang */
-#if defined(__clang__)
-#define DUK_F_CLANG
-#endif
-
-/* C99 or above */
-#undef DUK_F_C99
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
-#define DUK_F_C99
-#endif
-
-/* C++11 or above */
-#undef DUK_F_CPP11
-#if defined(__cplusplus) && (__cplusplus >= 201103L)
-#define DUK_F_CPP11
-#endif
-
-/* GCC. Clang also defines __GNUC__ so don't detect GCC if using Clang. */
-#if defined(__GNUC__) && !defined(__clang__) && !defined(DUK_F_CLANG)
-#define DUK_F_GCC
-#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
-/* Convenience, e.g. gcc 4.5.1 == 40501; http://stackoverflow.com/questions/6031819/emulating-gccs-builtin-unreachable */
-#define DUK_F_GCC_VERSION (__GNUC__ * 10000L + __GNUC_MINOR__ * 100L + __GNUC_PATCHLEVEL__)
-#else
-#error cannot figure out gcc version
-#endif
-#endif
-
-/* MinGW. Also GCC flags (DUK_F_GCC) are enabled now. */
-#if defined(__MINGW32__) || defined(__MINGW64__)
-#define DUK_F_MINGW
-#endif
-
-/* MSVC */
-#if defined(_MSC_VER)
-/* MSVC preprocessor defines: http://msdn.microsoft.com/en-us/library/b0084kay.aspx
- * _MSC_FULL_VER includes the build number, but it has at least two formats, see e.g.
- * BOOST_MSVC_FULL_VER in http://www.boost.org/doc/libs/1_52_0/boost/config/compiler/visualc.hpp
- */
-#define DUK_F_MSVC
-#if defined(_MSC_FULL_VER)
-#if (_MSC_FULL_VER > 100000000)
-#define DUK_F_MSVC_FULL_VER _MSC_FULL_VER
-#else
-#define DUK_F_MSCV_FULL_VER (_MSC_FULL_VER * 10)
-#endif
-#endif
-#endif /* _MSC_VER */
-
-/* TinyC */
-#if defined(__TINYC__)
-/* http://bellard.org/tcc/tcc-doc.html#SEC9 */
-#define DUK_F_TINYC
-#endif
-
-/* VBCC */
-#if defined(__VBCC__)
-#define DUK_F_VBCC
-#endif
-
-/* Atari Mint */
-#if defined(__MINT__)
-#define DUK_F_MINT
-#endif
-
-/*
- * Platform autodetection
- */
-
-/* Workaround for older C++ compilers before including <inttypes.h>,
- * see e.g.: https://sourceware.org/bugzilla/show_bug.cgi?id=15366
- */
-#if defined(__cplusplus) && !defined(__STDC_LIMIT_MACROS)
-#define __STDC_LIMIT_MACROS
-#endif
-#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS)
-#define __STDC_CONSTANT_MACROS
-#endif
-
-#if defined(DUK_F_APPLE)
-/* --- Mac OSX, iPhone, Darwin --- */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <TargetConditionals.h>
-#include <architecture/byte_order.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-/* http://stackoverflow.com/questions/5919996/how-to-detect-reliably-mac-os-x-ios-linux-windows-in-c-preprocessor */
-#if TARGET_IPHONE_SIMULATOR
-#define DUK_USE_OS_STRING "iphone-sim"
-#elif TARGET_OS_IPHONE
-#define DUK_USE_OS_STRING "iphone"
-#elif TARGET_OS_MAC
-#define DUK_USE_OS_STRING "osx"
-#else
-#define DUK_USE_OS_STRING "osx-unknown"
-#endif
-
-/* Use _setjmp() on Apple by default, see GH-55. */
-#define DUK_JMPBUF_TYPE jmp_buf
-#define DUK_SETJMP(jb) _setjmp((jb))
-#define DUK_LONGJMP(jb) _longjmp((jb), 1)
-#elif defined(DUK_F_OPENBSD)
-/* --- OpenBSD --- */
-/* http://www.monkey.org/openbsd/archive/ports/0401/msg00089.html */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <sys/types.h>
-#include <sys/endian.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_USE_OS_STRING "openbsd"
-#elif defined(DUK_F_BSD)
-/* --- Generic BSD --- */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <sys/types.h>
-#include <sys/endian.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_USE_OS_STRING "bsd"
-#elif defined(DUK_F_TOS)
-/* --- Atari ST TOS --- */
-#define DUK_USE_DATE_NOW_TIME
-#define DUK_USE_DATE_TZO_GMTIME
-/* no parsing (not an error) */
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <time.h>
-
-#define DUK_USE_OS_STRING "tos"
-
-/* TOS on M68K is always big endian. */
-#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_M68K)
-#define DUK_USE_BYTEORDER 3
-#endif
-#elif defined(DUK_F_AMIGAOS)
-/* --- AmigaOS --- */
-#if defined(DUK_F_M68K)
-/* AmigaOS on M68k */
-#define DUK_USE_DATE_NOW_TIME
-#define DUK_USE_DATE_TZO_GMTIME
-/* no parsing (not an error) */
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <time.h>
-#elif defined(DUK_F_PPC)
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <time.h>
-#ifndef UINTPTR_MAX
-#define UINTPTR_MAX UINT_MAX
-#endif
-#else
-#error AmigaOS but not M68K/PPC, not supported now
-#endif
-
-#define DUK_USE_OS_STRING "amigaos"
-
-/* AmigaOS on M68K or PPC is always big endian. */
-#if !defined(DUK_USE_BYTEORDER) && (defined(DUK_F_M68K) || defined(DUK_F_PPC))
-#define DUK_USE_BYTEORDER 3
-#endif
-#elif defined(DUK_F_WINDOWS)
-/* --- Windows --- */
-/* Initial fix: disable secure CRT related warnings when compiling Duktape
- * itself (must be defined before including Windows headers). Don't define
- * for user code including duktape.h.
- */
-#if defined(DUK_COMPILING_DUKTAPE) && !defined(_CRT_SECURE_NO_WARNINGS)
-#define _CRT_SECURE_NO_WARNINGS
-#endif
-
-/* Windows 32-bit and 64-bit are currently the same. */
-/* MSVC does not have sys/param.h */
-#define DUK_USE_DATE_NOW_WINDOWS
-#define DUK_USE_DATE_TZO_WINDOWS
-/* Note: PRS and FMT are intentionally left undefined for now. This means
- * there is no platform specific date parsing/formatting but there is still
- * the ISO 8601 standard format.
- */
-#if defined(DUK_COMPILING_DUKTAPE)
-/* Only include when compiling Duktape to avoid polluting application build
- * with a lot of unnecessary defines.
- */
-#include <windows.h>
-#endif
-
-#define DUK_USE_OS_STRING "windows"
-
-/* On Windows, assume we're little endian. Even Itanium which has a
- * configurable endianness runs little endian in Windows.
- */
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 1
-#endif
-#elif defined(DUK_F_FLASHPLAYER)
-/* --- Flashplayer (Crossbridge) --- */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <endian.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_USE_OS_STRING "flashplayer"
-
-#if !defined(DUK_USE_BYTEORDER) && defined(DUK_F_FLASHPLAYER)
-#define DUK_USE_BYTEORDER 1
-#endif
-#elif defined(DUK_F_QNX)
-/* --- QNX --- */
-#if defined(DUK_F_QNX) && defined(DUK_COMPILING_DUKTAPE)
-/* See: /opt/qnx650/target/qnx6/usr/include/sys/platform.h */
-#define _XOPEN_SOURCE 600
-#define _POSIX_C_SOURCE 200112L
-#endif
-
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_USE_OS_STRING "qnx"
-#elif defined(DUK_F_TINSPIRE)
-/* --- TI-Nspire --- */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_USE_OS_STRING "tinspire"
-#elif defined(DUK_F_EMSCRIPTEN)
-/* --- Emscripten --- */
-#if defined(DUK_COMPILING_DUKTAPE)
-#ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 200809L
-#endif
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* e.g. getdate_r */
-#endif
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE /* e.g. strptime */
-#endif
-#endif /* DUK_COMPILING_DUKTAPE */
-
-#include <sys/types.h>
-#if defined(DUK_F_BCC)
-/* no endian.h */
-#else
-#include <endian.h>
-#endif /* DUK_F_BCC */
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-#include <stdint.h>
-
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-
-#define DUK_USE_OS_STRING "emscripten"
-#elif defined(DUK_F_LINUX)
-/* --- Linux --- */
-#if defined(DUK_COMPILING_DUKTAPE)
-#ifndef _POSIX_C_SOURCE
-#define _POSIX_C_SOURCE 200809L
-#endif
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE /* e.g. getdate_r */
-#endif
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE /* e.g. strptime */
-#endif
-#endif /* DUK_COMPILING_DUKTAPE */
-
-#include <sys/types.h>
-#if defined(DUK_F_BCC)
-/* no endian.h or stdint.h */
-#else
-#include <endian.h>
-#include <stdint.h>
-#endif /* DUK_F_BCC */
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-
-#define DUK_USE_OS_STRING "linux"
-#elif defined(DUK_F_SUN)
-/* --- Solaris --- */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-
-#include <sys/types.h>
-#include <ast/endian.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_USE_OS_STRING "solaris"
-#elif defined(DUK_F_POSIX)
-/* --- Generic POSIX --- */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <sys/types.h>
-#include <endian.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_USE_OS_STRING "posix"
-#elif defined(DUK_F_CYGWIN)
-/* --- Cygwin --- */
-/* don't use strptime() for now */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <sys/types.h>
-#include <endian.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <time.h>
-
-#define DUK_JMPBUF_TYPE jmp_buf
-#define DUK_SETJMP(jb) _setjmp((jb))
-#define DUK_LONGJMP(jb) _longjmp((jb), 1)
-
-#define DUK_USE_OS_STRING "windows"
-#elif defined(DUK_F_UNIX)
-/* --- Generic UNIX --- */
-#define DUK_USE_DATE_NOW_GETTIMEOFDAY
-#define DUK_USE_DATE_TZO_GMTIME_R
-#define DUK_USE_DATE_PRS_STRPTIME
-#define DUK_USE_DATE_FMT_STRFTIME
-#include <time.h>
-#include <sys/time.h>
-#define DUK_USE_OS_STRING "unknown"
-#else
-/* --- Generic fallback --- */
-/* The most portable current time provider is time(), but it only has a
- * one second resolution.
- */
-#define DUK_USE_DATE_NOW_TIME
-
-/* The most portable way to figure out local time offset is gmtime(),
- * but it's not thread safe so use with caution.
- */
-#define DUK_USE_DATE_TZO_GMTIME
-
-/* Avoid custom date parsing and formatting for portability. */
-#undef DUK_USE_DATE_PRS_STRPTIME
-#undef DUK_USE_DATE_FMT_STRFTIME
-
-/* Rely on C89 headers only; time.h must be here. */
-#include <time.h>
-
-#define DUK_USE_OS_STRING "unknown"
-#endif /* autodetect platform */
-
-/* Shared includes: C89 */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h> /* varargs */
-#include <setjmp.h>
-#include <stddef.h> /* e.g. ptrdiff_t */
-#include <math.h>
-#include <limits.h>
-
-/* date.h is omitted, and included per platform */
-
-/* Shared includes: stdint.h is C99 */
-#if defined(DUK_F_NO_STDINT_H)
-/* stdint.h not available */
-#else
-/* Technically C99 (C++11) but found in many systems. On some systems
- * __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS must be defined before
- * including stdint.h (see above).
- */
-#include <stdint.h>
-#endif
-
-#if defined(DUK_F_CPP)
-#include <exception> /* std::exception */
-#endif
-
-/*
- * Architecture autodetection
- */
-
-#if defined(DUK_F_X86)
-/* --- x86 --- */
-#define DUK_USE_ARCH_STRING "x86"
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 1
-#endif
-/* XXX: This is technically not guaranteed because it's possible to configure
- * an x86 to require aligned accesses with Alignment Check (AC) flag.
- */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 1
-#endif
-#define DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_X64)
-/* --- x64 --- */
-#define DUK_USE_ARCH_STRING "x64"
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 1
-#endif
-/* XXX: This is technically not guaranteed because it's possible to configure
- * an x86 to require aligned accesses with Alignment Check (AC) flag.
- */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 1
-#endif
-#undef DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_X32)
-/* --- x32 --- */
-#define DUK_USE_ARCH_STRING "x32"
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 1
-#endif
-/* XXX: This is technically not guaranteed because it's possible to configure
- * an x86 to require aligned accesses with Alignment Check (AC) flag.
- */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 1
-#endif
-#define DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_ARM32)
-/* --- ARM 32-bit --- */
-#define DUK_USE_ARCH_STRING "arm32"
-/* Byte order varies, so rely on autodetect. */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 4
-#endif
-#define DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_ARM64)
-/* --- ARM 64-bit --- */
-#define DUK_USE_ARCH_STRING "arm64"
-/* Byte order varies, so rely on autodetect. */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-#undef DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_MIPS32)
-/* --- MIPS 32-bit --- */
-#define DUK_USE_ARCH_STRING "mips32"
-/* MIPS byte order varies so rely on autodetection. */
-/* Based on 'make checkalign' there are no alignment requirements on
- * Linux MIPS except for doubles, which need align by 4. Alignment
- * requirements vary based on target though.
- */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 4
-#endif
-#define DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_MIPS64)
-/* --- MIPS 64-bit --- */
-#define DUK_USE_ARCH_STRING "mips64"
-/* MIPS byte order varies so rely on autodetection. */
-/* Good default is a bit arbitrary because alignment requirements
- * depend on target. See https://github.com/svaarala/duktape/issues/102.
- */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-#undef DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_PPC32)
-/* --- PowerPC 32-bit --- */
-#define DUK_USE_ARCH_STRING "ppc32"
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 3
-#endif
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-#define DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_PPC64)
-/* --- PowerPC 64-bit --- */
-#define DUK_USE_ARCH_STRING "ppc64"
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 3
-#endif
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-#undef DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_SPARC32)
-/* --- SPARC 32-bit --- */
-#define DUK_USE_ARCH_STRING "sparc32"
-/* SPARC byte order varies so rely on autodetection. */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-#define DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_SPARC64)
-/* --- SPARC 64-bit --- */
-#define DUK_USE_ARCH_STRING "sparc64"
-/* SPARC byte order varies so rely on autodetection. */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-#undef DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_SUPERH)
-/* --- SuperH --- */
-#define DUK_USE_ARCH_STRING "sh"
-/* Byte order varies, rely on autodetection. */
-/* Based on 'make checkalign' there are no alignment requirements on
- * Linux SH4, but align by 4 is probably a good basic default.
- */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 4
-#endif
-#define DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_M68K)
-/* --- Motorola 68k --- */
-#define DUK_USE_ARCH_STRING "m68k"
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 3
-#endif
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-#define DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#elif defined(DUK_F_EMSCRIPTEN)
-/* --- Emscripten --- */
-#define DUK_USE_ARCH_STRING "emscripten"
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 1
-#endif
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-#undef DUK_USE_PACKED_TVAL
-#define DUK_F_PACKED_TVAL_PROVIDED
-#else
-/* --- Generic --- */
-/* These are necessary wild guesses. */
-#define DUK_USE_ARCH_STRING "generic"
-/* Rely on autodetection for byte order, alignment, and packed tval. */
-#endif /* autodetect architecture */
-
-/*
- * Compiler autodetection
- */
-
-#if defined(DUK_F_CLANG)
-/* --- Clang --- */
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-/* C99 / C++11 and above: rely on va_copy() which is required. */
-#define DUK_VA_COPY(dest,src) va_copy(dest,src)
-#else
-/* Clang: assume we have __va_copy() in non-C99 mode. */
-#define DUK_VA_COPY(dest,src) __va_copy(dest,src)
-#endif
-
-#define DUK_NORETURN(decl) decl __attribute__((noreturn))
-
-#if defined(__clang__) && defined(__has_builtin)
-#if __has_builtin(__builtin_unreachable)
-#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0)
-#endif
-#endif
-
-#define DUK_USE_BRANCH_HINTS
-#define DUK_LIKELY(x) __builtin_expect((x), 1)
-#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
-
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-#define DUK_NOINLINE __attribute__((noinline))
-#define DUK_INLINE inline
-#define DUK_ALWAYS_INLINE inline __attribute__((always_inline))
-#endif
-
-#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS)
-/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're
- * compiling Duktape or the application.
- */
-#if defined(DUK_COMPILING_DUKTAPE)
-#define DUK_EXTERNAL_DECL extern __declspec(dllexport)
-#define DUK_EXTERNAL __declspec(dllexport)
-#else
-#define DUK_EXTERNAL_DECL extern __declspec(dllimport)
-#define DUK_EXTERNAL should_not_happen
-#endif
-#if defined(DUK_SINGLE_FILE)
-#define DUK_INTERNAL_DECL static
-#define DUK_INTERNAL static
-#else
-#define DUK_INTERNAL_DECL extern
-#define DUK_INTERNAL /*empty*/
-#endif
-#define DUK_LOCAL_DECL static
-#define DUK_LOCAL static
-#else
-#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern
-#define DUK_EXTERNAL __attribute__ ((visibility("default")))
-#if defined(DUK_SINGLE_FILE)
-#define DUK_INTERNAL_DECL static
-#define DUK_INTERNAL static
-#else
-#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern
-#define DUK_INTERNAL __attribute__ ((visibility("hidden")))
-#endif
-#define DUK_LOCAL_DECL static
-#define DUK_LOCAL static
-#endif
-
-#if defined(DUK_F_CPP)
-#define DUK_USE_COMPILER_STRING "clang"
-#else
-#define DUK_USE_COMPILER_STRING "clang"
-#endif
-
-#undef DUK_USE_VARIADIC_MACROS
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-#define DUK_USE_VARIADIC_MACROS
-#endif
-
-#define DUK_USE_UNION_INITIALIZERS
-
-#undef DUK_USE_FLEX_C99
-#undef DUK_USE_FLEX_ZEROSIZE
-#undef DUK_USE_FLEX_ONESIZE
-#if defined(DUK_F_C99)
-#define DUK_USE_FLEX_C99
-#else
-#define DUK_USE_FLEX_ZEROSIZE
-#endif
-
-#undef DUK_USE_GCC_PRAGMAS
-#define DUK_USE_PACK_CLANG_ATTR
-#elif defined(DUK_F_GCC)
-/* --- GCC --- */
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-/* C99 / C++11 and above: rely on va_copy() which is required. */
-#define DUK_VA_COPY(dest,src) va_copy(dest,src)
-#else
-/* GCC: assume we have __va_copy() in non-C99 mode. */
-#define DUK_VA_COPY(dest,src) __va_copy(dest,src)
-#endif
-
-#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 20500L)
-/* since gcc-2.5 */
-#define DUK_NORETURN(decl) decl __attribute__((noreturn))
-#endif
-
-#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L)
-/* since gcc-4.5 */
-#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0)
-#endif
-
-#define DUK_USE_BRANCH_HINTS
-#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40500L)
-/* GCC: test not very accurate; enable only in relatively recent builds
- * because of bugs in gcc-4.4 (http://lists.debian.org/debian-gcc/2010/04/msg00000.html)
- */
-#define DUK_LIKELY(x) __builtin_expect((x), 1)
-#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
-#endif
-
-#if (defined(DUK_F_C99) || defined(DUK_F_CPP11)) && \
- defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 30101)
-#define DUK_NOINLINE __attribute__((noinline))
-#define DUK_INLINE inline
-#define DUK_ALWAYS_INLINE inline __attribute__((always_inline))
-#endif
-
-#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS)
-/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're
- * compiling Duktape or the application.
- */
-#if defined(DUK_COMPILING_DUKTAPE)
-#define DUK_EXTERNAL_DECL extern __declspec(dllexport)
-#define DUK_EXTERNAL __declspec(dllexport)
-#else
-#define DUK_EXTERNAL_DECL extern __declspec(dllimport)
-#define DUK_EXTERNAL should_not_happen
-#endif
-#if defined(DUK_SINGLE_FILE)
-#define DUK_INTERNAL_DECL static
-#define DUK_INTERNAL static
-#else
-#define DUK_INTERNAL_DECL extern
-#define DUK_INTERNAL /*empty*/
-#endif
-#define DUK_LOCAL_DECL static
-#define DUK_LOCAL static
-#elif defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40000)
-#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern
-#define DUK_EXTERNAL __attribute__ ((visibility("default")))
-#if defined(DUK_SINGLE_FILE)
-#define DUK_INTERNAL_DECL static
-#define DUK_INTERNAL static
-#else
-#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern
-#define DUK_INTERNAL __attribute__ ((visibility("hidden")))
-#endif
-#define DUK_LOCAL_DECL static
-#define DUK_LOCAL static
-#endif
-
-#if defined(DUK_F_MINGW)
-#if defined(DUK_F_CPP)
-#define DUK_USE_COMPILER_STRING "mingw++"
-#else
-#define DUK_USE_COMPILER_STRING "mingw"
-#endif
-#else
-#if defined(DUK_F_CPP)
-#define DUK_USE_COMPILER_STRING "g++"
-#else
-#define DUK_USE_COMPILER_STRING "gcc"
-#endif
-#endif
-
-#undef DUK_USE_VARIADIC_MACROS
-#if defined(DUK_F_C99) || (defined(DUK_F_CPP11) && defined(__GNUC__))
-#define DUK_USE_VARIADIC_MACROS
-#endif
-
-#define DUK_USE_UNION_INITIALIZERS
-
-#undef DUK_USE_FLEX_C99
-#undef DUK_USE_FLEX_ZEROSIZE
-#undef DUK_USE_FLEX_ONESIZE
-#if defined(DUK_F_C99)
-#define DUK_USE_FLEX_C99
-#else
-#define DUK_USE_FLEX_ZEROSIZE
-#endif
-
-#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION >= 40600)
-#define DUK_USE_GCC_PRAGMAS
-#else
-#undef DUK_USE_GCC_PRAGMAS
-#endif
-
-#define DUK_USE_PACK_GCC_ATTR
-#elif defined(DUK_F_MSVC)
-/* --- MSVC --- */
-/* http://msdn.microsoft.com/en-us/library/aa235362(VS.60).aspx */
-#define DUK_NORETURN(decl) __declspec(noreturn) decl
-
-/* XXX: DUK_UNREACHABLE for msvc? */
-
-#undef DUK_USE_BRANCH_HINTS
-
-/* XXX: DUK_LIKELY, DUK_UNLIKELY for msvc? */
-/* XXX: DUK_NOINLINE, DUK_INLINE, DUK_ALWAYS_INLINE for msvc? */
-
-#if defined(DUK_F_DLL_BUILD) && defined(DUK_F_WINDOWS)
-/* MSVC dllexport/dllimport: appropriate __declspec depends on whether we're
- * compiling Duktape or the application.
- */
-#if defined(DUK_COMPILING_DUKTAPE)
-#define DUK_EXTERNAL_DECL extern __declspec(dllexport)
-#define DUK_EXTERNAL __declspec(dllexport)
-#else
-#define DUK_EXTERNAL_DECL extern __declspec(dllimport)
-#define DUK_EXTERNAL should_not_happen
-#endif
-#if defined(DUK_SINGLE_FILE)
-#define DUK_INTERNAL_DECL static
-#define DUK_INTERNAL static
-#else
-#define DUK_INTERNAL_DECL extern
-#define DUK_INTERNAL /*empty*/
-#endif
-#define DUK_LOCAL_DECL static
-#define DUK_LOCAL static
-#endif
-
-#if defined(DUK_F_CPP)
-#define DUK_USE_COMPILER_STRING "msvc++"
-#else
-#define DUK_USE_COMPILER_STRING "msvc"
-#endif
-
-#undef DUK_USE_VARIADIC_MACROS
-#if defined(DUK_F_C99)
-#define DUK_USE_VARIADIC_MACROS
-#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
-/* VS2005+ should have variadic macros even when they're not C99. */
-#define DUK_USE_VARIADIC_MACROS
-#endif
-
-#undef DUK_USE_UNION_INITIALIZERS
-#if defined(_MSC_VER) && (_MSC_VER >= 1800)
-/* VS2013+ supports union initializers but there's a bug involving union-inside-struct:
- * https://connect.microsoft.com/VisualStudio/feedback/details/805981
- * The bug was fixed (at least) in VS2015 so check for VS2015 for now:
- * https://blogs.msdn.microsoft.com/vcblog/2015/07/01/c-compiler-front-end-fixes-in-vs2015/
- * Manually tested using VS2013, CL reports 18.00.31101, so enable for VS2013 too.
- */
-#define DUK_USE_UNION_INITIALIZERS
-#endif
-
-#undef DUK_USE_FLEX_C99
-#undef DUK_USE_FLEX_ZEROSIZE
-#undef DUK_USE_FLEX_ONESIZE
-#if defined(DUK_F_C99)
-#define DUK_USE_FLEX_C99
-#else
-#define DUK_USE_FLEX_ZEROSIZE
-#endif
-
-#undef DUK_USE_GCC_PRAGMAS
-
-#define DUK_USE_PACK_MSVC_PRAGMA
-
-/* These have been tested from VS2008 onwards; may work in older VS versions
- * too but not enabled by default.
- */
-#if defined(_MSC_VER) && (_MSC_VER >= 1500)
-#define DUK_NOINLINE __declspec(noinline)
-#define DUK_INLINE __inline
-#define DUK_ALWAYS_INLINE __forceinline
-#endif
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1900)
-#define DUK_SNPRINTF snprintf
-#define DUK_VSNPRINTF vsnprintf
-#else
-/* (v)snprintf() is missing before MSVC 2015. Note that _(v)snprintf() does
- * NOT NUL terminate on truncation, but Duktape code never assumes that.
- * http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
- */
-#define DUK_SNPRINTF _snprintf
-#define DUK_VSNPRINTF _vsnprintf
-#endif
-#elif defined(DUK_F_EMSCRIPTEN)
-/* --- Emscripten --- */
-#define DUK_NORETURN(decl) decl __attribute__((noreturn))
-
-#if defined(__clang__) && defined(__has_builtin)
-#if __has_builtin(__builtin_unreachable)
-#define DUK_UNREACHABLE() do { __builtin_unreachable(); } while (0)
-#endif
-#endif
-
-#define DUK_USE_BRANCH_HINTS
-#define DUK_LIKELY(x) __builtin_expect((x), 1)
-#define DUK_UNLIKELY(x) __builtin_expect((x), 0)
-
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-#define DUK_NOINLINE __attribute__((noinline))
-#define DUK_INLINE inline
-#define DUK_ALWAYS_INLINE inline __attribute__((always_inline))
-#endif
-
-#define DUK_EXTERNAL_DECL __attribute__ ((visibility("default"))) extern
-#define DUK_EXTERNAL __attribute__ ((visibility("default")))
-#if defined(DUK_SINGLE_FILE)
-#define DUK_INTERNAL_DECL static
-#define DUK_INTERNAL static
-#else
-#define DUK_INTERNAL_DECL __attribute__ ((visibility("hidden"))) extern
-#define DUK_INTERNAL __attribute__ ((visibility("hidden")))
-#endif
-#define DUK_LOCAL_DECL static
-#define DUK_LOCAL static
-
-#define DUK_USE_COMPILER_STRING "emscripten"
-
-#undef DUK_USE_VARIADIC_MACROS
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-#define DUK_USE_VARIADIC_MACROS
-#endif
-
-#define DUK_USE_UNION_INITIALIZERS
-
-#undef DUK_USE_FLEX_C99
-#undef DUK_USE_FLEX_ZEROSIZE
-#undef DUK_USE_FLEX_ONESIZE
-#if defined(DUK_F_C99)
-#define DUK_USE_FLEX_C99
-#else
-#define DUK_USE_FLEX_ZEROSIZE
-#endif
-
-#undef DUK_USE_GCC_PRAGMAS
-#define DUK_USE_PACK_CLANG_ATTR
-#elif defined(DUK_F_TINYC)
-/* --- TinyC --- */
-#undef DUK_USE_BRANCH_HINTS
-
-#if defined(DUK_F_CPP)
-#define DUK_USE_COMPILER_STRING "tinyc++"
-#else
-#define DUK_USE_COMPILER_STRING "tinyc"
-#endif
-
-/* http://bellard.org/tcc/tcc-doc.html#SEC7 */
-#define DUK_USE_VARIADIC_MACROS
-
-#define DUK_USE_UNION_INITIALIZERS
-
-/* Most portable, wastes space */
-#define DUK_USE_FLEX_ONESIZE
-
-/* Most portable, potentially wastes space */
-#define DUK_USE_PACK_DUMMY_MEMBER
-#elif defined(DUK_F_VBCC)
-/* --- VBCC --- */
-#undef DUK_USE_BRANCH_HINTS
-
-#if defined(DUK_F_CPP)
-#define DUK_USE_COMPILER_STRING "vbcc-c++"
-#else
-#define DUK_USE_COMPILER_STRING "vbcc"
-#endif
-
-#undef DUK_USE_VARIADIC_MACROS
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-#define DUK_USE_VARIADIC_MACROS
-#endif
-
-/* VBCC supports C99 so check only for C99 for union initializer support.
- * Designated union initializers would possibly work even without a C99 check.
- */
-#undef DUK_USE_UNION_INITIALIZERS
-#if defined(DUK_F_C99)
-#define DUK_USE_UNION_INITIALIZERS
-#endif
-
-#define DUK_USE_FLEX_ZEROSIZE
-#define DUK_USE_PACK_DUMMY_MEMBER
-#elif defined(DUK_F_BCC)
-/* --- Bruce's C compiler --- */
-#undef DUK_USE_BRANCH_HINTS
-
-#if defined(DUK_F_CPP)
-#define DUK_USE_COMPILER_STRING "bcc++"
-#else
-#define DUK_USE_COMPILER_STRING "bcc"
-#endif
-
-/* Most portable */
-#undef DUK_USE_VARIADIC_MACROS
-
-/* Most portable, wastes space */
-#undef DUK_USE_UNION_INITIALIZERS
-
-/* Most portable, wastes space */
-#define DUK_USE_FLEX_ONESIZE
-
-/* Most portable, potentially wastes space */
-#define DUK_USE_PACK_DUMMY_MEMBER
-
-/* BCC, assume we're on x86. */
-#if !defined(DUK_USE_BYTEORDER)
-#define DUK_USE_BYTEORDER 1
-#endif
-#else
-/* --- Generic --- */
-#undef DUK_USE_BRANCH_HINTS
-
-#if defined(DUK_F_CPP)
-#define DUK_USE_COMPILER_STRING "generic-c++"
-#else
-#define DUK_USE_COMPILER_STRING "generic"
-#endif
-
-#undef DUK_USE_VARIADIC_MACROS
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-#define DUK_USE_VARIADIC_MACROS
-#endif
-
-/* C++ doesn't have standard designated union initializers ({ .foo = 1 }). */
-#undef DUK_USE_UNION_INITIALIZERS
-#if defined(DUK_F_C99)
-#define DUK_USE_UNION_INITIALIZERS
-#endif
-
-/* Most portable, wastes space */
-#define DUK_USE_FLEX_ONESIZE
-
-/* Most portable, potentially wastes space */
-#define DUK_USE_PACK_DUMMY_MEMBER
-#endif /* autodetect compiler */
-
-/* uclibc */
-#if defined(__UCLIBC__)
-#define DUK_F_UCLIBC
-#endif
-
-/*
- * Wrapper typedefs and constants for integer types, also sanity check types.
- *
- * C99 typedefs are quite good but not always available, and we want to avoid
- * forcibly redefining the C99 typedefs. So, there are Duktape wrappers for
- * all C99 typedefs and Duktape code should only use these typedefs. Type
- * detection when C99 is not supported is best effort and may end up detecting
- * some types incorrectly.
- *
- * Pointer sizes are a portability problem: pointers to different types may
- * have a different size and function pointers are very difficult to manage
- * portably.
- *
- * http://en.wikipedia.org/wiki/C_data_types#Fixed-width_integer_types
- *
- * Note: there's an interesting corner case when trying to define minimum
- * signed integer value constants which leads to the current workaround of
- * defining e.g. -0x80000000 as (-0x7fffffffL - 1L). See doc/code-issues.txt
- * for a longer discussion.
- *
- * Note: avoid typecasts and computations in macro integer constants as they
- * can then no longer be used in macro relational expressions (such as
- * #if DUK_SIZE_MAX < 0xffffffffUL). There is internal code which relies on
- * being able to compare DUK_SIZE_MAX against a limit.
- */
-
-/* XXX: add feature options to force basic types from outside? */
-
-#if !defined(INT_MAX)
-#error INT_MAX not defined
-#endif
-
-/* Check that architecture is two's complement, standard C allows e.g.
- * INT_MIN to be -2**31+1 (instead of -2**31).
- */
-#if defined(INT_MAX) && defined(INT_MIN)
-#if INT_MAX != -(INT_MIN + 1)
-#error platform does not seem complement of two
-#endif
-#else
-#error cannot check complement of two
-#endif
-
-/* Pointer size determination based on __WORDSIZE or architecture when
- * that's not available.
- */
-#if defined(DUK_F_X86) || defined(DUK_F_X32) || \
- defined(DUK_F_M68K) || defined(DUK_F_PPC32) || \
- defined(DUK_F_BCC) || \
- (defined(__WORDSIZE) && (__WORDSIZE == 32))
-#define DUK_F_32BIT_PTRS
-#elif defined(DUK_F_X64) || \
- (defined(__WORDSIZE) && (__WORDSIZE == 64))
-#define DUK_F_64BIT_PTRS
-#else
-/* not sure, not needed with C99 anyway */
-#endif
-
-/* Intermediate define for 'have inttypes.h' */
-#undef DUK_F_HAVE_INTTYPES
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
- !(defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC))
-/* vbcc + AmigaOS has C99 but no inttypes.h */
-#define DUK_F_HAVE_INTTYPES
-#elif defined(__cplusplus) && (__cplusplus >= 201103L)
-/* C++11 apparently ratified stdint.h */
-#define DUK_F_HAVE_INTTYPES
-#endif
-
-/* Basic integer typedefs and limits, preferably from inttypes.h, otherwise
- * through automatic detection.
- */
-#if defined(DUK_F_HAVE_INTTYPES)
-/* C99 or compatible */
-
-#define DUK_F_HAVE_64BIT
-#include <inttypes.h>
-
-typedef uint8_t duk_uint8_t;
-typedef int8_t duk_int8_t;
-typedef uint16_t duk_uint16_t;
-typedef int16_t duk_int16_t;
-typedef uint32_t duk_uint32_t;
-typedef int32_t duk_int32_t;
-typedef uint64_t duk_uint64_t;
-typedef int64_t duk_int64_t;
-typedef uint_least8_t duk_uint_least8_t;
-typedef int_least8_t duk_int_least8_t;
-typedef uint_least16_t duk_uint_least16_t;
-typedef int_least16_t duk_int_least16_t;
-typedef uint_least32_t duk_uint_least32_t;
-typedef int_least32_t duk_int_least32_t;
-typedef uint_least64_t duk_uint_least64_t;
-typedef int_least64_t duk_int_least64_t;
-typedef uint_fast8_t duk_uint_fast8_t;
-typedef int_fast8_t duk_int_fast8_t;
-typedef uint_fast16_t duk_uint_fast16_t;
-typedef int_fast16_t duk_int_fast16_t;
-typedef uint_fast32_t duk_uint_fast32_t;
-typedef int_fast32_t duk_int_fast32_t;
-typedef uint_fast64_t duk_uint_fast64_t;
-typedef int_fast64_t duk_int_fast64_t;
-typedef uintptr_t duk_uintptr_t;
-typedef intptr_t duk_intptr_t;
-typedef uintmax_t duk_uintmax_t;
-typedef intmax_t duk_intmax_t;
-
-#define DUK_UINT8_MIN 0
-#define DUK_UINT8_MAX UINT8_MAX
-#define DUK_INT8_MIN INT8_MIN
-#define DUK_INT8_MAX INT8_MAX
-#define DUK_UINT_LEAST8_MIN 0
-#define DUK_UINT_LEAST8_MAX UINT_LEAST8_MAX
-#define DUK_INT_LEAST8_MIN INT_LEAST8_MIN
-#define DUK_INT_LEAST8_MAX INT_LEAST8_MAX
-#define DUK_UINT_FAST8_MIN 0
-#define DUK_UINT_FAST8_MAX UINT_FAST8_MAX
-#define DUK_INT_FAST8_MIN INT_FAST8_MIN
-#define DUK_INT_FAST8_MAX INT_FAST8_MAX
-#define DUK_UINT16_MIN 0
-#define DUK_UINT16_MAX UINT16_MAX
-#define DUK_INT16_MIN INT16_MIN
-#define DUK_INT16_MAX INT16_MAX
-#define DUK_UINT_LEAST16_MIN 0
-#define DUK_UINT_LEAST16_MAX UINT_LEAST16_MAX
-#define DUK_INT_LEAST16_MIN INT_LEAST16_MIN
-#define DUK_INT_LEAST16_MAX INT_LEAST16_MAX
-#define DUK_UINT_FAST16_MIN 0
-#define DUK_UINT_FAST16_MAX UINT_FAST16_MAX
-#define DUK_INT_FAST16_MIN INT_FAST16_MIN
-#define DUK_INT_FAST16_MAX INT_FAST16_MAX
-#define DUK_UINT32_MIN 0
-#define DUK_UINT32_MAX UINT32_MAX
-#define DUK_INT32_MIN INT32_MIN
-#define DUK_INT32_MAX INT32_MAX
-#define DUK_UINT_LEAST32_MIN 0
-#define DUK_UINT_LEAST32_MAX UINT_LEAST32_MAX
-#define DUK_INT_LEAST32_MIN INT_LEAST32_MIN
-#define DUK_INT_LEAST32_MAX INT_LEAST32_MAX
-#define DUK_UINT_FAST32_MIN 0
-#define DUK_UINT_FAST32_MAX UINT_FAST32_MAX
-#define DUK_INT_FAST32_MIN INT_FAST32_MIN
-#define DUK_INT_FAST32_MAX INT_FAST32_MAX
-#define DUK_UINT64_MIN 0
-#define DUK_UINT64_MAX UINT64_MAX
-#define DUK_INT64_MIN INT64_MIN
-#define DUK_INT64_MAX INT64_MAX
-#define DUK_UINT_LEAST64_MIN 0
-#define DUK_UINT_LEAST64_MAX UINT_LEAST64_MAX
-#define DUK_INT_LEAST64_MIN INT_LEAST64_MIN
-#define DUK_INT_LEAST64_MAX INT_LEAST64_MAX
-#define DUK_UINT_FAST64_MIN 0
-#define DUK_UINT_FAST64_MAX UINT_FAST64_MAX
-#define DUK_INT_FAST64_MIN INT_FAST64_MIN
-#define DUK_INT_FAST64_MAX INT_FAST64_MAX
-
-#define DUK_UINTPTR_MIN 0
-#define DUK_UINTPTR_MAX UINTPTR_MAX
-#define DUK_INTPTR_MIN INTPTR_MIN
-#define DUK_INTPTR_MAX INTPTR_MAX
-
-#define DUK_UINTMAX_MIN 0
-#define DUK_UINTMAX_MAX UINTMAX_MAX
-#define DUK_INTMAX_MIN INTMAX_MIN
-#define DUK_INTMAX_MAX INTMAX_MAX
-
-#define DUK_SIZE_MIN 0
-#define DUK_SIZE_MAX SIZE_MAX
-#undef DUK_SIZE_MAX_COMPUTED
-
-#else /* C99 types */
-
-/* When C99 types are not available, we use heuristic detection to get
- * the basic 8, 16, 32, and (possibly) 64 bit types. The fast/least
- * types are then assumed to be exactly the same for now: these could
- * be improved per platform but C99 types are very often now available.
- * 64-bit types are not available on all platforms; this is OK at least
- * on 32-bit platforms.
- *
- * This detection code is necessarily a bit hacky and can provide typedefs
- * and defines that won't work correctly on some exotic platform.
- */
-
-#if (defined(CHAR_BIT) && (CHAR_BIT == 8)) || \
- (defined(UCHAR_MAX) && (UCHAR_MAX == 255))
-typedef unsigned char duk_uint8_t;
-typedef signed char duk_int8_t;
-#else
-#error cannot detect 8-bit type
-#endif
-
-#if defined(USHRT_MAX) && (USHRT_MAX == 65535UL)
-typedef unsigned short duk_uint16_t;
-typedef signed short duk_int16_t;
-#elif defined(UINT_MAX) && (UINT_MAX == 65535UL)
-/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */
-typedef unsigned int duk_uint16_t;
-typedef signed int duk_int16_t;
-#else
-#error cannot detect 16-bit type
-#endif
-
-#if defined(UINT_MAX) && (UINT_MAX == 4294967295UL)
-typedef unsigned int duk_uint32_t;
-typedef signed int duk_int32_t;
-#elif defined(ULONG_MAX) && (ULONG_MAX == 4294967295UL)
-/* On some platforms int is 16-bit but long is 32-bit (e.g. PureC) */
-typedef unsigned long duk_uint32_t;
-typedef signed long duk_int32_t;
-#else
-#error cannot detect 32-bit type
-#endif
-
-/* 64-bit type detection is a bit tricky.
- *
- * ULLONG_MAX is a standard define. __LONG_LONG_MAX__ and __ULONG_LONG_MAX__
- * are used by at least GCC (even if system headers don't provide ULLONG_MAX).
- * Some GCC variants may provide __LONG_LONG_MAX__ but not __ULONG_LONG_MAX__.
- *
- * ULL / LL constants are rejected / warned about by some compilers, even if
- * the compiler has a 64-bit type and the compiler/system headers provide an
- * unsupported constant (ULL/LL)! Try to avoid using ULL / LL constants.
- * As a side effect we can only check that e.g. ULONG_MAX is larger than 32
- * bits but can't be sure it is exactly 64 bits. Self tests will catch such
- * cases.
- */
-#undef DUK_F_HAVE_64BIT
-#if !defined(DUK_F_HAVE_64BIT) && defined(ULONG_MAX)
-#if (ULONG_MAX > 4294967295UL)
-#define DUK_F_HAVE_64BIT
-typedef unsigned long duk_uint64_t;
-typedef signed long duk_int64_t;
-#endif
-#endif
-#if !defined(DUK_F_HAVE_64BIT) && defined(ULLONG_MAX)
-#if (ULLONG_MAX > 4294967295UL)
-#define DUK_F_HAVE_64BIT
-typedef unsigned long long duk_uint64_t;
-typedef signed long long duk_int64_t;
-#endif
-#endif
-#if !defined(DUK_F_HAVE_64BIT) && defined(__ULONG_LONG_MAX__)
-#if (__ULONG_LONG_MAX__ > 4294967295UL)
-#define DUK_F_HAVE_64BIT
-typedef unsigned long long duk_uint64_t;
-typedef signed long long duk_int64_t;
-#endif
-#endif
-#if !defined(DUK_F_HAVE_64BIT) && defined(__LONG_LONG_MAX__)
-#if (__LONG_LONG_MAX__ > 2147483647L)
-#define DUK_F_HAVE_64BIT
-typedef unsigned long long duk_uint64_t;
-typedef signed long long duk_int64_t;
-#endif
-#endif
-#if !defined(DUK_F_HAVE_64BIT) && \
- (defined(DUK_F_MINGW) || defined(DUK_F_MSVC))
-/* Both MinGW and MSVC have a 64-bit type. */
-#define DUK_F_HAVE_64BIT
-typedef unsigned long duk_uint64_t;
-typedef signed long duk_int64_t;
-#endif
-#if !defined(DUK_F_HAVE_64BIT)
-/* cannot detect 64-bit type, not always needed so don't error */
-#endif
-
-typedef duk_uint8_t duk_uint_least8_t;
-typedef duk_int8_t duk_int_least8_t;
-typedef duk_uint16_t duk_uint_least16_t;
-typedef duk_int16_t duk_int_least16_t;
-typedef duk_uint32_t duk_uint_least32_t;
-typedef duk_int32_t duk_int_least32_t;
-typedef duk_uint8_t duk_uint_fast8_t;
-typedef duk_int8_t duk_int_fast8_t;
-typedef duk_uint16_t duk_uint_fast16_t;
-typedef duk_int16_t duk_int_fast16_t;
-typedef duk_uint32_t duk_uint_fast32_t;
-typedef duk_int32_t duk_int_fast32_t;
-#if defined(DUK_F_HAVE_64BIT)
-typedef duk_uint64_t duk_uint_least64_t;
-typedef duk_int64_t duk_int_least64_t;
-typedef duk_uint64_t duk_uint_fast64_t;
-typedef duk_int64_t duk_int_fast64_t;
-#endif
-#if defined(DUK_F_HAVE_64BIT)
-typedef duk_uint64_t duk_uintmax_t;
-typedef duk_int64_t duk_intmax_t;
-#else
-typedef duk_uint32_t duk_uintmax_t;
-typedef duk_int32_t duk_intmax_t;
-#endif
-
-/* Note: the funny looking computations for signed minimum 16-bit, 32-bit, and
- * 64-bit values are intentional as the obvious forms (e.g. -0x80000000L) are
- * -not- portable. See code-issues.txt for a detailed discussion.
- */
-#define DUK_UINT8_MIN 0UL
-#define DUK_UINT8_MAX 0xffUL
-#define DUK_INT8_MIN (-0x80L)
-#define DUK_INT8_MAX 0x7fL
-#define DUK_UINT_LEAST8_MIN 0UL
-#define DUK_UINT_LEAST8_MAX 0xffUL
-#define DUK_INT_LEAST8_MIN (-0x80L)
-#define DUK_INT_LEAST8_MAX 0x7fL
-#define DUK_UINT_FAST8_MIN 0UL
-#define DUK_UINT_FAST8_MAX 0xffUL
-#define DUK_INT_FAST8_MIN (-0x80L)
-#define DUK_INT_FAST8_MAX 0x7fL
-#define DUK_UINT16_MIN 0UL
-#define DUK_UINT16_MAX 0xffffUL
-#define DUK_INT16_MIN (-0x7fffL - 1L)
-#define DUK_INT16_MAX 0x7fffL
-#define DUK_UINT_LEAST16_MIN 0UL
-#define DUK_UINT_LEAST16_MAX 0xffffUL
-#define DUK_INT_LEAST16_MIN (-0x7fffL - 1L)
-#define DUK_INT_LEAST16_MAX 0x7fffL
-#define DUK_UINT_FAST16_MIN 0UL
-#define DUK_UINT_FAST16_MAX 0xffffUL
-#define DUK_INT_FAST16_MIN (-0x7fffL - 1L)
-#define DUK_INT_FAST16_MAX 0x7fffL
-#define DUK_UINT32_MIN 0UL
-#define DUK_UINT32_MAX 0xffffffffUL
-#define DUK_INT32_MIN (-0x7fffffffL - 1L)
-#define DUK_INT32_MAX 0x7fffffffL
-#define DUK_UINT_LEAST32_MIN 0UL
-#define DUK_UINT_LEAST32_MAX 0xffffffffUL
-#define DUK_INT_LEAST32_MIN (-0x7fffffffL - 1L)
-#define DUK_INT_LEAST32_MAX 0x7fffffffL
-#define DUK_UINT_FAST32_MIN 0UL
-#define DUK_UINT_FAST32_MAX 0xffffffffUL
-#define DUK_INT_FAST32_MIN (-0x7fffffffL - 1L)
-#define DUK_INT_FAST32_MAX 0x7fffffffL
-
-/* 64-bit constants. Since LL / ULL constants are not always available,
- * use computed values. These values can't be used in preprocessor
- * comparisons; flag them as such.
- */
-#if defined(DUK_F_HAVE_64BIT)
-#define DUK_UINT64_MIN ((duk_uint64_t) 0)
-#define DUK_UINT64_MAX ((duk_uint64_t) -1)
-#define DUK_INT64_MIN ((duk_int64_t) (~(DUK_UINT64_MAX >> 1)))
-#define DUK_INT64_MAX ((duk_int64_t) (DUK_UINT64_MAX >> 1))
-#define DUK_UINT_LEAST64_MIN DUK_UINT64_MIN
-#define DUK_UINT_LEAST64_MAX DUK_UINT64_MAX
-#define DUK_INT_LEAST64_MIN DUK_INT64_MIN
-#define DUK_INT_LEAST64_MAX DUK_INT64_MAX
-#define DUK_UINT_FAST64_MIN DUK_UINT64_MIN
-#define DUK_UINT_FAST64_MAX DUK_UINT64_MAX
-#define DUK_INT_FAST64_MIN DUK_INT64_MIN
-#define DUK_INT_FAST64_MAX DUK_INT64_MAX
-#define DUK_UINT64_MIN_COMPUTED
-#define DUK_UINT64_MAX_COMPUTED
-#define DUK_INT64_MIN_COMPUTED
-#define DUK_INT64_MAX_COMPUTED
-#define DUK_UINT_LEAST64_MIN_COMPUTED
-#define DUK_UINT_LEAST64_MAX_COMPUTED
-#define DUK_INT_LEAST64_MIN_COMPUTED
-#define DUK_INT_LEAST64_MAX_COMPUTED
-#define DUK_UINT_FAST64_MIN_COMPUTED
-#define DUK_UINT_FAST64_MAX_COMPUTED
-#define DUK_INT_FAST64_MIN_COMPUTED
-#define DUK_INT_FAST64_MAX_COMPUTED
-#endif
-
-#if defined(DUK_F_HAVE_64BIT)
-#define DUK_UINTMAX_MIN DUK_UINT64_MIN
-#define DUK_UINTMAX_MAX DUK_UINT64_MAX
-#define DUK_INTMAX_MIN DUK_INT64_MIN
-#define DUK_INTMAX_MAX DUK_INT64_MAX
-#define DUK_UINTMAX_MIN_COMPUTED
-#define DUK_UINTMAX_MAX_COMPUTED
-#define DUK_INTMAX_MIN_COMPUTED
-#define DUK_INTMAX_MAX_COMPUTED
-#else
-#define DUK_UINTMAX_MIN 0UL
-#define DUK_UINTMAX_MAX 0xffffffffUL
-#define DUK_INTMAX_MIN (-0x7fffffffL - 1L)
-#define DUK_INTMAX_MAX 0x7fffffffL
-#endif
-
-/* This detection is not very reliable. */
-#if defined(DUK_F_32BIT_PTRS)
-typedef duk_int32_t duk_intptr_t;
-typedef duk_uint32_t duk_uintptr_t;
-#define DUK_UINTPTR_MIN DUK_UINT32_MIN
-#define DUK_UINTPTR_MAX DUK_UINT32_MAX
-#define DUK_INTPTR_MIN DUK_INT32_MIN
-#define DUK_INTPTR_MAX DUK_INT32_MAX
-#elif defined(DUK_F_64BIT_PTRS) && defined(DUK_F_HAVE_64BIT)
-typedef duk_int64_t duk_intptr_t;
-typedef duk_uint64_t duk_uintptr_t;
-#define DUK_UINTPTR_MIN DUK_UINT64_MIN
-#define DUK_UINTPTR_MAX DUK_UINT64_MAX
-#define DUK_INTPTR_MIN DUK_INT64_MIN
-#define DUK_INTPTR_MAX DUK_INT64_MAX
-#define DUK_UINTPTR_MIN_COMPUTED
-#define DUK_UINTPTR_MAX_COMPUTED
-#define DUK_INTPTR_MIN_COMPUTED
-#define DUK_INTPTR_MAX_COMPUTED
-#else
-#error cannot determine intptr type
-#endif
-
-/* SIZE_MAX may be missing so use an approximate value for it. */
-#undef DUK_SIZE_MAX_COMPUTED
-#if !defined(SIZE_MAX)
-#define DUK_SIZE_MAX_COMPUTED
-#define SIZE_MAX ((size_t) (-1))
-#endif
-#define DUK_SIZE_MIN 0
-#define DUK_SIZE_MAX SIZE_MAX
-
-#endif /* C99 types */
-
-/* A few types are assumed to always exist. */
-typedef size_t duk_size_t;
-typedef ptrdiff_t duk_ptrdiff_t;
-
-/* The best type for an "all around int" in Duktape internals is "at least
- * 32 bit signed integer" which is most convenient. Same for unsigned type.
- * Prefer 'int' when large enough, as it is almost always a convenient type.
- */
-#if defined(UINT_MAX) && (UINT_MAX >= 0xffffffffUL)
-typedef int duk_int_t;
-typedef unsigned int duk_uint_t;
-#define DUK_INT_MIN INT_MIN
-#define DUK_INT_MAX INT_MAX
-#define DUK_UINT_MIN 0
-#define DUK_UINT_MAX UINT_MAX
-#else
-typedef duk_int_fast32_t duk_int_t;
-typedef duk_uint_fast32_t duk_uint_t;
-#define DUK_INT_MIN DUK_INT_FAST32_MIN
-#define DUK_INT_MAX DUK_INT_FAST32_MAX
-#define DUK_UINT_MIN DUK_UINT_FAST32_MIN
-#define DUK_UINT_MAX DUK_UINT_FAST32_MAX
-#endif
-
-/* Same as 'duk_int_t' but guaranteed to be a 'fast' variant if this
- * distinction matters for the CPU. These types are used mainly in the
- * executor where it might really matter.
- */
-typedef duk_int_fast32_t duk_int_fast_t;
-typedef duk_uint_fast32_t duk_uint_fast_t;
-#define DUK_INT_FAST_MIN DUK_INT_FAST32_MIN
-#define DUK_INT_FAST_MAX DUK_INT_FAST32_MAX
-#define DUK_UINT_FAST_MIN DUK_UINT_FAST32_MIN
-#define DUK_UINT_FAST_MAX DUK_UINT_FAST32_MAX
-
-/* Small integers (16 bits or more) can fall back to the 'int' type, but
- * have a typedef so they are marked "small" explicitly.
- */
-typedef int duk_small_int_t;
-typedef unsigned int duk_small_uint_t;
-#define DUK_SMALL_INT_MIN INT_MIN
-#define DUK_SMALL_INT_MAX INT_MAX
-#define DUK_SMALL_UINT_MIN 0
-#define DUK_SMALL_UINT_MAX UINT_MAX
-
-/* Fast variants of small integers, again for really fast paths like the
- * executor.
- */
-typedef duk_int_fast16_t duk_small_int_fast_t;
-typedef duk_uint_fast16_t duk_small_uint_fast_t;
-#define DUK_SMALL_INT_FAST_MIN DUK_INT_FAST16_MIN
-#define DUK_SMALL_INT_FAST_MAX DUK_INT_FAST16_MAX
-#define DUK_SMALL_UINT_FAST_MIN DUK_UINT_FAST16_MIN
-#define DUK_SMALL_UINT_FAST_MAX DUK_UINT_FAST16_MAX
-
-/* Boolean values are represented with the platform 'int'. */
-typedef duk_small_int_t duk_bool_t;
-#define DUK_BOOL_MIN DUK_SMALL_INT_MIN
-#define DUK_BOOL_MAX DUK_SMALL_INT_MAX
-
-/* Index values must have at least 32-bit signed range. */
-typedef duk_int_t duk_idx_t;
-#define DUK_IDX_MIN DUK_INT_MIN
-#define DUK_IDX_MAX DUK_INT_MAX
-
-/* Unsigned index variant. */
-typedef duk_uint_t duk_uidx_t;
-#define DUK_UIDX_MIN DUK_UINT_MIN
-#define DUK_UIDX_MAX DUK_UINT_MAX
-
-/* Array index values, could be exact 32 bits.
- * Currently no need for signed duk_arridx_t.
- */
-typedef duk_uint_t duk_uarridx_t;
-#define DUK_UARRIDX_MIN DUK_UINT_MIN
-#define DUK_UARRIDX_MAX DUK_UINT_MAX
-
-/* Duktape/C function return value, platform int is enough for now to
- * represent 0, 1, or negative error code. Must be compatible with
- * assigning truth values (e.g. duk_ret_t rc = (foo == bar);).
- */
-typedef duk_small_int_t duk_ret_t;
-#define DUK_RET_MIN DUK_SMALL_INT_MIN
-#define DUK_RET_MAX DUK_SMALL_INT_MAX
-
-/* Error codes are represented with platform int. High bits are used
- * for flags and such, so 32 bits are needed.
- */
-typedef duk_int_t duk_errcode_t;
-#define DUK_ERRCODE_MIN DUK_INT_MIN
-#define DUK_ERRCODE_MAX DUK_INT_MAX
-
-/* Codepoint type. Must be 32 bits or more because it is used also for
- * internal codepoints. The type is signed because negative codepoints
- * are used as internal markers (e.g. to mark EOF or missing argument).
- * (X)UTF-8/CESU-8 encode/decode take and return an unsigned variant to
- * ensure duk_uint32_t casts back and forth nicely. Almost everything
- * else uses the signed one.
- */
-typedef duk_int_t duk_codepoint_t;
-typedef duk_uint_t duk_ucodepoint_t;
-#define DUK_CODEPOINT_MIN DUK_INT_MIN
-#define DUK_CODEPOINT_MAX DUK_INT_MAX
-#define DUK_UCODEPOINT_MIN DUK_UINT_MIN
-#define DUK_UCODEPOINT_MAX DUK_UINT_MAX
-
-/* IEEE float/double typedef. */
-typedef float duk_float_t;
-typedef double duk_double_t;
-
-/* We're generally assuming that we're working on a platform with a 32-bit
- * address space. If DUK_SIZE_MAX is a typecast value (which is necessary
- * if SIZE_MAX is missing), the check must be avoided because the
- * preprocessor can't do a comparison.
- */
-#if !defined(DUK_SIZE_MAX)
-#error DUK_SIZE_MAX is undefined, probably missing SIZE_MAX
-#elif !defined(DUK_SIZE_MAX_COMPUTED)
-#if DUK_SIZE_MAX < 0xffffffffUL
-/* On some systems SIZE_MAX can be smaller than max unsigned 32-bit value
- * which seems incorrect if size_t is (at least) an unsigned 32-bit type.
- * However, it doesn't seem useful to error out compilation if this is the
- * case.
- */
-#endif
-#endif
-
-/* Type for public API calls. */
-typedef struct duk_hthread duk_context;
-
-/* Check whether we should use 64-bit integers or not.
- *
- * Quite incomplete now. Use 64-bit types if detected (C99 or other detection)
- * unless they are known to be unreliable. For instance, 64-bit types are
- * available on VBCC but seem to misbehave.
- */
-#if defined(DUK_F_HAVE_64BIT) && !defined(DUK_F_VBCC)
-#define DUK_USE_64BIT_OPS
-#else
-#undef DUK_USE_64BIT_OPS
-#endif
-
-/*
- * Fill-ins for platform, architecture, and compiler
- */
-
-#if !defined(DUK_SETJMP)
-#define DUK_JMPBUF_TYPE jmp_buf
-#define DUK_SETJMP(jb) setjmp((jb))
-#define DUK_LONGJMP(jb) longjmp((jb), 1)
-#endif
-
-#if 0
-/* sigsetjmp() alternative */
-#define DUK_JMPBUF_TYPE sigjmp_buf
-#define DUK_SETJMP(jb) sigsetjmp((jb))
-#define DUK_LONGJMP(jb) siglongjmp((jb), 1)
-#endif
-
-typedef FILE duk_file;
-#if !defined(DUK_STDIN)
-#define DUK_STDIN stdin
-#endif
-#if !defined(DUK_STDOUT)
-#define DUK_STDOUT stdout
-#endif
-#if !defined(DUK_STDERR)
-#define DUK_STDERR stderr
-#endif
-
-/* Special naming to avoid conflict with e.g. DUK_FREE() in duk_heap.h
- * (which is unfortunately named). May sometimes need replacement, e.g.
- * some compilers don't handle zero length or NULL correctly in realloc().
- */
-#if !defined(DUK_ANSI_MALLOC)
-#define DUK_ANSI_MALLOC malloc
-#endif
-#if !defined(DUK_ANSI_REALLOC)
-#define DUK_ANSI_REALLOC realloc
-#endif
-#if !defined(DUK_ANSI_CALLOC)
-#define DUK_ANSI_CALLOC calloc
-#endif
-#if !defined(DUK_ANSI_FREE)
-#define DUK_ANSI_FREE free
-#endif
-
-/* ANSI C (various versions) and some implementations require that the
- * pointer arguments to memset(), memcpy(), and memmove() be valid values
- * even when byte size is 0 (even a NULL pointer is considered invalid in
- * this context). Zero-size operations as such are allowed, as long as their
- * pointer arguments point to a valid memory area. The DUK_MEMSET(),
- * DUK_MEMCPY(), and DUK_MEMMOVE() macros require this same behavior, i.e.:
- * (1) pointers must be valid and non-NULL, (2) zero size must otherwise be
- * allowed. If these are not fulfilled, a macro wrapper is needed.
- *
- * http://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0
- * http://lists.cs.uiuc.edu/pipermail/llvmdev/2007-October/011065.html
- *
- * Not sure what's the required behavior when a pointer points just past the
- * end of a buffer, which often happens in practice (e.g. zero size memmoves).
- * For example, if allocation size is 3, the following pointer would not
- * technically point to a valid memory byte:
- *
- * <-- alloc -->
- * | 0 | 1 | 2 | .....
- * ^-- p=3, points after last valid byte (2)
- */
-#if !defined(DUK_MEMCPY)
-#if defined(DUK_F_UCLIBC)
-/* Old uclibcs have a broken memcpy so use memmove instead (this is overly wide
- * now on purpose): http://lists.uclibc.org/pipermail/uclibc-cvs/2008-October/025511.html
- */
-#define DUK_MEMCPY memmove
-#else
-#define DUK_MEMCPY memcpy
-#endif
-#endif
-#if !defined(DUK_MEMMOVE)
-#define DUK_MEMMOVE memmove
-#endif
-#if !defined(DUK_MEMCMP)
-#define DUK_MEMCMP memcmp
-#endif
-#if !defined(DUK_MEMSET)
-#define DUK_MEMSET memset
-#endif
-#if !defined(DUK_STRLEN)
-#define DUK_STRLEN strlen
-#endif
-#if !defined(DUK_STRCMP)
-#define DUK_STRCMP strcmp
-#endif
-#if !defined(DUK_STRNCMP)
-#define DUK_STRNCMP strncmp
-#endif
-#if !defined(DUK_PRINTF)
-#define DUK_PRINTF printf
-#endif
-#if !defined(DUK_FPRINTF)
-#define DUK_FPRINTF fprintf
-#endif
-#if !defined(DUK_SPRINTF)
-#define DUK_SPRINTF sprintf
-#endif
-#if !defined(DUK_SNPRINTF)
-/* snprintf() is technically not part of C89 but usually available. */
-#define DUK_SNPRINTF snprintf
-#endif
-#if !defined(DUK_VSPRINTF)
-#define DUK_VSPRINTF vsprintf
-#endif
-#if !defined(DUK_VSNPRINTF)
-/* vsnprintf() is technically not part of C89 but usually available. */
-#define DUK_VSNPRINTF vsnprintf
-#endif
-#if !defined(DUK_SSCANF)
-#define DUK_SSCANF sscanf
-#endif
-#if !defined(DUK_VSSCANF)
-#define DUK_VSSCANF vsscanf
-#endif
-#if !defined(DUK_FOPEN)
-#define DUK_FOPEN fopen
-#endif
-#if !defined(DUK_FCLOSE)
-#define DUK_FCLOSE fclose
-#endif
-#if !defined(DUK_FREAD)
-#define DUK_FREAD fread
-#endif
-#if !defined(DUK_FWRITE)
-#define DUK_FWRITE fwrite
-#endif
-#if !defined(DUK_FSEEK)
-#define DUK_FSEEK fseek
-#endif
-#if !defined(DUK_FTELL)
-#define DUK_FTELL ftell
-#endif
-#if !defined(DUK_FFLUSH)
-#define DUK_FFLUSH fflush
-#endif
-#if !defined(DUK_FPUTC)
-#define DUK_FPUTC fputc
-#endif
-#if !defined(DUK_MEMZERO)
-#define DUK_MEMZERO(p,n) DUK_MEMSET((p), 0, (n))
-#endif
-#if !defined(DUK_ABORT)
-#define DUK_ABORT abort
-#endif
-#if !defined(DUK_EXIT)
-#define DUK_EXIT exit
-#endif
-
-#if !defined(DUK_DOUBLE_2TO32)
-#define DUK_DOUBLE_2TO32 4294967296.0
-#endif
-#if !defined(DUK_DOUBLE_2TO31)
-#define DUK_DOUBLE_2TO31 2147483648.0
-#endif
-
-#if !defined(DUK_DOUBLE_INFINITY)
-#undef DUK_USE_COMPUTED_INFINITY
-#if defined(DUK_F_GCC_VERSION) && (DUK_F_GCC_VERSION < 40600)
-/* GCC older than 4.6: avoid overflow warnings related to using INFINITY */
-#define DUK_DOUBLE_INFINITY (__builtin_inf())
-#elif defined(INFINITY)
-#define DUK_DOUBLE_INFINITY ((double) INFINITY)
-#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC)
-#define DUK_DOUBLE_INFINITY (1.0 / 0.0)
-#else
-/* In VBCC (1.0 / 0.0) results in a warning and 0.0 instead of infinity.
- * Use a computed infinity (initialized when a heap is created at the
- * latest).
- */
-#define DUK_USE_COMPUTED_INFINITY
-#define DUK_DOUBLE_INFINITY duk_computed_infinity
-#endif
-#endif
-
-#if !defined(DUK_DOUBLE_NAN)
-#undef DUK_USE_COMPUTED_NAN
-#if defined(NAN)
-#define DUK_DOUBLE_NAN NAN
-#elif !defined(DUK_F_VBCC) && !defined(DUK_F_MSVC) && !defined(DUK_F_BCC)
-#define DUK_DOUBLE_NAN (0.0 / 0.0)
-#else
-/* In VBCC (0.0 / 0.0) results in a warning and 0.0 instead of NaN.
- * In MSVC (VS2010 Express) (0.0 / 0.0) results in a compile error.
- * Use a computed NaN (initialized when a heap is created at the
- * latest).
- */
-#define DUK_USE_COMPUTED_NAN
-#define DUK_DOUBLE_NAN duk_computed_nan
-#endif
-#endif
-
-/* Many platforms are missing fpclassify() and friends, so use replacements
- * if necessary. The replacement constants (FP_NAN etc) can be anything but
- * match Linux constants now.
- */
-#undef DUK_USE_REPL_FPCLASSIFY
-#undef DUK_USE_REPL_SIGNBIT
-#undef DUK_USE_REPL_ISFINITE
-#undef DUK_USE_REPL_ISNAN
-#undef DUK_USE_REPL_ISINF
-
-/* Complex condition broken into separate parts. */
-#undef DUK_F_USE_REPL_ALL
-#if !(defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO) && \
- defined(FP_SUBNORMAL) && defined(FP_NORMAL))
-/* Missing some obvious constants. */
-#define DUK_F_USE_REPL_ALL
-#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)
-/* VBCC is missing the built-ins even in C99 mode (perhaps a header issue) */
-#define DUK_F_USE_REPL_ALL
-#elif defined(DUK_F_FREEBSD) && defined(DUK_F_CLANG)
-/* Placeholder fix for (detection is wider than necessary):
- * http://llvm.org/bugs/show_bug.cgi?id=17788
- */
-#define DUK_F_USE_REPL_ALL
-#elif defined(DUK_F_UCLIBC)
-/* At least some uclibc versions have broken floating point math. For
- * example, fpclassify() can incorrectly classify certain NaN formats.
- * To be safe, use replacements.
- */
-#define DUK_F_USE_REPL_ALL
-#endif
-
-#if defined(DUK_F_USE_REPL_ALL)
-#define DUK_USE_REPL_FPCLASSIFY
-#define DUK_USE_REPL_SIGNBIT
-#define DUK_USE_REPL_ISFINITE
-#define DUK_USE_REPL_ISNAN
-#define DUK_USE_REPL_ISINF
-#define DUK_FPCLASSIFY duk_repl_fpclassify
-#define DUK_SIGNBIT duk_repl_signbit
-#define DUK_ISFINITE duk_repl_isfinite
-#define DUK_ISNAN duk_repl_isnan
-#define DUK_ISINF duk_repl_isinf
-#define DUK_FP_NAN 0
-#define DUK_FP_INFINITE 1
-#define DUK_FP_ZERO 2
-#define DUK_FP_SUBNORMAL 3
-#define DUK_FP_NORMAL 4
-#else
-#define DUK_FPCLASSIFY fpclassify
-#define DUK_SIGNBIT signbit
-#define DUK_ISFINITE isfinite
-#define DUK_ISNAN isnan
-#define DUK_ISINF isinf
-#define DUK_FP_NAN FP_NAN
-#define DUK_FP_INFINITE FP_INFINITE
-#define DUK_FP_ZERO FP_ZERO
-#define DUK_FP_SUBNORMAL FP_SUBNORMAL
-#define DUK_FP_NORMAL FP_NORMAL
-#endif
-
-#if defined(DUK_F_USE_REPL_ALL)
-#undef DUK_F_USE_REPL_ALL
-#endif
-
-/* Some math functions are C99 only. This is also an issue with some
- * embedded environments using uclibc where uclibc has been configured
- * not to provide some functions. For now, use replacements whenever
- * using uclibc.
- */
-#undef DUK_USE_MATH_FMIN
-#undef DUK_USE_MATH_FMAX
-#undef DUK_USE_MATH_ROUND
-#if defined(DUK_F_UCLIBC)
-/* uclibc may be missing these */
-#elif defined(DUK_F_AMIGAOS) && defined(DUK_F_VBCC)
-/* vbcc + AmigaOS may be missing these */
-#elif defined(DUK_F_MINT)
-/* mint clib is missing these */
-#elif !defined(DUK_F_C99) && !defined(DUK_F_CPP11)
-/* build is not C99 or C++11, play it safe */
-#else
-/* C99 or C++11, no known issues */
-#define DUK_USE_MATH_FMIN
-#define DUK_USE_MATH_FMAX
-#define DUK_USE_MATH_ROUND
-#endif
-
-/* These functions don't currently need replacement but are wrapped for
- * completeness. Because these are used as function pointers, they need
- * to be defined as concrete C functions (not macros).
- */
-#if !defined(DUK_FABS)
-#define DUK_FABS fabs
-#endif
-#if !defined(DUK_FMIN)
-#define DUK_FMIN fmin
-#endif
-#if !defined(DUK_FMAX)
-#define DUK_FMAX fmax
-#endif
-#if !defined(DUK_FLOOR)
-#define DUK_FLOOR floor
-#endif
-#if !defined(DUK_CEIL)
-#define DUK_CEIL ceil
-#endif
-#if !defined(DUK_FMOD)
-#define DUK_FMOD fmod
-#endif
-#if !defined(DUK_POW)
-#define DUK_POW pow
-#endif
-#if !defined(DUK_ACOS)
-#define DUK_ACOS acos
-#endif
-#if !defined(DUK_ASIN)
-#define DUK_ASIN asin
-#endif
-#if !defined(DUK_ATAN)
-#define DUK_ATAN atan
-#endif
-#if !defined(DUK_ATAN2)
-#define DUK_ATAN2 atan2
-#endif
-#if !defined(DUK_SIN)
-#define DUK_SIN sin
-#endif
-#if !defined(DUK_COS)
-#define DUK_COS cos
-#endif
-#if !defined(DUK_TAN)
-#define DUK_TAN tan
-#endif
-#if !defined(DUK_EXP)
-#define DUK_EXP exp
-#endif
-#if !defined(DUK_LOG)
-#define DUK_LOG log
-#endif
-#if !defined(DUK_SQRT)
-#define DUK_SQRT sqrt
-#endif
-
-/* NetBSD 6.0 x86 (at least) has a few problems with pow() semantics,
- * see test-bug-netbsd-math-pow.js. Use NetBSD specific workaround.
- * (This might be a wider problem; if so, generalize the define name.)
- */
-#undef DUK_USE_POW_NETBSD_WORKAROUND
-#if defined(DUK_F_NETBSD)
-#define DUK_USE_POW_NETBSD_WORKAROUND
-#endif
-
-/* Rely as little as possible on compiler behavior for NaN comparison,
- * signed zero handling, etc. Currently never activated but may be needed
- * for broken compilers.
- */
-#undef DUK_USE_PARANOID_MATH
-
-/* There was a curious bug where test-bi-date-canceling.js would fail e.g.
- * on 64-bit Ubuntu, gcc-4.8.1, -m32, and no -std=c99. Some date computations
- * using doubles would be optimized which then broke some corner case tests.
- * The problem goes away by adding 'volatile' to the datetime computations.
- * Not sure what the actual triggering conditions are, but using this on
- * non-C99 systems solves the known issues and has relatively little cost
- * on other platforms.
- */
-#undef DUK_USE_PARANOID_DATE_COMPUTATION
-#if !defined(DUK_F_C99)
-#define DUK_USE_PARANOID_DATE_COMPUTATION
-#endif
-
-/*
- * Byte order and double memory layout detection
- *
- * Endianness detection is a major portability hassle because the macros
- * and headers are not standardized. There's even variance across UNIX
- * platforms. Even with "standard" headers, details like underscore count
- * varies between platforms, e.g. both __BYTE_ORDER and _BYTE_ORDER are used
- * (Crossbridge has a single underscore, for instance).
- *
- * The checks below are structured with this in mind: several approaches are
- * used, and at the end we check if any of them worked. This allows generic
- * approaches to be tried first, and platform/compiler specific hacks tried
- * last. As a last resort, the user can force a specific endianness, as it's
- * not likely that automatic detection will work on the most exotic platforms.
- *
- * Duktape supports little and big endian machines. There's also support
- * for a hybrid used by some ARM machines where integers are little endian
- * but IEEE double values use a mixed order (12345678 -> 43218765). This
- * byte order for doubles is referred to as "mixed endian".
- */
-
-/* For custom platforms allow user to define byteorder explicitly.
- * Since endianness headers are not standardized, this is a useful
- * workaround for custom platforms for which endianness detection
- * is not directly supported. Perhaps custom hardware is used and
- * user cannot submit upstream patches.
- */
-#if defined(DUK_OPT_FORCE_BYTEORDER)
-#undef DUK_USE_BYTEORDER
-#if (DUK_OPT_FORCE_BYTEORDER == 1)
-#define DUK_USE_BYTEORDER 1
-#elif (DUK_OPT_FORCE_BYTEORDER == 2)
-#define DUK_USE_BYTEORDER 2
-#elif (DUK_OPT_FORCE_BYTEORDER == 3)
-#define DUK_USE_BYTEORDER 3
-#else
-#error invalid DUK_OPT_FORCE_BYTEORDER value
-#endif
-#endif /* DUK_OPT_FORCE_BYTEORDER */
-
-/* GCC and Clang provide endianness defines as built-in predefines, with
- * leading and trailing double underscores (e.g. __BYTE_ORDER__). See
- * output of "make gccpredefs" and "make clangpredefs". Clang doesn't
- * seem to provide __FLOAT_WORD_ORDER__; assume not mixed endian for clang.
- * http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
- */
-#if !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__)
-#if defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-#define DUK_USE_BYTEORDER 1
-#elif defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
-#define DUK_USE_BYTEORDER 2
-#elif !defined(__FLOAT_WORD_ORDER__)
-/* Float word order not known, assume not a hybrid. */
-#define DUK_USE_BYTEORDER 1
-#else
-/* Byte order is little endian but cannot determine IEEE double word order. */
-#endif /* float word order */
-#elif defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
-#if defined(__FLOAT_WORD_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
-#define DUK_USE_BYTEORDER 3
-#elif !defined(__FLOAT_WORD_ORDER__)
-/* Float word order not known, assume not a hybrid. */
-#define DUK_USE_BYTEORDER 3
-#else
-/* Byte order is big endian but cannot determine IEEE double word order. */
-#endif /* float word order */
-#else
-/* Cannot determine byte order; __ORDER_PDP_ENDIAN__ is related to 32-bit
- * integer ordering and is not relevant.
- */
-#endif /* integer byte order */
-#endif /* !defined(DUK_USE_BYTEORDER) && defined(__BYTE_ORDER__) */
-
-/* More or less standard endianness predefines provided by header files.
- * The ARM hybrid case is detected by assuming that __FLOAT_WORD_ORDER
- * will be big endian, see: http://lists.mysql.com/internals/443.
- * On some platforms some defines may be present with an empty value which
- * causes comparisons to fail: https://github.com/svaarala/duktape/issues/453.
- */
-#if !defined(DUK_USE_BYTEORDER)
-#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN) || \
- defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && (_BYTE_ORDER == _LITTLE_ENDIAN) || \
- defined(__LITTLE_ENDIAN__)
-#if defined(__FLOAT_WORD_ORDER) && defined(__LITTLE_ENDIAN) && (__FLOAT_WORD_ORDER == __LITTLE_ENDIAN) || \
- defined(_FLOAT_WORD_ORDER) && defined(_LITTLE_ENDIAN) && (_FLOAT_WORD_ORDER == _LITTLE_ENDIAN)
-#define DUK_USE_BYTEORDER 1
-#elif defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \
- defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN)
-#define DUK_USE_BYTEORDER 2
-#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER)
-/* Float word order not known, assume not a hybrid. */
-#define DUK_USE_BYTEORDER 1
-#else
-/* Byte order is little endian but cannot determine IEEE double word order. */
-#endif /* float word order */
-#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) || \
- defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && (_BYTE_ORDER == _BIG_ENDIAN) || \
- defined(__BIG_ENDIAN__)
-#if defined(__FLOAT_WORD_ORDER) && defined(__BIG_ENDIAN) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) || \
- defined(_FLOAT_WORD_ORDER) && defined(_BIG_ENDIAN) && (_FLOAT_WORD_ORDER == _BIG_ENDIAN)
-#define DUK_USE_BYTEORDER 3
-#elif !defined(__FLOAT_WORD_ORDER) && !defined(_FLOAT_WORD_ORDER)
-/* Float word order not known, assume not a hybrid. */
-#define DUK_USE_BYTEORDER 3
-#else
-/* Byte order is big endian but cannot determine IEEE double word order. */
-#endif /* float word order */
-#else
-/* Cannot determine byte order. */
-#endif /* integer byte order */
-#endif /* !defined(DUK_USE_BYTEORDER) */
-
-/* QNX gcc cross compiler seems to define e.g. __LITTLEENDIAN__ or __BIGENDIAN__:
- * $ /opt/qnx650/host/linux/x86/usr/bin/i486-pc-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian
- * 67:#define __LITTLEENDIAN__ 1
- * $ /opt/qnx650/host/linux/x86/usr/bin/mips-unknown-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian
- * 81:#define __BIGENDIAN__ 1
- * $ /opt/qnx650/host/linux/x86/usr/bin/arm-unknown-nto-qnx6.5.0-gcc -dM -E - </dev/null | grep -ni endian
- * 70:#define __LITTLEENDIAN__ 1
- */
-#if !defined(DUK_USE_BYTEORDER)
-#if defined(__LITTLEENDIAN__)
-#define DUK_USE_BYTEORDER 1
-#elif defined(__BIGENDIAN__)
-#define DUK_USE_BYTEORDER 3
-#endif
-#endif
-
-/*
- * Alignment requirement and support for unaligned accesses
- *
- * Assume unaligned accesses are not supported unless specifically allowed
- * in the target platform. Some platforms may support unaligned accesses
- * but alignment to 4 or 8 may still be desirable.
- */
-
-/* If not provided, use safe default for alignment. */
-#if !defined(DUK_USE_ALIGN_BY)
-#define DUK_USE_ALIGN_BY 8
-#endif
-
-/* User forced alignment to 4 or 8. */
-#if defined(DUK_OPT_FORCE_ALIGN)
-#undef DUK_USE_ALIGN_BY
-#if (DUK_OPT_FORCE_ALIGN == 4)
-#define DUK_USE_ALIGN_BY 4
-#elif (DUK_OPT_FORCE_ALIGN == 8)
-#define DUK_USE_ALIGN_BY 8
-#else
-#error invalid DUK_OPT_FORCE_ALIGN value
-#endif
-#endif
-
-/* Compiler specific hackery needed to force struct size to match aligment,
- * see e.g. duk_hbuffer.h.
- *
- * http://stackoverflow.com/questions/11130109/c-struct-size-alignment
- * http://stackoverflow.com/questions/10951039/specifying-64-bit-alignment
- */
-#if !(defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_GCC_ATTR) || \
- defined(DUK_USE_PACK_CLANG_ATTR) || defined(DUK_USE_PACK_DUMMY_MEMBER))
-#define DUK_USE_PACK_DUMMY_MEMBER
-#endif
-
-#if !defined(DUK_VA_COPY)
-/* We need va_copy() which is defined in C99 / C++11, so an awkward
- * replacement is needed for pre-C99 / pre-C++11 environments. This
- * will quite likely need portability hacks for some non-C99
- * environments.
- */
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-/* C99 / C++11 and above: rely on va_copy() which is required.
- * Omit parenthesis on macro right side on purpose to minimize differences
- * to direct use.
- */
-#define DUK_VA_COPY(dest,src) va_copy(dest,src)
-#else
-/* Pre-C99: va_list type is implementation dependent. This replacement
- * assumes it is a plain value so that a simple assignment will work.
- * This is not the case on all platforms (it may be a single-array element,
- * for instance).
- */
-#define DUK_VA_COPY(dest,src) do { (dest) = (src); } while (0)
-#endif
-#endif
-
-#if !defined(DUK_MACRO_STRINGIFY)
-/* Macro hackery to convert e.g. __LINE__ to a string without formatting,
- * see: http://stackoverflow.com/questions/240353/convert-a-preprocessor-token-to-a-string
- */
-#define DUK_MACRO_STRINGIFY_HELPER(x) #x
-#define DUK_MACRO_STRINGIFY(x) DUK_MACRO_STRINGIFY_HELPER(x)
-#endif
-
-#if !defined(DUK_CAUSE_SEGFAULT)
-/* This is optionally used by panic handling to cause the program to segfault
- * (instead of e.g. abort()) on panic. Valgrind will then indicate the C
- * call stack leading to the panic.
- */
-#define DUK_CAUSE_SEGFAULT() do { *((volatile duk_uint32_t *) NULL) = (duk_uint32_t) 0xdeadbeefUL; } while (0)
-#endif
-#if !defined(DUK_UNREF)
-/* Macro for suppressing warnings for potentially unreferenced variables.
- * The variables can be actually unreferenced or unreferenced in some
- * specific cases only; for instance, if a variable is only debug printed,
- * it is unreferenced when debug printing is disabled.
- */
-#define DUK_UNREF(x) do { (void) (x); } while (0)
-#endif
-#if !defined(DUK_NORETURN)
-#define DUK_NORETURN(decl) decl
-#endif
-#if !defined(DUK_UNREACHABLE)
-/* Don't know how to declare unreachable point, so don't do it; this
- * may cause some spurious compilation warnings (e.g. "variable used
- * uninitialized").
- */
-#define DUK_UNREACHABLE() do { } while (0)
-#endif
-#if !defined(DUK_LOSE_CONST)
-/* Convert any input pointer into a "void *", losing a const qualifier.
- * This is not fully portable because casting through duk_uintptr_t may
- * not work on all architectures (e.g. those with long, segmented pointers).
- */
-#define DUK_LOSE_CONST(src) ((void *) (duk_uintptr_t) (src))
-#endif
-
-#if !defined(DUK_LIKELY)
-#define DUK_LIKELY(x) (x)
-#endif
-#if !defined(DUK_UNLIKELY)
-#define DUK_UNLIKELY(x) (x)
-#endif
-
-#if !defined(DUK_NOINLINE)
-#define DUK_NOINLINE /*nop*/
-#endif
-#if !defined(DUK_INLINE)
-#define DUK_INLINE /*nop*/
-#endif
-#if !defined(DUK_ALWAYS_INLINE)
-#define DUK_ALWAYS_INLINE /*nop*/
-#endif
-
-#if !defined(DUK_EXTERNAL_DECL)
-#define DUK_EXTERNAL_DECL extern
-#endif
-#if !defined(DUK_EXTERNAL)
-#define DUK_EXTERNAL /*empty*/
-#endif
-#if !defined(DUK_INTERNAL_DECL)
-#if defined(DUK_SINGLE_FILE)
-#define DUK_INTERNAL_DECL static
-#else
-#define DUK_INTERNAL_DECL extern
-#endif
-#endif
-#if !defined(DUK_INTERNAL)
-#if defined(DUK_SINGLE_FILE)
-#define DUK_INTERNAL static
-#else
-#define DUK_INTERNAL /*empty*/
-#endif
-#endif
-#if !defined(DUK_LOCAL_DECL)
-#define DUK_LOCAL_DECL static
-#endif
-#if !defined(DUK_LOCAL)
-#define DUK_LOCAL static
-#endif
-
-#if !defined(DUK_FILE_MACRO)
-#define DUK_FILE_MACRO __FILE__
-#endif
-#if !defined(DUK_LINE_MACRO)
-#define DUK_LINE_MACRO __LINE__
-#endif
-#if !defined(DUK_FUNC_MACRO)
-#if defined(DUK_F_C99) || defined(DUK_F_CPP11)
-#define DUK_FUNC_MACRO __func__
-#elif defined(__FUNCTION__)
-#define DUK_FUNC_MACRO __FUNCTION__
-#else
-#define DUK_FUNC_MACRO "unknown"
-#endif
-#endif
-
-#if !defined(DUK_BSWAP32)
-#define DUK_BSWAP32(x) \
- ((((duk_uint32_t) (x)) >> 24) | \
- ((((duk_uint32_t) (x)) >> 8) & 0xff00UL) | \
- ((((duk_uint32_t) (x)) << 8) & 0xff0000UL) | \
- (((duk_uint32_t) (x)) << 24))
-#endif
-#if !defined(DUK_BSWAP16)
-#define DUK_BSWAP16(x) \
- ((duk_uint16_t) (x) >> 8) | \
- ((duk_uint16_t) (x) << 8)
-#endif
-
-/* DUK_USE_VARIADIC_MACROS: required from compilers, so no fill-in. */
-/* DUK_USE_UNION_INITIALIZERS: required from compilers, so no fill-in. */
-
-#if !(defined(DUK_USE_FLEX_C99) || defined(DUK_USE_FLEX_ZEROSIZE) || defined(DUK_USE_FLEX_ONESIZE))
-#if defined(DUK_F_C99)
-#define DUK_USE_FLEX_C99
-#else
-#define DUK_USE_FLEX_ZEROSIZE /* Not standard but common enough */
-#endif
-#endif
-
-#if !(defined(DUK_USE_PACK_GCC_ATTR) || defined(DUK_USE_PACK_CLANG_ATTR) || \
- defined(DUK_USE_PACK_MSVC_PRAGMA) || defined(DUK_USE_PACK_DUMMY_MEMBER))
-#define DUK_USE_PACK_DUMMY_MEMBER
-#endif
-
-#if 0 /* not defined by default */
-#undef DUK_USE_GCC_PRAGMAS
-#endif
-
-/* Workaround for GH-323: avoid inlining control when compiling from
- * multiple sources, as it causes compiler portability trouble.
- */
-#if !defined(DUK_SINGLE_FILE)
-#undef DUK_NOINLINE
-#undef DUK_INLINE
-#undef DUK_ALWAYS_INLINE
-#define DUK_NOINLINE /*nop*/
-#define DUK_INLINE /*nop*/
-#define DUK_ALWAYS_INLINE /*nop*/
-#endif
-
-/*
- * Check whether or not a packed duk_tval representation is possible.
- * What's basically required is that pointers are 32-bit values
- * (sizeof(void *) == 4). Best effort check, not always accurate.
- * If guess goes wrong, crashes may result; self tests also verify
- * the guess.
- */
-
-/* Explicit marker needed; may be 'defined', 'undefined, 'or 'not provided'. */
-#if !defined(DUK_F_PACKED_TVAL_PROVIDED)
-#undef DUK_F_PACKED_TVAL_POSSIBLE
-
-/* Strict C99 case: DUK_UINTPTR_MAX (= UINTPTR_MAX) should be very reliable */
-#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX)
-#if (DUK_UINTPTR_MAX <= 0xffffffffUL)
-#define DUK_F_PACKED_TVAL_POSSIBLE
-#endif
-#endif
-
-/* Non-C99 case, still relying on DUK_UINTPTR_MAX, as long as it is not a computed value */
-#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_UINTPTR_MAX) && !defined(DUK_UINTPTR_MAX_COMPUTED)
-#if (DUK_UINTPTR_MAX <= 0xffffffffUL)
-#define DUK_F_PACKED_TVAL_POSSIBLE
-#endif
-#endif
-
-/* DUK_SIZE_MAX (= SIZE_MAX) is often reliable */
-#if !defined(DUK_F_PACKED_TVAL_POSSIBLE) && defined(DUK_SIZE_MAX) && !defined(DUK_SIZE_MAX_COMPUTED)
-#if (DUK_SIZE_MAX <= 0xffffffffUL)
-#define DUK_F_PACKED_TVAL_POSSIBLE
-#endif
-#endif
-
-#undef DUK_USE_PACKED_TVAL
-#if defined(DUK_F_PACKED_TVAL_POSSIBLE)
-#define DUK_USE_PACKED_TVAL
-#endif
-
-#undef DUK_F_PACKED_TVAL_POSSIBLE
-#endif /* DUK_F_PACKED_TVAL_PROVIDED */
-
-/* Feature option forcing. */
-#if defined(DUK_OPT_NO_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#elif defined(DUK_OPT_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#define DUK_USE_PACKED_TVAL
-#endif
-/* Object property allocation layout has implications for memory and code
- * footprint and generated code size/speed. The best layout also depends
- * on whether the platform has alignment requirements or benefits from
- * having mostly aligned accesses.
- */
-#undef DUK_USE_HOBJECT_LAYOUT_1
-#undef DUK_USE_HOBJECT_LAYOUT_2
-#undef DUK_USE_HOBJECT_LAYOUT_3
-#if (DUK_USE_ALIGN_BY == 1)
-/* On platforms without any alignment issues, layout 1 is preferable
- * because it compiles to slightly less code and provides direct access
- * to property keys.
- */
-#define DUK_USE_HOBJECT_LAYOUT_1
-#else
-/* On other platforms use layout 2, which requires some padding but
- * is a bit more natural than layout 3 in ordering the entries. Layout
- * 3 is currently not used.
- */
-#define DUK_USE_HOBJECT_LAYOUT_2
-#endif
-
-/* GCC/clang inaccurate math would break compliance and probably duk_tval,
- * so refuse to compile. Relax this if -ffast-math is tested to work.
- */
-#if defined(__FAST_MATH__)
-#error __FAST_MATH__ defined, refusing to compile
-#endif
-
-/*
- * Feature option handling
- */
-
-#if !defined(DUK_USE_ALIGN_BY)
-#if defined(DUK_OPT_FORCE_ALIGN)
-#define DUK_USE_ALIGN_BY DUK_OPT_FORCE_ALIGN
-#else
-#define DUK_USE_ALIGN_BY 8
-#endif
-#endif
-
-#if defined(DUK_OPT_ASSERTIONS)
-#define DUK_USE_ASSERTIONS
-#elif defined(DUK_OPT_NO_ASSERTIONS)
-#undef DUK_USE_ASSERTIONS
-#else
-#undef DUK_USE_ASSERTIONS
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_AUGMENT_ERROR_CREATE
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_AUGMENT_ERROR_CREATE
-#else
-#define DUK_USE_AUGMENT_ERROR_CREATE
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_AUGMENT_ERROR_THROW
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_AUGMENT_ERROR_THROW
-#else
-#define DUK_USE_AUGMENT_ERROR_THROW
-#endif
-
-#if defined(DUK_OPT_BROWSER_LIKE)
-#define DUK_USE_BROWSER_LIKE
-#elif defined(DUK_OPT_NO_BROWSER_LIKE)
-#undef DUK_USE_BROWSER_LIKE
-#else
-#define DUK_USE_BROWSER_LIKE
-#endif
-
-#if defined(DUK_OPT_BUFFEROBJECT_SUPPORT)
-#define DUK_USE_BUFFEROBJECT_SUPPORT
-#elif defined(DUK_OPT_NO_BUFFEROBJECT_SUPPORT)
-#undef DUK_USE_BUFFEROBJECT_SUPPORT
-#else
-#define DUK_USE_BUFFEROBJECT_SUPPORT
-#endif
-
-#if defined(DUK_OPT_BUFLEN16)
-#define DUK_USE_BUFLEN16
-#elif defined(DUK_OPT_NO_BUFLEN16)
-#undef DUK_USE_BUFLEN16
-#else
-#undef DUK_USE_BUFLEN16
-#endif
-
-#if defined(DUK_OPT_BYTECODE_DUMP_SUPPORT)
-#define DUK_USE_BYTECODE_DUMP_SUPPORT
-#elif defined(DUK_OPT_NO_BYTECODE_DUMP_SUPPORT)
-#undef DUK_USE_BYTECODE_DUMP_SUPPORT
-#else
-#define DUK_USE_BYTECODE_DUMP_SUPPORT
-#endif
-
-#if defined(DUK_OPT_COMMONJS_MODULES)
-#define DUK_USE_COMMONJS_MODULES
-#elif defined(DUK_OPT_NO_COMMONJS_MODULES)
-#undef DUK_USE_COMMONJS_MODULES
-#else
-#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)
-#undef DUK_USE_DATAPTR16
-#else
-#undef DUK_USE_DATAPTR16
-#endif
-
-#if defined(DUK_OPT_DATAPTR_DEC16)
-#define DUK_USE_DATAPTR_DEC16(udata,ptr) DUK_OPT_DATAPTR_DEC16((udata),(ptr))
-#else
-#undef DUK_USE_DATAPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_DATAPTR_ENC16)
-#define DUK_USE_DATAPTR_ENC16(udata,ptr) DUK_OPT_DATAPTR_ENC16((udata),(ptr))
-#else
-#undef DUK_USE_DATAPTR_ENC16
-#endif
-
-#if defined(DUK_OPT_DDDPRINT)
-#define DUK_USE_DDDPRINT
-#elif defined(DUK_OPT_NO_DDDPRINT)
-#undef DUK_USE_DDDPRINT
-#else
-#undef DUK_USE_DDDPRINT
-#endif
-
-#if defined(DUK_OPT_DDPRINT)
-#define DUK_USE_DDPRINT
-#elif defined(DUK_OPT_NO_DDPRINT)
-#undef DUK_USE_DDPRINT
-#else
-#undef DUK_USE_DDPRINT
-#endif
-
-#if defined(DUK_OPT_DEBUG)
-#define DUK_USE_DEBUG
-#elif defined(DUK_OPT_NO_DEBUG)
-#undef DUK_USE_DEBUG
-#else
-#undef DUK_USE_DEBUG
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_DUMPHEAP)
-#define DUK_USE_DEBUGGER_DUMPHEAP
-#elif defined(DUK_OPT_NO_DEBUGGER_DUMPHEAP)
-#undef DUK_USE_DEBUGGER_DUMPHEAP
-#else
-#undef DUK_USE_DEBUGGER_DUMPHEAP
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_FWD_LOGGING)
-#define DUK_USE_DEBUGGER_FWD_LOGGING
-#elif defined(DUK_OPT_NO_DEBUGGER_FWD_LOGGING)
-#undef DUK_USE_DEBUGGER_FWD_LOGGING
-#else
-#undef DUK_USE_DEBUGGER_FWD_LOGGING
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_FWD_PRINTALERT)
-#define DUK_USE_DEBUGGER_FWD_PRINTALERT
-#elif defined(DUK_OPT_NO_DEBUGGER_FWD_PRINTALERT)
-#undef DUK_USE_DEBUGGER_FWD_PRINTALERT
-#else
-#undef DUK_USE_DEBUGGER_FWD_PRINTALERT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_INSPECT)
-#define DUK_USE_DEBUGGER_INSPECT
-#elif defined(DUK_OPT_NO_DEBUGGER_INSPECT)
-#undef DUK_USE_DEBUGGER_INSPECT
-#else
-#undef DUK_USE_DEBUGGER_INSPECT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_PAUSE_UNCAUGHT)
-#define DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#elif defined(DUK_OPT_NO_DEBUGGER_PAUSE_UNCAUGHT)
-#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#else
-#undef DUK_USE_DEBUGGER_PAUSE_UNCAUGHT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_SUPPORT)
-#define DUK_USE_DEBUGGER_SUPPORT
-#elif defined(DUK_OPT_NO_DEBUGGER_SUPPORT)
-#undef DUK_USE_DEBUGGER_SUPPORT
-#else
-#undef DUK_USE_DEBUGGER_SUPPORT
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_THROW_NOTIFY)
-#define DUK_USE_DEBUGGER_THROW_NOTIFY
-#elif defined(DUK_OPT_NO_DEBUGGER_THROW_NOTIFY)
-#undef DUK_USE_DEBUGGER_THROW_NOTIFY
-#else
-#define DUK_USE_DEBUGGER_THROW_NOTIFY
-#endif
-
-#if defined(DUK_OPT_DEBUGGER_TRANSPORT_TORTURE)
-#define DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#elif defined(DUK_OPT_NO_DEBUGGER_TRANSPORT_TORTURE)
-#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#else
-#undef DUK_USE_DEBUGGER_TRANSPORT_TORTURE
-#endif
-
-#if defined(DUK_OPT_DEBUG_BUFSIZE)
-#define DUK_USE_DEBUG_BUFSIZE DUK_OPT_DEBUG_BUFSIZE
-#else
-#define DUK_USE_DEBUG_BUFSIZE 65536L
-#endif
-
-#if defined(DUK_OPT_REFERENCE_COUNTING)
-#define DUK_USE_DOUBLE_LINKED_HEAP
-#elif defined(DUK_OPT_NO_REFERENCE_COUNTING)
-#undef DUK_USE_DOUBLE_LINKED_HEAP
-#else
-#define DUK_USE_DOUBLE_LINKED_HEAP
-#endif
-
-#if defined(DUK_OPT_DPRINT)
-#define DUK_USE_DPRINT
-#elif defined(DUK_OPT_NO_DPRINT)
-#undef DUK_USE_DPRINT
-#else
-#undef DUK_USE_DPRINT
-#endif
-
-#if defined(DUK_OPT_DPRINT_COLORS)
-#define DUK_USE_DPRINT_COLORS
-#elif defined(DUK_OPT_NO_DPRINT_COLORS)
-#undef DUK_USE_DPRINT_COLORS
-#else
-#undef DUK_USE_DPRINT_COLORS
-#endif
-
-#if defined(DUK_OPT_DPRINT_RDTSC)
-#define DUK_USE_DPRINT_RDTSC
-#elif defined(DUK_OPT_NO_DPRINT_RDTSC)
-#undef DUK_USE_DPRINT_RDTSC
-#else
-#undef DUK_USE_DPRINT_RDTSC
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_ERRCREATE
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_ERRCREATE
-#else
-#define DUK_USE_ERRCREATE
-#endif
-
-#if defined(DUK_OPT_AUGMENT_ERRORS)
-#define DUK_USE_ERRTHROW
-#elif defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_ERRTHROW
-#else
-#define DUK_USE_ERRTHROW
-#endif
-
-#if defined(DUK_OPT_ES6_OBJECT_PROTO_PROPERTY)
-#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#elif defined(DUK_OPT_NO_ES6_OBJECT_PROTO_PROPERTY)
-#undef DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#else
-#define DUK_USE_ES6_OBJECT_PROTO_PROPERTY
-#endif
-
-#if defined(DUK_OPT_ES6_OBJECT_SETPROTOTYPEOF)
-#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#elif defined(DUK_OPT_NO_ES6_OBJECT_SETPROTOTYPEOF)
-#undef DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#else
-#define DUK_USE_ES6_OBJECT_SETPROTOTYPEOF
-#endif
-
-#if defined(DUK_OPT_ES6_PROXY)
-#define DUK_USE_ES6_PROXY
-#elif defined(DUK_OPT_NO_ES6_PROXY)
-#undef DUK_USE_ES6_PROXY
-#else
-#define DUK_USE_ES6_PROXY
-#endif
-
-#if defined(DUK_OPT_ES6_REGEXP_BRACES)
-#define DUK_USE_ES6_REGEXP_BRACES
-#elif defined(DUK_OPT_NO_ES6_REGEXP_BRACES)
-#undef DUK_USE_ES6_REGEXP_BRACES
-#else
-#define DUK_USE_ES6_REGEXP_BRACES
-#endif
-
-#undef DUK_USE_EXEC_INDIRECT_BOUND_CHECK
-#if defined(DUK_OPT_DEBUG) || defined(DUK_OPT_ASSERTIONS)
-/* Enabled with debug/assertions just so that any issues can be caught. */
-#define DUK_USE_EXEC_INDIRECT_BOUND_CHECK
-#endif
-
-#undef DUK_USE_EXEC_TIMEOUT_CHECK
-#if defined(DUK_OPT_EXEC_TIMEOUT_CHECK)
-#define DUK_USE_EXEC_TIMEOUT_CHECK(udata) DUK_OPT_EXEC_TIMEOUT_CHECK((udata))
-#endif
-
-#undef DUK_USE_EXTSTR_FREE
-#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_FREE)
-#define DUK_USE_EXTSTR_FREE(udata,ptr) DUK_OPT_EXTSTR_FREE((udata), (ptr))
-#endif
-
-#undef DUK_USE_EXTSTR_INTERN_CHECK
-#if defined(DUK_OPT_EXTERNAL_STRINGS) && defined(DUK_OPT_EXTSTR_INTERN_CHECK)
-#define DUK_USE_EXTSTR_INTERN_CHECK(udata,ptr,len) DUK_OPT_EXTSTR_INTERN_CHECK((udata), (ptr), (len))
-#endif
-
-/* Support for 48-bit signed integer duk_tval with transparent semantics. */
-#undef DUK_USE_FASTINT
-#if defined(DUK_OPT_FASTINT)
-#if !defined(DUK_F_HAVE_64BIT)
-#error DUK_OPT_FASTINT requires 64-bit integer type support at the moment
-#endif
-#define DUK_USE_FASTINT
-#endif
-
-#if defined(DUK_OPT_FILE_IO)
-#define DUK_USE_FILE_IO
-#elif defined(DUK_OPT_NO_FILE_IO)
-#undef DUK_USE_FILE_IO
-#else
-#define DUK_USE_FILE_IO
-#endif
-
-#if defined(DUK_OPT_FUNCPTR16)
-#define DUK_USE_FUNCPTR16
-#elif defined(DUK_OPT_NO_FUNCPTR16)
-#undef DUK_USE_FUNCPTR16
-#else
-#undef DUK_USE_FUNCPTR16
-#endif
-
-#if defined(DUK_OPT_FUNCPTR_DEC16)
-#define DUK_USE_FUNCPTR_DEC16(udata,ptr) DUK_OPT_FUNCPTR_DEC16((udata),(ptr))
-#else
-#undef DUK_USE_FUNCPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_FUNCPTR_ENC16)
-#define DUK_USE_FUNCPTR_ENC16(udata,ptr) DUK_OPT_FUNCPTR_ENC16((udata),(ptr))
-#else
-#undef DUK_USE_FUNCPTR_ENC16
-#endif
-
-#if defined(DUK_OPT_GC_TORTURE)
-#define DUK_USE_GC_TORTURE
-#elif defined(DUK_OPT_NO_GC_TORTURE)
-#undef DUK_USE_GC_TORTURE
-#else
-#undef DUK_USE_GC_TORTURE
-#endif
-
-#if defined(DUK_OPT_HEAPPTR16)
-#define DUK_USE_HEAPPTR16
-#elif defined(DUK_OPT_NO_HEAPPTR16)
-#undef DUK_USE_HEAPPTR16
-#else
-#undef DUK_USE_HEAPPTR16
-#endif
-
-#if defined(DUK_OPT_HEAPPTR_DEC16)
-#define DUK_USE_HEAPPTR_DEC16(udata,ptr) DUK_OPT_HEAPPTR_DEC16((udata),(ptr))
-#else
-#undef DUK_USE_HEAPPTR_DEC16
-#endif
-
-#if defined(DUK_OPT_HEAPPTR_ENC16)
-#define DUK_USE_HEAPPTR_ENC16(udata,ptr) DUK_OPT_HEAPPTR_ENC16((udata),(ptr))
-#else
-#undef DUK_USE_HEAPPTR_ENC16
-#endif
-
-/* For now, hash part is dropped if and only if 16-bit object fields are used. */
-#define DUK_USE_HOBJECT_HASH_PART
-#if defined(DUK_OPT_OBJSIZES16)
-#undef DUK_USE_HOBJECT_HASH_PART
-#endif
-
-#if defined(DUK_OPT_HSTRING_CLEN)
-#define DUK_USE_HSTRING_CLEN
-#elif defined(DUK_OPT_NO_HSTRING_CLEN)
-#undef DUK_USE_HSTRING_CLEN
-#else
-#define DUK_USE_HSTRING_CLEN
-#endif
-
-#if defined(DUK_OPT_EXTERNAL_STRINGS)
-#define DUK_USE_HSTRING_EXTDATA
-#elif defined(DUK_OPT_NO_EXTERNAL_STRINGS)
-#undef DUK_USE_HSTRING_EXTDATA
-#else
-#undef DUK_USE_HSTRING_EXTDATA
-#endif
-
-#if defined(DUK_OPT_INTERRUPT_COUNTER)
-#define DUK_USE_INTERRUPT_COUNTER
-#elif defined(DUK_OPT_NO_INTERRUPT_COUNTER)
-#undef DUK_USE_INTERRUPT_COUNTER
-#else
-#undef DUK_USE_INTERRUPT_COUNTER
-#endif
-
-#if defined(DUK_OPT_JC)
-#define DUK_USE_JC
-#elif defined(DUK_OPT_NO_JC)
-#undef DUK_USE_JC
-#else
-#define DUK_USE_JC
-#endif
-
-#if defined(DUK_OPT_JSON_STRINGIFY_FASTPATH)
-#define DUK_USE_JSON_STRINGIFY_FASTPATH
-#elif defined(DUK_OPT_NO_JSON_STRINGIFY_FASTPATH)
-#undef DUK_USE_JSON_STRINGIFY_FASTPATH
-#else
-#undef DUK_USE_JSON_STRINGIFY_FASTPATH
-#endif
-
-#if defined(DUK_OPT_JX)
-#define DUK_USE_JX
-#elif defined(DUK_OPT_NO_JX)
-#undef DUK_USE_JX
-#else
-#define DUK_USE_JX
-#endif
-
-#if defined(DUK_OPT_LIGHTFUNC_BUILTINS)
-#define DUK_USE_LIGHTFUNC_BUILTINS
-#elif defined(DUK_OPT_NO_LIGHTFUNC_BUILTINS)
-#undef DUK_USE_LIGHTFUNC_BUILTINS
-#else
-#undef DUK_USE_LIGHTFUNC_BUILTINS
-#endif
-
-#if defined(DUK_OPT_MARK_AND_SWEEP)
-#define DUK_USE_MARK_AND_SWEEP
-#elif defined(DUK_OPT_NO_MARK_AND_SWEEP)
-#undef DUK_USE_MARK_AND_SWEEP
-#else
-#define DUK_USE_MARK_AND_SWEEP
-#endif
-
-#if defined(DUK_OPT_MS_STRINGTABLE_RESIZE)
-#define DUK_USE_MS_STRINGTABLE_RESIZE
-#elif defined(DUK_OPT_NO_MS_STRINGTABLE_RESIZE)
-#undef DUK_USE_MS_STRINGTABLE_RESIZE
-#else
-#define DUK_USE_MS_STRINGTABLE_RESIZE
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_CONCAT_TRAILER)
-#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_CONCAT_TRAILER)
-#undef DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#else
-#define DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_MAP_TRAILER)
-#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_MAP_TRAILER)
-#undef DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#else
-#define DUK_USE_NONSTD_ARRAY_MAP_TRAILER
-#endif
-
-#if defined(DUK_OPT_NONSTD_ARRAY_SPLICE_DELCOUNT)
-#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#elif defined(DUK_OPT_NO_NONSTD_ARRAY_SPLICE_DELCOUNT)
-#undef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#else
-#define DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY)
-#define DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_CALLER_PROPERTY)
-#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#else
-#undef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_SOURCE_PROPERTY)
-#define DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_SOURCE_PROPERTY)
-#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#else
-#undef DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_STMT)
-#define DUK_USE_NONSTD_FUNC_STMT
-#elif defined(DUK_OPT_NO_NONSTD_FUNC_STMT)
-#undef DUK_USE_NONSTD_FUNC_STMT
-#else
-#define DUK_USE_NONSTD_FUNC_STMT
-#endif
-
-#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#undef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#else
-#define DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
-#endif
-
-#if defined(DUK_OPT_NONSTD_JSON_ESC_U2028_U2029)
-#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#elif defined(DUK_OPT_NO_NONSTD_JSON_ESC_U2028_U2029)
-#undef DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#else
-#define DUK_USE_NONSTD_JSON_ESC_U2028_U2029
-#endif
-
-#if defined(DUK_OPT_NONSTD_REGEXP_DOLLAR_ESCAPE)
-#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#elif defined(DUK_OPT_NO_NONSTD_REGEXP_DOLLAR_ESCAPE)
-#undef DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#else
-#define DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE
-#endif
-
-#if defined(DUK_OPT_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#elif defined(DUK_OPT_NO_NONSTD_ACCESSOR_KEY_ARGUMENT)
-#undef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#else
-#define DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
-#endif
-
-#if defined(DUK_OPT_NONSTD_STRING_FROMCHARCODE_32BIT)
-#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#elif defined(DUK_OPT_NO_NONSTD_STRING_FROMCHARCODE_32BIT)
-#undef DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#else
-#define DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT
-#endif
-
-#if defined(DUK_OPT_OBJSIZES16)
-#define DUK_USE_OBJSIZES16
-#elif defined(DUK_OPT_NO_OBJSIZES16)
-#undef DUK_USE_OBJSIZES16
-#else
-#undef DUK_USE_OBJSIZES16
-#endif
-
-#if defined(DUK_OPT_OCTAL_SUPPORT)
-#define DUK_USE_OCTAL_SUPPORT
-#elif defined(DUK_OPT_NO_OCTAL_SUPPORT)
-#undef DUK_USE_OCTAL_SUPPORT
-#else
-#define DUK_USE_OCTAL_SUPPORT
-#endif
-
-#if defined(DUK_OPT_PACKED_TVAL)
-#define DUK_USE_PACKED_TVAL
-#elif defined(DUK_OPT_NO_PACKED_TVAL)
-#undef DUK_USE_PACKED_TVAL
-#else
-/* Already provided above */
-#endif
-
-#undef DUK_USE_PANIC_ABORT
-#if !defined(DUK_OPT_SEGFAULT_ON_PANIC)
-#define DUK_USE_PANIC_ABORT
-#endif
-
-#undef DUK_USE_PANIC_HANDLER
-#if defined(DUK_OPT_PANIC_HANDLER)
-#define DUK_USE_PANIC_HANDLER(code,msg) DUK_OPT_PANIC_HANDLER((code),(msg))
-#endif
-
-#undef DUK_USE_PANIC_SEGFAULT
-#if defined(DUK_OPT_SEGFAULT_ON_PANIC)
-#define DUK_USE_PANIC_SEGFAULT
-#endif
-
-#if defined(DUK_OPT_PARANOID_ERRORS)
-#define DUK_USE_PARANOID_ERRORS
-#elif defined(DUK_OPT_NO_PARANOID_ERRORS)
-#undef DUK_USE_PARANOID_ERRORS
-#else
-#undef DUK_USE_PARANOID_ERRORS
-#endif
-
-#if defined(DUK_OPT_PC2LINE)
-#define DUK_USE_PC2LINE
-#elif defined(DUK_OPT_NO_PC2LINE)
-#undef DUK_USE_PC2LINE
-#else
-#define DUK_USE_PC2LINE
-#endif
-
-#if defined(DUK_OPT_REFCOUNT16)
-#define DUK_USE_REFCOUNT16
-#elif defined(DUK_OPT_NO_REFCOUNT16)
-#undef DUK_USE_REFCOUNT16
-#else
-#undef DUK_USE_REFCOUNT16
-#endif
-
-#if defined(DUK_OPT_REFERENCE_COUNTING)
-#define DUK_USE_REFERENCE_COUNTING
-#elif defined(DUK_OPT_NO_REFERENCE_COUNTING)
-#undef DUK_USE_REFERENCE_COUNTING
-#else
-#define DUK_USE_REFERENCE_COUNTING
-#endif
-
-#if defined(DUK_OPT_REGEXP_CANON_WORKAROUND)
-#define DUK_USE_REGEXP_CANON_WORKAROUND
-#elif defined(DUK_OPT_NO_REGEXP_CANON_WORKAROUND)
-#undef DUK_USE_REGEXP_CANON_WORKAROUND
-#else
-#undef DUK_USE_REGEXP_CANON_WORKAROUND
-#endif
-
-#if defined(DUK_OPT_REGEXP_SUPPORT)
-#define DUK_USE_REGEXP_SUPPORT
-#elif defined(DUK_OPT_NO_REGEXP_SUPPORT)
-#undef DUK_USE_REGEXP_SUPPORT
-#else
-#define DUK_USE_REGEXP_SUPPORT
-#endif
-
-#if defined(DUK_OPT_ROM_GLOBAL_CLONE)
-#define DUK_USE_ROM_GLOBAL_CLONE
-#elif defined(DUK_OPT_NO_ROM_GLOBAL_CLONE)
-#undef DUK_USE_ROM_GLOBAL_CLONE
-#else
-#undef DUK_USE_ROM_GLOBAL_CLONE
-#endif
-
-#if defined(DUK_OPT_ROM_GLOBAL_INHERIT)
-#define DUK_USE_ROM_GLOBAL_INHERIT
-#elif defined(DUK_OPT_NO_ROM_GLOBAL_INHERIT)
-#undef DUK_USE_ROM_GLOBAL_INHERIT
-#else
-#undef DUK_USE_ROM_GLOBAL_INHERIT
-#endif
-
-#if defined(DUK_OPT_ROM_OBJECTS)
-#define DUK_USE_ROM_OBJECTS
-#elif defined(DUK_OPT_NO_ROM_OBJECTS)
-#undef DUK_USE_ROM_OBJECTS
-#else
-#undef DUK_USE_ROM_OBJECTS
-#endif
-
-#if defined(DUK_OPT_ROM_STRINGS)
-#define DUK_USE_ROM_STRINGS
-#elif defined(DUK_OPT_NO_ROM_STRINGS)
-#undef DUK_USE_ROM_STRINGS
-#else
-#undef DUK_USE_ROM_STRINGS
-#endif
-
-#if defined(DUK_OPT_SECTION_B)
-#define DUK_USE_SECTION_B
-#elif defined(DUK_OPT_NO_SECTION_B)
-#undef DUK_USE_SECTION_B
-#else
-#define DUK_USE_SECTION_B
-#endif
-
-#if defined(DUK_OPT_SELF_TESTS)
-#define DUK_USE_SELF_TESTS
-#elif defined(DUK_OPT_NO_SELF_TESTS)
-#undef DUK_USE_SELF_TESTS
-#else
-#undef DUK_USE_SELF_TESTS
-#endif
-
-#if defined(DUK_OPT_SHUFFLE_TORTURE)
-#define DUK_USE_SHUFFLE_TORTURE
-#elif defined(DUK_OPT_NO_SHUFFLE_TORTURE)
-#undef DUK_USE_SHUFFLE_TORTURE
-#else
-#undef DUK_USE_SHUFFLE_TORTURE
-#endif
-
-#if defined(DUK_OPT_SOURCE_NONBMP)
-#define DUK_USE_SOURCE_NONBMP
-#elif defined(DUK_OPT_NO_SOURCE_NONBMP)
-#undef DUK_USE_SOURCE_NONBMP
-#else
-#define DUK_USE_SOURCE_NONBMP
-#endif
-
-#if defined(DUK_OPT_STRHASH16)
-#define DUK_USE_STRHASH16
-#elif defined(DUK_OPT_NO_STRHASH16)
-#undef DUK_USE_STRHASH16
-#else
-#undef DUK_USE_STRHASH16
-#endif
-
-#if defined(DUK_OPT_STRICT_DECL)
-#define DUK_USE_STRICT_DECL
-#elif defined(DUK_OPT_NO_STRICT_DECL)
-#undef DUK_USE_STRICT_DECL
-#else
-#define DUK_USE_STRICT_DECL
-#endif
-
-#if defined(DUK_OPT_STRICT_UTF8_SOURCE)
-#define DUK_USE_STRICT_UTF8_SOURCE
-#elif defined(DUK_OPT_NO_STRICT_UTF8_SOURCE)
-#undef DUK_USE_STRICT_UTF8_SOURCE
-#else
-#undef DUK_USE_STRICT_UTF8_SOURCE
-#endif
-
-#if defined(DUK_OPT_STRLEN16)
-#define DUK_USE_STRLEN16
-#elif defined(DUK_OPT_NO_STRLEN16)
-#undef DUK_USE_STRLEN16
-#else
-#undef DUK_USE_STRLEN16
-#endif
-
-#undef DUK_USE_STRTAB_CHAIN
-#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)
-#define DUK_USE_STRTAB_CHAIN
-#endif
-
-#undef DUK_USE_STRTAB_CHAIN_SIZE
-#if defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE)
-/* Low memory algorithm: separate chaining using arrays, fixed size hash */
-#define DUK_USE_STRTAB_CHAIN_SIZE DUK_OPT_STRTAB_CHAIN_SIZE
-#endif
-
-#undef DUK_USE_STRTAB_PROBE
-#if !(defined(DUK_OPT_STRTAB_CHAIN) && defined(DUK_OPT_STRTAB_CHAIN_SIZE))
-#define DUK_USE_STRTAB_PROBE
-#endif
-
-#if defined(DUK_OPT_NONSTD_FUNC_CALLER_PROPERTY)
-#undef DUK_USE_TAILCALL
-#else
-#define DUK_USE_TAILCALL
-#endif
-
-#if defined(DUK_OPT_TARGET_INFO)
-#define DUK_USE_TARGET_INFO DUK_OPT_TARGET_INFO
-#else
-#define DUK_USE_TARGET_INFO "unknown"
-#endif
-
-#if defined(DUK_OPT_NO_AUGMENT_ERRORS)
-#undef DUK_USE_TRACEBACKS
-#elif defined(DUK_OPT_NO_TRACEBACKS)
-#undef DUK_USE_TRACEBACKS
-#else
-#define DUK_USE_TRACEBACKS
-#endif
-
-#if defined(DUK_OPT_TRACEBACK_DEPTH)
-#define DUK_USE_TRACEBACK_DEPTH DUK_OPT_TRACEBACK_DEPTH
-#else
-#define DUK_USE_TRACEBACK_DEPTH 10
-#endif
-
-#if defined(DUK_OPT_DECLARE)
-#define DUK_USE_USER_DECLARE() DUK_OPT_DECLARE
-#else
-#define DUK_USE_USER_DECLARE() /* no user declarations */
-#endif
-
-/* User provided InitJS. */
-#undef DUK_USE_USER_INITJS
-#if defined(DUK_OPT_USER_INITJS)
-#define DUK_USE_USER_INITJS (DUK_OPT_USER_INITJS)
-#endif
-
-#if defined(DUK_OPT_VERBOSE_ERRORS)
-#define DUK_USE_VERBOSE_ERRORS
-#elif defined(DUK_OPT_NO_VERBOSE_ERRORS)
-#undef DUK_USE_VERBOSE_ERRORS
-#else
-#define DUK_USE_VERBOSE_ERRORS
-#endif
-
-#if defined(DUK_OPT_VOLUNTARY_GC)
-#define DUK_USE_VOLUNTARY_GC
-#elif defined(DUK_OPT_NO_VOLUNTARY_GC)
-#undef DUK_USE_VOLUNTARY_GC
-#else
-#define DUK_USE_VOLUNTARY_GC
-#endif
-
-#if defined(DUK_OPT_ZERO_BUFFER_DATA)
-#define DUK_USE_ZERO_BUFFER_DATA
-#elif defined(DUK_OPT_NO_ZERO_BUFFER_DATA)
-#undef DUK_USE_ZERO_BUFFER_DATA
-#else
-#define DUK_USE_ZERO_BUFFER_DATA
-#endif
-
-/*
- * Autogenerated defaults
- */
-
-#define DUK_USE_AVOID_PLATFORM_FUNCPTRS
-#define DUK_USE_BASE64_FASTPATH
-#define DUK_USE_BUILTIN_INITJS
-#define DUK_USE_COMPILER_RECLIMIT 2500
-#undef DUK_USE_DATE_FORMAT_STRING
-#undef DUK_USE_DATE_GET_LOCAL_TZOFFSET
-#undef DUK_USE_DATE_GET_NOW
-#undef DUK_USE_DATE_PARSE_STRING
-#undef DUK_USE_DATE_PRS_GETDATE
-#define DUK_USE_ESBC_LIMITS
-#define DUK_USE_ESBC_MAX_BYTES 2147418112L
-#define DUK_USE_ESBC_MAX_LINENUMBER 2147418112L
-#undef DUK_USE_EXEC_FUN_LOCAL
-#undef DUK_USE_EXPLICIT_NULL_INIT
-#define DUK_USE_FAST_REFCOUNT_DEFAULT
-#define DUK_USE_HEX_FASTPATH
-#define DUK_USE_IDCHAR_FASTPATH
-#undef DUK_USE_INTERRUPT_DEBUG_FIXUP
-#define DUK_USE_JSON_DECNUMBER_FASTPATH
-#define DUK_USE_JSON_DECSTRING_FASTPATH
-#define DUK_USE_JSON_DEC_RECLIMIT 1000
-#define DUK_USE_JSON_EATWHITE_FASTPATH
-#define DUK_USE_JSON_ENC_RECLIMIT 1000
-#define DUK_USE_JSON_QUOTESTRING_FASTPATH
-#define DUK_USE_LEXER_SLIDING_WINDOW
-#undef DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE
-#define DUK_USE_MARK_AND_SWEEP_RECLIMIT 256
-#define DUK_USE_MATH_BUILTIN
-#define DUK_USE_NATIVE_CALL_RECLIMIT 1000
-#undef DUK_USE_PANIC_EXIT
-#undef DUK_USE_PREFER_SIZE
-#define DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS
-#undef DUK_USE_REFZERO_FINALIZER_TORTURE
-#define DUK_USE_REGEXP_COMPILER_RECLIMIT 10000
-#define DUK_USE_REGEXP_EXECUTOR_RECLIMIT 10000
-#define DUK_USE_ROM_PTRCOMP_FIRST 63488L
-#undef DUK_USE_STRHASH_DENSE
-#define DUK_USE_STRHASH_SKIP_SHIFT 5
-#undef DUK_USE_VALSTACK_UNSAFE
-#define DUK_USE_VERBOSE_EXECUTOR_ERRORS
-
-/*
- * Alternative customization header
- *
- * If you want to modify the final DUK_USE_xxx flags directly (without
- * using the available DUK_OPT_xxx flags), define DUK_OPT_HAVE_CUSTOM_H
- * and tweak the final flags there.
- */
-
-#if defined(DUK_OPT_HAVE_CUSTOM_H)
-#include "duk_custom.h"
-#endif
-
-/*
- * You may add overriding #define/#undef directives below for
- * customization. You of course cannot un-#include or un-typedef
- * anything; these require direct changes above.
- */
-
-/* __OVERRIDE_DEFINES__ */
-
-/*
- * Date provider selection
- *
- * User may define DUK_USE_DATE_GET_NOW() etc directly, in which case we'll
- * rely on an external provider. If this is not done, revert to previous
- * behavior and use Unix/Windows built-in provider.
- */
-
-#if defined(DUK_COMPILING_DUKTAPE)
-
-#if defined(DUK_USE_DATE_GET_NOW)
-/* External provider already defined. */
-#elif defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_gettimeofday((ctx))
-#elif defined(DUK_USE_DATE_NOW_TIME)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_time((ctx))
-#elif defined(DUK_USE_DATE_NOW_WINDOWS)
-#define DUK_USE_DATE_GET_NOW(ctx) duk_bi_date_get_now_windows((ctx))
-#else
-#error no provider for DUK_USE_DATE_GET_NOW()
-#endif
-
-#if defined(DUK_USE_DATE_GET_LOCAL_TZOFFSET)
-/* External provider already defined. */
-#elif defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
-#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_gmtime((d))
-#elif defined(DUK_USE_DATE_TZO_WINDOWS)
-#define DUK_USE_DATE_GET_LOCAL_TZOFFSET(d) duk_bi_date_get_local_tzoffset_windows((d))
-#else
-#error no provider for DUK_USE_DATE_GET_LOCAL_TZOFFSET()
-#endif
-
-#if defined(DUK_USE_DATE_PARSE_STRING)
-/* External provider already defined. */
-#elif defined(DUK_USE_DATE_PRS_STRPTIME)
-#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_strptime((ctx), (str))
-#elif defined(DUK_USE_DATE_PRS_GETDATE)
-#define DUK_USE_DATE_PARSE_STRING(ctx,str) duk_bi_date_parse_string_getdate((ctx), (str))
-#else
-/* No provider for DUK_USE_DATE_PARSE_STRING(), fall back to ISO 8601 only. */
-#endif
-
-#if defined(DUK_USE_DATE_FORMAT_STRING)
-/* External provider already defined. */
-#elif defined(DUK_USE_DATE_FMT_STRFTIME)
-#define DUK_USE_DATE_FORMAT_STRING(ctx,parts,tzoffset,flags) \
- duk_bi_date_format_parts_strftime((ctx), (parts), (tzoffset), (flags))
-#else
-/* No provider for DUK_USE_DATE_FORMAT_STRING(), fall back to ISO 8601 only. */
-#endif
-
-#endif /* DUK_COMPILING_DUKTAPE */
-
-/*
- * Checks for config option consistency (DUK_USE_xxx)
- */
-
-#if defined(DUK_USE_32BIT_PTRS)
-#error unsupported config option used (option has been removed): DUK_USE_32BIT_PTRS
-#endif
-#if defined(DUK_USE_ALIGN_4)
-#error unsupported config option used (option has been removed): DUK_USE_ALIGN_4
-#endif
-#if defined(DUK_USE_ALIGN_8)
-#error unsupported config option used (option has been removed): DUK_USE_ALIGN_8
-#endif
-#if defined(DUK_USE_BYTEORDER_FORCED)
-#error unsupported config option used (option has been removed): DUK_USE_BYTEORDER_FORCED
-#endif
-#if defined(DUK_USE_DATAPTR_DEC16) && !defined(DUK_USE_DATAPTR16)
-#error config option DUK_USE_DATAPTR_DEC16 requires option DUK_USE_DATAPTR16 (which is missing)
-#endif
-#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_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_DEEP_C_STACK)
-#error unsupported config option used (option has been removed): DUK_USE_DEEP_C_STACK
-#endif
-#if defined(DUK_USE_DOUBLE_BE)
-#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_BE
-#endif
-#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_LE)
-#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_LE (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_BE) && defined(DUK_USE_DOUBLE_ME)
-#error config option DUK_USE_DOUBLE_BE conflicts with option DUK_USE_DOUBLE_ME (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_LE)
-#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_LE
-#endif
-#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_BE)
-#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_BE (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_LE) && defined(DUK_USE_DOUBLE_ME)
-#error config option DUK_USE_DOUBLE_LE conflicts with option DUK_USE_DOUBLE_ME (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_ME)
-#error unsupported config option used (option has been removed): DUK_USE_DOUBLE_ME
-#endif
-#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_LE)
-#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_LE (which is also defined)
-#endif
-#if defined(DUK_USE_DOUBLE_ME) && defined(DUK_USE_DOUBLE_BE)
-#error config option DUK_USE_DOUBLE_ME conflicts with option DUK_USE_DOUBLE_BE (which is also defined)
-#endif
-#if defined(DUK_USE_DPRINT) && !defined(DUK_USE_DEBUG)
-#error config option DUK_USE_DPRINT requires option DUK_USE_DEBUG (which is missing)
-#endif
-#if defined(DUK_USE_ESBC_MAX_BYTES) && !defined(DUK_USE_ESBC_LIMITS)
-#error config option DUK_USE_ESBC_MAX_BYTES requires option DUK_USE_ESBC_LIMITS (which is missing)
-#endif
-#if defined(DUK_USE_ESBC_MAX_LINENUMBER) && !defined(DUK_USE_ESBC_LIMITS)
-#error config option DUK_USE_ESBC_MAX_LINENUMBER requires option DUK_USE_ESBC_LIMITS (which is missing)
-#endif
-#if defined(DUK_USE_EXEC_TIMEOUT_CHECK) && !defined(DUK_USE_INTERRUPT_COUNTER)
-#error config option DUK_USE_EXEC_TIMEOUT_CHECK requires option DUK_USE_INTERRUPT_COUNTER (which is missing)
-#endif
-#if defined(DUK_USE_EXTSTR_FREE) && !defined(DUK_USE_HSTRING_EXTDATA)
-#error config option DUK_USE_EXTSTR_FREE requires option DUK_USE_HSTRING_EXTDATA (which is missing)
-#endif
-#if defined(DUK_USE_EXTSTR_INTERN_CHECK) && !defined(DUK_USE_HSTRING_EXTDATA)
-#error config option DUK_USE_EXTSTR_INTERN_CHECK requires option DUK_USE_HSTRING_EXTDATA (which is missing)
-#endif
-#if defined(DUK_USE_FULL_TVAL)
-#error unsupported config option used (option has been removed): DUK_USE_FULL_TVAL
-#endif
-#if defined(DUK_USE_FUNCPTR_DEC16) && !defined(DUK_USE_FUNCPTR16)
-#error config option DUK_USE_FUNCPTR_DEC16 requires option DUK_USE_FUNCPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_FUNCPTR_ENC16) && !defined(DUK_USE_FUNCPTR16)
-#error config option DUK_USE_FUNCPTR_ENC16 requires option DUK_USE_FUNCPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS)
-#error unsupported config option used (option has been removed): DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
-#endif
-#if defined(DUK_USE_HEAPPTR16) && defined(DUK_USE_DEBUG)
-#error config option DUK_USE_HEAPPTR16 conflicts with option DUK_USE_DEBUG (which is also defined)
-#endif
-#if defined(DUK_USE_HEAPPTR_DEC16) && !defined(DUK_USE_HEAPPTR16)
-#error config option DUK_USE_HEAPPTR_DEC16 requires option DUK_USE_HEAPPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_HEAPPTR_ENC16) && !defined(DUK_USE_HEAPPTR16)
-#error config option DUK_USE_HEAPPTR_ENC16 requires option DUK_USE_HEAPPTR16 (which is missing)
-#endif
-#if defined(DUK_USE_INTEGER_BE)
-#error unsupported config option used (option has been removed): DUK_USE_INTEGER_BE
-#endif
-#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_LE)
-#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_LE (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_BE) && defined(DUK_USE_INTEGER_ME)
-#error config option DUK_USE_INTEGER_BE conflicts with option DUK_USE_INTEGER_ME (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_LE)
-#error unsupported config option used (option has been removed): DUK_USE_INTEGER_LE
-#endif
-#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_BE)
-#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_BE (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_LE) && defined(DUK_USE_INTEGER_ME)
-#error config option DUK_USE_INTEGER_LE conflicts with option DUK_USE_INTEGER_ME (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_ME)
-#error unsupported config option used (option has been removed): DUK_USE_INTEGER_ME
-#endif
-#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_LE)
-#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_LE (which is also defined)
-#endif
-#if defined(DUK_USE_INTEGER_ME) && defined(DUK_USE_INTEGER_BE)
-#error config option DUK_USE_INTEGER_ME conflicts with option DUK_USE_INTEGER_BE (which is also defined)
-#endif
-#if defined(DUK_USE_NO_DOUBLE_ALIASING_SELFTEST)
-#error unsupported config option used (option has been removed): DUK_USE_NO_DOUBLE_ALIASING_SELFTEST
-#endif
-#if defined(DUK_USE_PACKED_TVAL_POSSIBLE)
-#error unsupported config option used (option has been removed): DUK_USE_PACKED_TVAL_POSSIBLE
-#endif
-#if defined(DUK_USE_RDTSC)
-#error unsupported config option used (option has been removed): DUK_USE_RDTSC
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_STRINGS)
-#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_STRINGS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_CLONE) && !defined(DUK_USE_ROM_OBJECTS)
-#error config option DUK_USE_ROM_GLOBAL_CLONE requires option DUK_USE_ROM_OBJECTS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_CLONE) && defined(DUK_USE_ROM_GLOBAL_INHERIT)
-#error config option DUK_USE_ROM_GLOBAL_CLONE conflicts with option DUK_USE_ROM_GLOBAL_INHERIT (which is also defined)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_STRINGS)
-#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_STRINGS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && !defined(DUK_USE_ROM_OBJECTS)
-#error config option DUK_USE_ROM_GLOBAL_INHERIT requires option DUK_USE_ROM_OBJECTS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_GLOBAL_INHERIT) && defined(DUK_USE_ROM_GLOBAL_CLONE)
-#error config option DUK_USE_ROM_GLOBAL_INHERIT conflicts with option DUK_USE_ROM_GLOBAL_CLONE (which is also defined)
-#endif
-#if defined(DUK_USE_ROM_OBJECTS) && !defined(DUK_USE_ROM_STRINGS)
-#error config option DUK_USE_ROM_OBJECTS requires option DUK_USE_ROM_STRINGS (which is missing)
-#endif
-#if defined(DUK_USE_ROM_STRINGS) && !defined(DUK_USE_ROM_OBJECTS)
-#error config option DUK_USE_ROM_STRINGS requires option DUK_USE_ROM_OBJECTS (which is missing)
-#endif
-#if defined(DUK_USE_SETJMP)
-#error unsupported config option used (option has been removed): DUK_USE_SETJMP
-#endif
-#if defined(DUK_USE_SIGSETJMP)
-#error unsupported config option used (option has been removed): DUK_USE_SIGSETJMP
-#endif
-#if defined(DUK_USE_STRTAB_CHAIN_SIZE) && !defined(DUK_USE_STRTAB_CHAIN)
-#error config option DUK_USE_STRTAB_CHAIN_SIZE requires option DUK_USE_STRTAB_CHAIN (which is missing)
-#endif
-#if defined(DUK_USE_TAILCALL) && defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
-#error config option DUK_USE_TAILCALL conflicts with option DUK_USE_NONSTD_FUNC_CALLER_PROPERTY (which is also defined)
-#endif
-#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
-#error unsupported config option used (option has been removed): DUK_USE_UNALIGNED_ACCESSES_POSSIBLE
-#endif
-#if defined(DUK_USE_UNDERSCORE_SETJMP)
-#error unsupported config option used (option has been removed): DUK_USE_UNDERSCORE_SETJMP
-#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.
- */
-
-#if defined(DUK_USE_BYTEORDER)
-#if (DUK_USE_BYTEORDER == 1)
-#define DUK_USE_INTEGER_LE
-#define DUK_USE_DOUBLE_LE
-#elif (DUK_USE_BYTEORDER == 2)
-#define DUK_USE_INTEGER_LE /* integer endianness is little on purpose */
-#define DUK_USE_DOUBLE_ME
-#elif (DUK_USE_BYTEORDER == 3)
-#define DUK_USE_INTEGER_BE
-#define DUK_USE_DOUBLE_BE
-#else
-#error unsupported: byte order invalid
-#endif /* byte order */
-#else
-#error unsupported: byte order detection failed
-#endif /* defined(DUK_USE_BYTEORDER) */
-
-#endif /* DUK_CONFIG_H_INCLUDED */
diff --git a/javascript/duktape/duk_custom.h b/javascript/duktape/duk_custom.h
deleted file mode 100644
index 1f98b7825..000000000
--- a/javascript/duktape/duk_custom.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2015 Daniel Silverstone <dsilvers@netsurf-browser.org>
- *
- * 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/>.
- */
-
-/** \file
- * Custom configuration for duktape
- */
-
-#include "utils/config.h"
-
-#ifndef HAVE_STRPTIME
-#undef DUK_USE_DATE_PRS_STRPTIME
-#undef DUK_USE_DATE_PRS_GETDATE
-#undef DUK_USE_DATE_PARSE_STRING
-#endif
-
-#define DUK_USE_REGEXP_CANON_WORKAROUND
-
-/* Required for execution timeout checking */
-#define DUK_USE_INTERRUPT_COUNTER
-
-extern duk_bool_t dukky_check_timeout(void *udata);
-#define DUK_USE_EXEC_TIMEOUT_CHECK dukky_check_timeout
diff --git a/javascript/duktape/dukky.c b/javascript/duktape/dukky.c
deleted file mode 100644
index 7dd3bd71e..000000000
--- a/javascript/duktape/dukky.c
+++ /dev/null
@@ -1,1135 +0,0 @@
-/*
- * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
- * Copyright 2015 Daniel Dilverstone <dsilvers@netsurf-browser.org>
- * Copyright 2016 Michael Drake <tlsa@netsurf-browser.org>
- * Copyright 2016 John-Mark Bell <jmb@netsurf-browser.org>
- *
- * 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/>.
- */
-
-/** \file
- * Duktapeish implementation of javascript engine functions.
- */
-
-#include <inttypes.h>
-
-#include <nsutils/time.h>
-
-#include "content/content.h"
-
-#include "utils/utils.h"
-#include "utils/nsoption.h"
-#include "utils/log.h"
-#include "utils/corestrings.h"
-
-#include "javascript/js.h"
-#include "javascript/content.h"
-
-#include "duktape/binding.h"
-
-#include "duktape.h"
-#include "dukky.h"
-
-#include <dom/dom.h>
-
-#define EVENT_MAGIC MAGIC(EVENT_MAP)
-#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP)
-#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
-
-static duk_ret_t dukky_populate_object(duk_context *ctx)
-{
- /* ... obj args protoname nargs */
- int nargs = duk_get_int(ctx, -1);
- duk_pop(ctx);
- /* ... obj args protoname */
- duk_get_global_string(ctx, PROTO_MAGIC);
- /* .. obj args protoname prototab */
- duk_insert(ctx, -2);
- /* ... obj args prototab protoname */
- duk_get_prop(ctx, -2);
- /* ... obj args prototab {proto/undefined} */
- if (duk_is_undefined(ctx, -1)) {
- LOG("RuhRoh, couldn't find a prototype, HTMLUnknownElement it is");
- duk_pop(ctx);
- duk_push_string(ctx, PROTO_NAME(HTMLUNKNOWNELEMENT));
- duk_get_prop(ctx, -2);
- }
- /* ... obj args prototab proto */
- duk_dup(ctx, -1);
- /* ... obj args prototab proto proto */
- duk_set_prototype(ctx, -(nargs+4));
- /* ... obj[proto] args prototab proto */
- duk_get_prop_string(ctx, -1, INIT_MAGIC);
- /* ... obj[proto] args prototab proto initfn */
- duk_insert(ctx, -(nargs+4));
- /* ... initfn obj[proto] args prototab proto */
- duk_pop_2(ctx);
- /* ... initfn obj[proto] args */
- LOG("Call the init function");
- duk_call(ctx, nargs + 1);
- return 1; /* The object */
-}
-
-duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args)
-{
- duk_ret_t ret;
- LOG("name=%s nargs=%d", name+2, args);
- /* ... args */
- duk_push_object(ctx);
- /* ... args obj */
- duk_push_object(ctx);
- /* ... args obj handlers */
- duk_put_prop_string(ctx, -2, HANDLER_LISTENER_MAGIC);
- /* ... args obj */
- duk_push_object(ctx);
- /* ... args obj handlers */
- duk_put_prop_string(ctx, -2, HANDLER_MAGIC);
- /* ... args obj */
- duk_insert(ctx, -(args+1));
- /* ... obj args */
- duk_push_string(ctx, name);
- /* ... obj args name */
- duk_push_int(ctx, args);
- /* ... obj args name nargs */
- if ((ret = duk_safe_call(ctx, dukky_populate_object, args + 3, 1))
- != DUK_EXEC_SUCCESS)
- return ret;
- LOG("created");
- return DUK_EXEC_SUCCESS;
-}
-
-
-
-duk_bool_t
-dukky_push_node_stacked(duk_context *ctx)
-{
- int top_at_fail = duk_get_top(ctx) - 2;
- /* ... nodeptr klass */
- duk_get_global_string(ctx, NODE_MAGIC);
- /* ... nodeptr klass nodes */
- duk_dup(ctx, -3);
- /* ... nodeptr klass nodes nodeptr */
- duk_get_prop(ctx, -2);
- /* ... nodeptr klass nodes node/undefined */
- if (duk_is_undefined(ctx, -1)) {
- /* ... nodeptr klass nodes undefined */
- duk_pop(ctx);
- /* ... nodeptr klass nodes */
- duk_push_object(ctx);
- /* ... nodeptr klass nodes obj */
- duk_push_object(ctx);
- /* ... nodeptr klass nodes obj handlers */
- duk_put_prop_string(ctx, -2, HANDLER_LISTENER_MAGIC);
- /* ... nodeptr klass nodes obj */
- duk_push_object(ctx);
- /* ... nodeptr klass nodes obj handlers */
- duk_put_prop_string(ctx, -2, HANDLER_MAGIC);
- /* ... nodeptr klass nodes obj */
- duk_dup(ctx, -4);
- /* ... nodeptr klass nodes obj nodeptr */
- duk_dup(ctx, -4);
- /* ... nodeptr klass nodes obj nodeptr klass */
- duk_push_int(ctx, 1);
- /* ... nodeptr klass nodes obj nodeptr klass 1 */
- if (duk_safe_call(ctx, dukky_populate_object, 4, 1)
- != DUK_EXEC_SUCCESS) {
- duk_set_top(ctx, top_at_fail);
- LOG("Boo and also hiss");
- return false;
- }
- /* ... nodeptr klass nodes node */
- duk_dup(ctx, -4);
- /* ... nodeptr klass nodes node nodeptr */
- duk_dup(ctx, -2);
- /* ... nodeptr klass nodes node nodeptr node */
- duk_put_prop(ctx, -4);
- /* ... nodeptr klass nodes node */
- }
- /* ... nodeptr klass nodes node */
- duk_insert(ctx, -4);
- /* ... node nodeptr klass nodes */
- duk_pop_3(ctx);
- /* ... node */
- return true;
-}
-
-#define SET_HTML_CLASS(CLASS) \
- *html_class = PROTO_NAME(HTML##CLASS##ELEMENT); \
- *html_class_len = \
- SLEN(PROTO_NAME(HTML)) + \
- SLEN(#CLASS) + \
- SLEN("ELEMENT");
-
-static void dukky_html_element_class_from_tag_type(dom_html_element_type type,
- const char **html_class, size_t *html_class_len)
-{
- switch(type) {
- case DOM_HTML_ELEMENT_TYPE_HTML:
- SET_HTML_CLASS(HTML)
- break;
- case DOM_HTML_ELEMENT_TYPE_HEAD:
- SET_HTML_CLASS(HEAD)
- break;
- case DOM_HTML_ELEMENT_TYPE_META:
- SET_HTML_CLASS(META)
- break;
- case DOM_HTML_ELEMENT_TYPE_BASE:
- SET_HTML_CLASS(BASE)
- break;
- case DOM_HTML_ELEMENT_TYPE_TITLE:
- SET_HTML_CLASS(TITLE)
- break;
- case DOM_HTML_ELEMENT_TYPE_BODY:
- SET_HTML_CLASS(BODY)
- break;
- case DOM_HTML_ELEMENT_TYPE_DIV:
- SET_HTML_CLASS(DIV)
- break;
- case DOM_HTML_ELEMENT_TYPE_FORM:
- SET_HTML_CLASS(FORM)
- break;
- case DOM_HTML_ELEMENT_TYPE_LINK:
- SET_HTML_CLASS(LINK)
- break;
- case DOM_HTML_ELEMENT_TYPE_BUTTON:
- SET_HTML_CLASS(BUTTOM)
- break;
- case DOM_HTML_ELEMENT_TYPE_INPUT:
- SET_HTML_CLASS(INPUT)
- break;
- case DOM_HTML_ELEMENT_TYPE_TEXTAREA:
- SET_HTML_CLASS(TEXTAREA)
- break;
- case DOM_HTML_ELEMENT_TYPE_OPTGROUP:
- SET_HTML_CLASS(OPTGROUP)
- break;
- case DOM_HTML_ELEMENT_TYPE_OPTION:
- SET_HTML_CLASS(OPTION)
- break;
- case DOM_HTML_ELEMENT_TYPE_SELECT:
- SET_HTML_CLASS(SELECT)
- break;
- case DOM_HTML_ELEMENT_TYPE_HR:
- SET_HTML_CLASS(HR)
- break;
- case DOM_HTML_ELEMENT_TYPE_DL:
- SET_HTML_CLASS(DLIST)
- break;
- case DOM_HTML_ELEMENT_TYPE_DIR:
- SET_HTML_CLASS(DIRECTORY)
- break;
- case DOM_HTML_ELEMENT_TYPE_MENU:
- SET_HTML_CLASS(MENU)
- break;
- case DOM_HTML_ELEMENT_TYPE_FIELDSET:
- SET_HTML_CLASS(FIELDSET)
- break;
- case DOM_HTML_ELEMENT_TYPE_LEGEND:
- SET_HTML_CLASS(LEGEND)
- break;
- case DOM_HTML_ELEMENT_TYPE_P:
- SET_HTML_CLASS(PARAGRAPH)
- break;
- case DOM_HTML_ELEMENT_TYPE_H1:
- case DOM_HTML_ELEMENT_TYPE_H2:
- case DOM_HTML_ELEMENT_TYPE_H3:
- case DOM_HTML_ELEMENT_TYPE_H4:
- case DOM_HTML_ELEMENT_TYPE_H5:
- case DOM_HTML_ELEMENT_TYPE_H6:
- SET_HTML_CLASS(HEADING)
- break;
- case DOM_HTML_ELEMENT_TYPE_BLOCKQUOTE:
- case DOM_HTML_ELEMENT_TYPE_Q:
- SET_HTML_CLASS(QUOTE)
- break;
- case DOM_HTML_ELEMENT_TYPE_PRE:
- SET_HTML_CLASS(PRE)
- break;
- case DOM_HTML_ELEMENT_TYPE_BR:
- SET_HTML_CLASS(BR)
- break;
- case DOM_HTML_ELEMENT_TYPE_LABEL:
- SET_HTML_CLASS(LABEL)
- break;
- case DOM_HTML_ELEMENT_TYPE_UL:
- SET_HTML_CLASS(ULIST)
- break;
- case DOM_HTML_ELEMENT_TYPE_OL:
- SET_HTML_CLASS(OLIST)
- break;
- case DOM_HTML_ELEMENT_TYPE_LI:
- SET_HTML_CLASS(LI)
- break;
- case DOM_HTML_ELEMENT_TYPE_FONT:
- SET_HTML_CLASS(FONT)
- break;
- case DOM_HTML_ELEMENT_TYPE_DEL:
- case DOM_HTML_ELEMENT_TYPE_INS:
- SET_HTML_CLASS(MOD)
- break;
- case DOM_HTML_ELEMENT_TYPE_A:
- SET_HTML_CLASS(ANCHOR)
- break;
- case DOM_HTML_ELEMENT_TYPE_BASEFONT:
- SET_HTML_CLASS(BASEFONT)
- break;
- case DOM_HTML_ELEMENT_TYPE_IMG:
- SET_HTML_CLASS(IMAGE)
- break;
- case DOM_HTML_ELEMENT_TYPE_OBJECT:
- SET_HTML_CLASS(OBJECT)
- break;
- case DOM_HTML_ELEMENT_TYPE_PARAM:
- SET_HTML_CLASS(PARAM)
- break;
- case DOM_HTML_ELEMENT_TYPE_APPLET:
- SET_HTML_CLASS(APPLET)
- break;
- case DOM_HTML_ELEMENT_TYPE_MAP:
- SET_HTML_CLASS(MAP)
- break;
- case DOM_HTML_ELEMENT_TYPE_AREA:
- SET_HTML_CLASS(AREA)
- break;
- case DOM_HTML_ELEMENT_TYPE_SCRIPT:
- SET_HTML_CLASS(SCRIPT)
- break;
- case DOM_HTML_ELEMENT_TYPE_CAPTION:
- SET_HTML_CLASS(TABLECAPTION)
- break;
- case DOM_HTML_ELEMENT_TYPE_TD:
- case DOM_HTML_ELEMENT_TYPE_TH:
- SET_HTML_CLASS(TABLECELL)
- break;
- case DOM_HTML_ELEMENT_TYPE_COL:
- case DOM_HTML_ELEMENT_TYPE_COLGROUP:
- SET_HTML_CLASS(TABLECOL)
- break;
- case DOM_HTML_ELEMENT_TYPE_THEAD:
- case DOM_HTML_ELEMENT_TYPE_TBODY:
- case DOM_HTML_ELEMENT_TYPE_TFOOT:
- SET_HTML_CLASS(TABLESECTION)
- break;
- case DOM_HTML_ELEMENT_TYPE_TABLE:
- SET_HTML_CLASS(TABLE)
- break;
- case DOM_HTML_ELEMENT_TYPE_TR:
- SET_HTML_CLASS(TABLEROW)
- break;
- case DOM_HTML_ELEMENT_TYPE_STYLE:
- SET_HTML_CLASS(STYLE)
- break;
- case DOM_HTML_ELEMENT_TYPE_FRAMESET:
- SET_HTML_CLASS(FRAMESET)
- break;
- case DOM_HTML_ELEMENT_TYPE_FRAME:
- SET_HTML_CLASS(FRAME)
- break;
- case DOM_HTML_ELEMENT_TYPE_IFRAME:
- SET_HTML_CLASS(IFRAME)
- break;
- case DOM_HTML_ELEMENT_TYPE_ISINDEX:
- SET_HTML_CLASS(ISINDEX)
- break;
- case DOM_HTML_ELEMENT_TYPE__COUNT:
- assert(type != DOM_HTML_ELEMENT_TYPE__COUNT);
- /* fallthrough */
- case DOM_HTML_ELEMENT_TYPE__UNKNOWN:
- SET_HTML_CLASS(UNKNOWN)
- break;
- default:
- /* Known HTML element without a specialisation */
- *html_class = PROTO_NAME(HTMLELEMENT);
- *html_class_len =
- SLEN(PROTO_NAME(HTML)) +
- SLEN("ELEMENT");
- break;
- }
- return;
-}
-
-#undef SET_HTML_CLASS
-
-static void
-dukky_push_node_klass(duk_context *ctx, struct dom_node *node)
-{
- dom_node_type nodetype;
- dom_exception err;
-
- err = dom_node_get_node_type(node, &nodetype);
- if (err != DOM_NO_ERR) {
- /* Oh bum, just node then */
- duk_push_string(ctx, PROTO_NAME(NODE));
- return;
- }
-
- switch(nodetype) {
- case DOM_ELEMENT_NODE: {
- dom_string *namespace;
- dom_html_element_type type;
- const char *html_class;
- size_t html_class_len;
- err = dom_node_get_namespace(node, &namespace);
- if (err != DOM_NO_ERR) {
- /* Feck it, element */
- LOG("dom_node_get_namespace() failed");
- duk_push_string(ctx, PROTO_NAME(ELEMENT));
- break;
- }
- if (namespace == NULL) {
- /* No namespace, -> element */
- LOG("no namespace");
- duk_push_string(ctx, PROTO_NAME(ELEMENT));
- break;
- }
-
- if (dom_string_isequal(namespace, corestring_dom_html_namespace) == false) {
- /* definitely not an HTML element of some kind */
- duk_push_string(ctx, PROTO_NAME(ELEMENT));
- dom_string_unref(namespace);
- break;
- }
- dom_string_unref(namespace);
-
- err = dom_html_element_get_tag_type(node, &type);
- if (err != DOM_NO_ERR) {
- type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
- }
-
- dukky_html_element_class_from_tag_type(type,
- &html_class, &html_class_len);
-
- duk_push_lstring(ctx, html_class, html_class_len);
- break;
- }
- case DOM_TEXT_NODE:
- duk_push_string(ctx, PROTO_NAME(TEXT));
- break;
- case DOM_COMMENT_NODE:
- duk_push_string(ctx, PROTO_NAME(COMMENT));
- break;
- case DOM_DOCUMENT_NODE:
- duk_push_string(ctx, PROTO_NAME(DOCUMENT));
- break;
- case DOM_ATTRIBUTE_NODE:
- case DOM_PROCESSING_INSTRUCTION_NODE:
- case DOM_DOCUMENT_TYPE_NODE:
- case DOM_DOCUMENT_FRAGMENT_NODE:
- case DOM_NOTATION_NODE:
- case DOM_ENTITY_REFERENCE_NODE:
- case DOM_ENTITY_NODE:
- case DOM_CDATA_SECTION_NODE:
- default:
- /* Oh bum, just node then */
- duk_push_string(ctx, PROTO_NAME(NODE));
- }
-}
-
-duk_bool_t
-dukky_push_node(duk_context *ctx, struct dom_node *node)
-{
- JS_LOG("Pushing node %p", node);
- /* First check if we can find the node */
- /* ... */
- duk_get_global_string(ctx, NODE_MAGIC);
- /* ... nodes */
- duk_push_pointer(ctx, node);
- /* ... nodes nodeptr */
- duk_get_prop(ctx, -2);
- /* ... nodes node/undefined */
- if (!duk_is_undefined(ctx, -1)) {
- /* ... nodes node */
- duk_insert(ctx, -2);
- /* ... node nodes */
- duk_pop(ctx);
- /* ... node */
- JS_LOG("Found it memoised");
- return true;
- }
- /* ... nodes undefined */
- duk_pop_2(ctx);
- /* ... */
- /* We couldn't, so now we determine the node type and then
- * we ask for it to be created
- */
- duk_push_pointer(ctx, node);
- /* ... nodeptr */
- dukky_push_node_klass(ctx, node);
- /* ... nodeptr klass */
- return dukky_push_node_stacked(ctx);
-}
-
-static duk_ret_t
-dukky_bad_constructor(duk_context *ctx)
-{
- duk_error(ctx, DUK_ERR_ERROR, "Bad constructor");
- return 0;
-}
-
-void
-dukky_inject_not_ctr(duk_context *ctx, int idx, const char *name)
-{
- /* ... p[idx] ... proto */
- duk_push_c_function(ctx, dukky_bad_constructor, 0);
- /* ... p[idx] ... proto cons */
- duk_insert(ctx, -2);
- /* ... p[idx] ... cons proto */
- duk_put_prop_string(ctx, -2, "prototype");
- /* ... p[idx] ... cons[proto] */
- duk_put_prop_string(ctx, idx, name);
- /* ... p ... */
- return;
-}
-
-/* Duktape heap utility functions */
-
-/* We need to override the defaults because not all platforms are fully ANSI
- * compatible. E.g. RISC OS gets upset if we malloc or realloc a zero byte
- * block, as do debugging tools such as Electric Fence by Bruce Perens.
- */
-
-static void *dukky_alloc_function(void *udata, duk_size_t size)
-{
- if (size == 0)
- return NULL;
-
- return malloc(size);
-}
-
-static void *dukky_realloc_function(void *udata, void *ptr, duk_size_t size)
-{
- if (ptr == NULL && size == 0)
- return NULL;
-
- if (size == 0) {
- free(ptr);
- return NULL;
- }
-
- return realloc(ptr, size);
-}
-
-static void dukky_free_function(void *udata, void *ptr)
-{
- if (ptr != NULL)
- free(ptr);
-}
-
-
-/**************************************** js.h ******************************/
-struct jscontext {
- duk_context *ctx;
- duk_context *thread;
- uint64_t exec_start_time;
-};
-
-#define CTX (ctx->thread)
-
-void js_initialise(void)
-{
- /** TODO: Forces JS on for our testing, needs changing before a release
- * lest we incur the wrath of others.
- */
- /* Disabled force-on for forthcoming release */
- /* nsoption_set_bool(enable_javascript, true);
- */
- javascript_init();
-}
-
-void js_finalise(void)
-{
- /* NADA for now */
-}
-
-#define DUKKY_NEW_PROTOTYPE(klass, uklass, klass_name) \
- dukky_create_prototype(ctx, dukky_##klass##___proto, PROTO_NAME(uklass), klass_name)
-
-nserror js_newcontext(int timeout, jscallback *cb, void *cbctx,
- jscontext **jsctx)
-{
- duk_context *ctx;
- jscontext *ret = calloc(1, sizeof(*ret));
- *jsctx = NULL;
- LOG("Creating new duktape javascript context");
- if (ret == NULL) return NSERROR_NOMEM;
- ctx = ret->ctx = duk_create_heap(
- dukky_alloc_function,
- dukky_realloc_function,
- dukky_free_function,
- ret,
- NULL);
- if (ret->ctx == NULL) { free(ret); return NSERROR_NOMEM; }
- /* Create the prototype stuffs */
- duk_push_global_object(ctx);
- duk_push_boolean(ctx, true);
- duk_put_prop_string(ctx, -2, "protos");
- duk_put_global_string(ctx, PROTO_MAGIC);
- /* Create prototypes here */
- dukky_create_prototypes(ctx);
-
- *jsctx = ret;
- return NSERROR_OK;
-}
-
-void js_destroycontext(jscontext *ctx)
-{
- LOG("Destroying duktape javascript context");
- duk_destroy_heap(ctx->ctx);
- free(ctx);
-}
-
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
-{
- assert(ctx != NULL);
- /* Pop any active thread off */
- LOG("Yay, new compartment, win_priv=%p, doc_priv=%p", win_priv, doc_priv);
- duk_set_top(ctx->ctx, 0);
- duk_push_thread(ctx->ctx);
- ctx->thread = duk_require_context(ctx->ctx, -1);
- duk_push_int(CTX, 0);
- duk_push_int(CTX, 1);
- duk_push_int(CTX, 2);
- /* Manufacture a Window object */
- /* win_priv is a browser_window, doc_priv is an html content struct */
- duk_push_pointer(CTX, win_priv);
- duk_push_pointer(CTX, doc_priv);
- dukky_create_object(CTX, PROTO_NAME(WINDOW), 2);
- duk_push_global_object(CTX);
- duk_put_prop_string(CTX, -2, PROTO_MAGIC);
- duk_set_global_object(CTX);
-
- /* Now we need to prepare our node mapping table */
- duk_push_object(CTX);
- duk_push_pointer(CTX, NULL);
- duk_push_null(CTX);
- duk_put_prop(CTX, -3);
- duk_put_global_string(CTX, NODE_MAGIC);
-
- /* And now the event mapping table */
- duk_push_object(CTX);
- duk_put_global_string(CTX, EVENT_MAGIC);
-
- return (jsobject *)ctx;
-}
-
-static duk_ret_t eval_top_string(duk_context *ctx)
-{
- duk_eval(ctx);
- return 0;
-}
-
-duk_bool_t dukky_check_timeout(void *udata)
-{
-#define JS_EXEC_TIMEOUT_MS 10000 /* 10 seconds */
- jscontext *ctx = (jscontext *) udata;
- uint64_t now;
-
- (void) nsu_getmonotonic_ms(&now);
-
- /* This function may be called during duk heap construction,
- * so only test for execution timeout if we've recorded a
- * start time.
- */
- return ctx->exec_start_time != 0 &&
- now > (ctx->exec_start_time + JS_EXEC_TIMEOUT_MS);
-}
-
-bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
-{
- assert(ctx);
- if (txt == NULL || txtlen == 0) return false;
- duk_set_top(CTX, 0);
- duk_push_lstring(CTX, txt, txtlen);
-
- (void) nsu_getmonotonic_ms(&ctx->exec_start_time);
- if (duk_safe_call(CTX, eval_top_string, 1, 1) == DUK_EXEC_ERROR) {
- duk_get_prop_string(CTX, 0, "name");
- duk_get_prop_string(CTX, 0, "message");
- duk_get_prop_string(CTX, 0, "fileName");
- duk_get_prop_string(CTX, 0, "lineNumber");
- duk_get_prop_string(CTX, 0, "stack");
- LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(CTX, 1),
- duk_safe_to_string(CTX, 2));
- LOG(" was at: %s line %s", duk_safe_to_string(CTX, 3),
- duk_safe_to_string(CTX, 4));
- LOG(" Stack trace: %s", duk_safe_to_string(CTX, 5));
- return false;
- }
- if (duk_get_top(CTX) == 0) duk_push_boolean(CTX, false);
- LOG("Returning %s", duk_get_boolean(CTX, 0) ? "true" : "false");
- return duk_get_boolean(CTX, 0);
-}
-
-/*** New style event handling ***/
-
-static void dukky_push_event(duk_context *ctx, dom_event *evt)
-{
- /* ... */
- duk_get_global_string(ctx, EVENT_MAGIC);
- /* ... events */
- duk_push_pointer(ctx, evt);
- /* ... events eventptr */
- duk_get_prop(ctx, -2);
- /* ... events event? */
- if (duk_is_undefined(ctx, -1)) {
- /* ... events undefined */
- duk_pop(ctx);
- /* ... events */
- duk_push_pointer(ctx, evt);
- if (dukky_create_object(ctx, PROTO_NAME(EVENT), 1) != DUK_EXEC_SUCCESS) {
- /* ... events err */
- duk_pop(ctx);
- /* ... events */
- duk_push_object(ctx);
- /* ... events eobj[meh] */
- }
- /* ... events eobj */
- duk_push_pointer(ctx, evt);
- /* ... events eobj eventptr */
- duk_dup(ctx, -2);
- /* ... events eobj eventptr eobj */
- duk_put_prop(ctx, -4);
- /* ... events eobj */
- }
- /* ... events event */
- duk_replace(ctx, -2);
- /* ... event */
-}
-
-static void dukky_push_handler_code_(duk_context *ctx, dom_string *name,
- dom_event_target *et)
-{
- dom_string *onname, *val;
- dom_element *ele = (dom_element *)et;
- dom_exception exc;
- dom_node_type ntype;
-
- /* Currently safe since libdom has no event targets which are not
- * nodes. Reconsider this as and when we work out how to have
- * window do stuff
- */
- exc = dom_node_get_node_type(et, &ntype);
- if (exc != DOM_NO_ERR) {
- duk_push_lstring(ctx, "", 0);
- return;
- }
-
- if (ntype != DOM_ELEMENT_NODE) {
- duk_push_lstring(ctx, "", 0);
- return;
- }
-
- exc = dom_string_concat(corestring_dom_on, name, &onname);
- if (exc != DOM_NO_ERR) {
- duk_push_lstring(ctx, "", 0);
- return;
- }
-
- exc = dom_element_get_attribute(ele, onname, &val);
- if ((exc != DOM_NO_ERR) || (val == NULL)) {
- dom_string_unref(onname);
- duk_push_lstring(ctx, "", 0);
- return;
- }
-
- dom_string_unref(onname);
- duk_push_lstring(ctx, dom_string_data(val), dom_string_length(val));
- dom_string_unref(val);
-}
-
-bool dukky_get_current_value_of_event_handler(duk_context *ctx,
- dom_string *name,
- dom_event_target *et)
-{
- /* Must be entered as:
- * ... node(et)
- */
- duk_get_prop_string(ctx, -1, HANDLER_MAGIC);
- /* ... node handlers */
- duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
- /* ... node handlers name */
- duk_get_prop(ctx, -2);
- /* ... node handlers handler? */
- if (duk_is_undefined(ctx, -1)) {
- /* ... node handlers undefined */
- duk_pop_2(ctx);
- /* ... node */
- dukky_push_handler_code_(ctx, name, et);
- /* ... node handlercode? */
- /* TODO: If this is null, clean up and propagate */
- /* ... node handlercode */
- /** @todo This is entirely wrong, but it's hard to get right */
- duk_push_string(ctx, "function (event) {");
- /* ... node handlercode prefix */
- duk_insert(ctx, -2);
- /* ... node prefix handlercode */
- duk_push_string(ctx, "}");
- /* ... node prefix handlercode suffix */
- duk_concat(ctx, 3);
- /* ... node fullhandlersrc */
- duk_push_string(ctx, "internal raw uncompiled handler");
- /* ... node fullhandlersrc filename */
- if (duk_pcompile(ctx, DUK_COMPILE_FUNCTION) != 0) {
- /* ... node err */
- LOG("Unable to proceed with handler, could not compile");
- duk_pop_2(ctx);
- return false;
- }
- /* ... node handler */
- duk_insert(ctx, -2);
- /* ... handler node */
- } else {
- /* ... node handlers handler */
- duk_insert(ctx, -3);
- /* ... handler node handlers */
- duk_pop(ctx);
- /* ... handler node */
- }
- /* ... handler node */
- return true;
-}
-
-static void dukky_generic_event_handler(dom_event *evt, void *pw)
-{
- duk_memory_functions funcs;
- duk_context *ctx = (duk_context *)pw;
- jscontext *jsctx;
- dom_string *name;
- dom_exception exc;
- dom_event_target *targ;
- dom_event_flow_phase phase;
-
- /* Retrieve the JS context from the Duktape context */
- duk_get_memory_functions(ctx, &funcs);
- jsctx = funcs.udata;
-
- LOG("WOOP WOOP, An event:");
- exc = dom_event_get_type(evt, &name);
- if (exc != DOM_NO_ERR) {
- LOG("Unable to find the event name");
- return;
- }
- LOG("Event's name is %*s",
- dom_string_length(name), dom_string_data(name));
- exc = dom_event_get_event_phase(evt, &phase);
- if (exc != DOM_NO_ERR) {
- LOG("Unable to get event phase");
- return;
- }
- LOG("Event phase is: %s (%d)",
- phase == DOM_CAPTURING_PHASE ? "capturing" :
- phase == DOM_AT_TARGET ? "at-target" :
- phase == DOM_BUBBLING_PHASE ? "bubbling" :
- "unknown", (int)phase);
-
- exc = dom_event_get_current_target(evt, &targ);
- if (exc != DOM_NO_ERR) {
- dom_string_unref(name);
- LOG("Unable to find the event target");
- return;
- }
-
- /* ... */
- if (dukky_push_node(ctx, (dom_node *)targ) == false) {
- dom_string_unref(name);
- dom_node_unref(targ);
- LOG("Unable to push JS node representation?!");
- return;
- }
- /* ... node */
- if (dukky_get_current_value_of_event_handler(
- ctx, name, (dom_event_target *)targ) == false) {
- dom_node_unref(targ);
- dom_string_unref(name);
- return;
- }
- /** @todo handle other kinds of event than the generic case */
- dom_node_unref(targ);
- dom_string_unref(name);
- /* ... handler node */
- dukky_push_event(ctx, evt);
- /* ... handler node event */
- (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
- if (duk_pcall_method(ctx, 1) != 0) {
- /* Failed to run the method */
- /* ... err */
- LOG("OH NOES! An error running a callback. Meh.");
- exc = dom_event_stop_immediate_propagation(evt);
- if (exc != DOM_NO_ERR)
- LOG("WORSE! could not stop propagation");
- duk_get_prop_string(ctx, -1, "name");
- duk_get_prop_string(ctx, -2, "message");
- duk_get_prop_string(ctx, -3, "fileName");
- duk_get_prop_string(ctx, -4, "lineNumber");
- duk_get_prop_string(ctx, -5, "stack");
- /* ... err name message fileName lineNumber stack */
- LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
- duk_safe_to_string(ctx, -4));
- LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
- duk_safe_to_string(ctx, -2));
- LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
-
- duk_pop_n(ctx, 6);
- /* ... */
- return;
- }
- /* ... result */
- if (duk_is_boolean(ctx, -1) &&
- duk_to_boolean(ctx, -1) == 0) {
- dom_event_prevent_default(evt);
- }
- duk_pop(ctx);
- /* ... */
-}
-
-void dukky_register_event_listener_for(duk_context *ctx,
- struct dom_element *ele,
- dom_string *name)
-{
- dom_event_listener *listen = NULL;
- dom_exception exc;
-
- /* ... */
- if (dukky_push_node(ctx, (struct dom_node *)ele) == false)
- return;
- /* ... node */
- duk_get_prop_string(ctx, -1, HANDLER_LISTENER_MAGIC);
- /* ... node handlers */
- duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
- /* ... node handlers name */
- if (duk_has_prop(ctx, -2)) {
- /* ... node handlers */
- duk_pop_2(ctx);
- /* ... */
- return;
- }
- /* ... node handlers */
- duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
- /* ... node handlers name */
- duk_push_boolean(ctx, true);
- /* ... node handlers name true */
- duk_put_prop(ctx, -3);
- /* ... node handlers */
- duk_pop_2(ctx);
- /* ... */
- exc = dom_event_listener_create(dukky_generic_event_handler, ctx,
- &listen);
- if (exc != DOM_NO_ERR) return;
- exc = dom_event_target_add_event_listener(
- ele, name, listen, false);
- if (exc != DOM_NO_ERR) {
- LOG("Unable to register listener for %p.%*s",
- ele, dom_string_length(name), dom_string_data(name));
- } else {
- LOG("have registered listener for %p.%*s",
- ele, dom_string_length(name), dom_string_data(name));
- }
- dom_event_listener_unref(listen);
-}
-
-
-void js_handle_new_element(jscontext *ctx, struct dom_element *node)
-{
- assert(ctx);
- assert(node);
- dom_namednodemap *map;
- dom_exception exc;
- dom_ulong idx;
- dom_ulong siz;
- dom_attr *attr = NULL;
- dom_string *key = NULL;
- dom_string *nodename;
- duk_bool_t is_body = false;
-
- exc = dom_node_get_node_name(node, &nodename);
- if (exc != DOM_NO_ERR) return;
-
- if (nodename == corestring_dom_BODY)
- is_body = true;
-
- dom_string_unref(nodename);
-
- exc = dom_node_get_attributes(node, &map);
- if (exc != DOM_NO_ERR) return;
- if (map == NULL) return;
-
- exc = dom_namednodemap_get_length(map, &siz);
- if (exc != DOM_NO_ERR) goto out;
-
- for (idx = 0; idx < siz; idx++) {
- exc = dom_namednodemap_item(map, idx, &attr);
- if (exc != DOM_NO_ERR) goto out;
- exc = dom_attr_get_name(attr, &key);
- if (exc != DOM_NO_ERR) goto out;
- if (is_body && (
- key == corestring_dom_onblur ||
- key == corestring_dom_onerror ||
- key == corestring_dom_onfocus ||
- key == corestring_dom_onload ||
- key == corestring_dom_onresize ||
- key == corestring_dom_onscroll)) {
- /* This is a forwarded event, it doesn't matter,
- * we should skip registering for it and later
- * we will register it for Window itself
- */
- goto skip_register;
- }
- if (dom_string_length(key) > 2) {
- /* Can be on* */
- const uint8_t *data = (const uint8_t *)dom_string_data(key);
- if (data[0] == 'o' && data[1] == 'n') {
- dom_string *sub = NULL;
- exc = dom_string_substr(
- key, 2, dom_string_length(key),
- &sub);
- if (exc == DOM_NO_ERR) {
- dukky_register_event_listener_for(
- CTX, node, sub);
- dom_string_unref(sub);
- }
- }
- }
- skip_register:
- dom_string_unref(key); key = NULL;
- dom_node_unref(attr); attr = NULL;
- }
-
-out:
- if (key != NULL)
- dom_string_unref(key);
-
- if (attr != NULL)
- dom_node_unref(attr);
-
- dom_namednodemap_unref(map);
-}
-
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt)
-{
- assert(ctx);
- /* ... */
- duk_get_global_string(CTX, EVENT_MAGIC);
- /* ... EVENT_MAP */
- duk_push_pointer(CTX, evt);
- /* ... EVENT_MAP eventptr */
- duk_del_prop(CTX, -2);
- /* ... EVENT_MAP */
- duk_pop(CTX);
- /* ... */
-}
-
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, struct dom_node *target)
-{
- dom_exception exc;
- dom_event *evt;
- dom_event_target *body;
-
- LOG("Event: %s (doc=%p, target=%p)", type, doc, target);
-
- /** @todo Make this more generic, this only handles load and only
- * targetting the window, so that we actually stand a chance of
- * getting 3.4 out.
- */
-
- if (target != NULL)
- /* Swallow non-Window-targetted events quietly */
- return true;
-
- if (strcmp(type, "load") != 0)
- /* Swallow non-load events quietly */
- return true;
-
- /* Okay, we're processing load, targetted at Window, do the single
- * thing which gets us there, which is to find the appropriate event
- * handler and call it. If we have no event handler on Window then
- * we divert to the body, and if there's no event handler there
- * we swallow the event silently
- */
-
- exc = dom_event_create(&evt);
- if (exc != DOM_NO_ERR) return true;
- exc = dom_event_init(evt, corestring_dom_load, false, false);
- if (exc != DOM_NO_ERR) {
- dom_event_unref(evt);
- return true;
- }
- /* ... */
- duk_get_global_string(CTX, HANDLER_MAGIC);
- /* ... handlers */
- duk_push_lstring(CTX, "load", 4);
- /* ... handlers "load" */
- duk_get_prop(CTX, -2);
- /* ... handlers handler? */
- if (duk_is_undefined(CTX, -1)) {
- /* No handler here, *try* and retrieve a handler from
- * the body
- */
- duk_pop(CTX);
- /* ... handlers */
- exc = dom_html_document_get_body(doc, &body);
- if (exc != DOM_NO_ERR) {
- dom_event_unref(evt);
- return true;
- }
- dukky_push_node(CTX, (struct dom_node *)body);
- /* ... handlers bodynode */
- if (dukky_get_current_value_of_event_handler(
- CTX, corestring_dom_load, body) == false) {
- /* ... handlers */
- duk_pop(CTX);
- return true;
- }
- /* ... handlers handler bodynode */
- duk_pop(CTX);
- }
- /* ... handlers handler */
- duk_insert(CTX, -2);
- /* ... handler handlers */
- duk_pop(CTX);
- /* ... handler */
- duk_push_global_object(CTX);
- /* ... handler Window */
- dukky_push_event(CTX, evt);
- /* ... handler Window event */
- (void) nsu_getmonotonic_ms(&ctx->exec_start_time);
- if (duk_pcall_method(CTX, 1) != 0) {
- /* Failed to run the handler */
- /* ... err */
- LOG("OH NOES! An error running a handler. Meh.");
- duk_get_prop_string(CTX, -1, "name");
- duk_get_prop_string(CTX, -2, "message");
- duk_get_prop_string(CTX, -3, "fileName");
- duk_get_prop_string(CTX, -4, "lineNumber");
- duk_get_prop_string(CTX, -5, "stack");
- /* ... err name message fileName lineNumber stack */
- LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(CTX, -5),
- duk_safe_to_string(CTX, -4));
- LOG(" was at: %s line %s", duk_safe_to_string(CTX, -3),
- duk_safe_to_string(CTX, -2));
- LOG(" Stack trace: %s", duk_safe_to_string(CTX, -1));
-
- duk_pop_n(CTX, 6);
- /* ... */
- js_event_cleanup(ctx, evt);
- dom_event_unref(evt);
- return true;
- }
- /* ... result */
- duk_pop(CTX);
- /* ... */
- js_event_cleanup(ctx, evt);
- dom_event_unref(evt);
- return true;
-}
diff --git a/javascript/duktape/dukky.h b/javascript/duktape/dukky.h
deleted file mode 100644
index 0c3ff0e25..000000000
--- a/javascript/duktape/dukky.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
- * Copyright 2015 Daniel Dilverstone <dsilvers@netsurf-browser.org>
- * Copyright 2016 Michael Drake <tlsa@netsurf-browser.org>
- *
- * 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/>.
- */
-
-/** \file
- * Duktapeish implementation of javascript engine functions, prototypes.
- */
-
-#ifndef DUKKY_H
-#define DUKKY_H
-
-#ifdef JS_DEBUG
-# define JS_LOG(format, args...) LOG(format , ##args)
-#else
-# define JS_LOG(format, ...) ((void) 0)
-#endif
-
-duk_ret_t dukky_create_object(duk_context *ctx, const char *name, int args);
-duk_bool_t dukky_push_node_stacked(duk_context *ctx);
-duk_bool_t dukky_push_node(duk_context *ctx, struct dom_node *node);
-void dukky_inject_not_ctr(duk_context *ctx, int idx, const char *name);
-void dukky_register_event_listener_for(duk_context *ctx,
- struct dom_element *ele,
- dom_string *name);
-bool dukky_get_current_value_of_event_handler(duk_context *ctx,
- dom_string *name,
- dom_event_target *et);
-
-#endif
diff --git a/javascript/duktape/duktape.c b/javascript/duktape/duktape.c
deleted file mode 100644
index eb4c77a04..000000000
--- a/javascript/duktape/duktape.c
+++ /dev/null
@@ -1,86513 +0,0 @@
-/* Omit from static analysis. */
-#ifndef __clang_analyzer__
-/*
- * Single source autogenerated distributable for Duktape 1.5.0.
- *
- * Git commit 83d557704ee63f68ab40b6fcb00995c9b3d6777c (v1.5.0).
- * Git branch master.
- *
- * See Duktape AUTHORS.rst and LICENSE.txt for copyright and
- * licensing information.
- */
-
-/* LICENSE.txt */
-/*
-* ===============
-* Duktape license
-* ===============
-*
-* (http://opensource.org/licenses/MIT)
-*
-* 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
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-*/
-/* AUTHORS.rst */
-/*
-* ===============
-* Duktape authors
-* ===============
-*
-* Copyright
-* =========
-*
-* Duktape copyrights are held by its authors. Each author has a copyright
-* to their contribution, and agrees to irrevocably license the contribution
-* under the Duktape ``LICENSE.txt``.
-*
-* Authors
-* =======
-*
-* Please include an e-mail address, a link to your GitHub profile, or something
-* similar to allow your contribution to be identified accurately.
-*
-* The following people have contributed code, website contents, or Wiki contents,
-* and agreed to irrevocably license their contributions under the Duktape
-* ``LICENSE.txt`` (in order of appearance):
-*
-* * Sami Vaarala <sami.vaarala@iki.fi>
-* * Niki Dobrev
-* * Andreas \u00d6man <andreas@lonelycoder.com>
-* * L\u00e1szl\u00f3 Lang\u00f3 <llango.u-szeged@partner.samsung.com>
-* * Legimet <legimet.calc@gmail.com>
-* * Karl Skomski <karl@skomski.com>
-* * Bruce Pascoe <fatcerberus1@gmail.com>
-* * Ren\u00e9 Hollander <rene@rene8888.at>
-* * Julien Hamaide (https://github.com/crazyjul)
-* * Sebastian G\u00f6tte (https://github.com/jaseg)
-*
-* Other contributions
-* ===================
-*
-* The following people have contributed something other than code (e.g. reported
-* bugs, provided ideas, etc; roughly in order of appearance):
-*
-* * Greg Burns
-* * Anthony Rabine
-* * Carlos Costa
-* * Aur\u00e9lien Bouilland
-* * Preet Desai (Pris Matic)
-* * judofyr (http://www.reddit.com/user/judofyr)
-* * Jason Woofenden
-* * Micha\u0142 Przyby\u015b
-* * Anthony Howe
-* * Conrad Pankoff
-* * Jim Schimpf
-* * Rajaran Gaunker (https://github.com/zimbabao)
-* * Andreas \u00d6man
-* * Doug Sanden
-* * Josh Engebretson (https://github.com/JoshEngebretson)
-* * Remo Eichenberger (https://github.com/remoe)
-* * Mamod Mehyar (https://github.com/mamod)
-* * David Demelier (https://github.com/markand)
-* * Tim Caswell (https://github.com/creationix)
-* * Mitchell Blank Jr (https://github.com/mitchblank)
-* * https://github.com/yushli
-* * Seo Sanghyeon (https://github.com/sanxiyn)
-* * Han ChoongWoo (https://github.com/tunz)
-* * Joshua Peek (https://github.com/josh)
-* * Bruce E. Pascoe (https://github.com/fatcerberus)
-* * https://github.com/Kelledin
-* * https://github.com/sstruchtrup
-* * Michael Drake (https://github.com/tlsa)
-* * https://github.com/chris-y
-* * Laurent Zubiaur (https://github.com/lzubiaur)
-* * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
-*
-* If you are accidentally missing from this list, send me an e-mail
-* (``sami.vaarala@iki.fi``) and I'll fix the omission.
-*/
-#line 1 "duk_internal.h"
-/*
- * Top-level include file to be used for all (internal) source files.
- *
- * Source files should not include individual header files, as they
- * have not been designed to be individually included.
- */
-
-#ifndef DUK_INTERNAL_H_INCLUDED
-#define DUK_INTERNAL_H_INCLUDED
-
-/*
- * The 'duktape.h' header provides the public API, but also handles all
- * compiler and platform specific feature detection, Duktape feature
- * resolution, inclusion of system headers, etc. These have been merged
- * because the public API is also dependent on e.g. detecting appropriate
- * C types which is quite platform/compiler specific especially for a non-C99
- * build. The public API is also dependent on the resolved feature set.
- *
- * Some actions taken by the merged header (such as including system headers)
- * are not appropriate for building a user application. The define
- * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some
- * sections depending on what is being built.
- */
-
-#define DUK_COMPILING_DUKTAPE
-#include "duktape.h"
-
-/*
- * User declarations, e.g. prototypes for user functions used by Duktape
- * macros. Concretely, if DUK_USE_PANIC_HANDLER is used and the macro
- * value calls a user function, it needs to be declared for Duktape
- * compilation to avoid warnings.
- */
-
-DUK_USE_USER_DECLARE()
-
-/*
- * Duktape includes (other than duk_features.h)
- *
- * The header files expect to be included in an order which satisfies header
- * dependencies correctly (the headers themselves don't include any other
- * includes). Forward declarations are used to break circular struct/typedef
- * dependencies.
- */
-
-#line 1 "duk_replacements.h"
-#ifndef DUK_REPLACEMENTS_H_INCLUDED
-#define DUK_REPLACEMENTS_H_INCLUDED
-
-#if !defined(DUK_SINGLE_FILE)
-#if defined(DUK_USE_COMPUTED_INFINITY)
-DUK_INTERNAL_DECL double duk_computed_infinity;
-#endif
-#if defined(DUK_USE_COMPUTED_NAN)
-DUK_INTERNAL_DECL double duk_computed_nan;
-#endif
-#if defined(DUK_USE_REPL_FPCLASSIFY)
-DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
-#endif
-#if defined(DUK_USE_REPL_SIGNBIT)
-DUK_INTERNAL_DECL int duk_repl_signbit(double x);
-#endif
-#if defined(DUK_USE_REPL_ISFINITE)
-DUK_INTERNAL_DECL int duk_repl_isfinite(double x);
-#endif
-#if defined(DUK_USE_REPL_ISNAN)
-DUK_INTERNAL_DECL int duk_repl_isnan(double x);
-#endif
-#if defined(DUK_USE_REPL_ISINF)
-DUK_INTERNAL_DECL int duk_repl_isinf(double x);
-#endif
-#endif /* !DUK_SINGLE_FILE */
-
-#endif /* DUK_REPLACEMENTS_H_INCLUDED */
-#line 1 "duk_jmpbuf.h"
-/*
- * Wrapper for jmp_buf.
- *
- * This is used because jmp_buf is an array type for backward compatibility.
- * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc,
- * behave more intuitively.
- *
- * http://en.wikipedia.org/wiki/Setjmp.h#Member_types
- */
-
-#ifndef DUK_JMPBUF_H_INCLUDED
-#define DUK_JMPBUF_H_INCLUDED
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
-struct duk_jmpbuf {
- duk_small_int_t dummy; /* unused */
-};
-#else
-struct duk_jmpbuf {
- DUK_JMPBUF_TYPE jb;
-};
-#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.
- */
-
-#ifndef DUK_FORWDECL_H_INCLUDED
-#define DUK_FORWDECL_H_INCLUDED
-
-/*
- * Forward declarations
- */
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
-class duk_internal_exception;
-#else
-struct duk_jmpbuf;
-#endif
-
-/* duk_tval intentionally skipped */
-struct duk_heaphdr;
-struct duk_heaphdr_string;
-struct duk_hstring;
-struct duk_hstring_external;
-struct duk_hobject;
-struct duk_hcompiledfunction;
-struct duk_hnativefunction;
-struct duk_hthread;
-struct duk_hbufferobject;
-struct duk_hbuffer;
-struct duk_hbuffer_fixed;
-struct duk_hbuffer_dynamic;
-struct duk_hbuffer_external;
-
-struct duk_propaccessor;
-union duk_propvalue;
-struct duk_propdesc;
-
-struct duk_heap;
-struct duk_breakpoint;
-
-struct duk_activation;
-struct duk_catcher;
-struct duk_strcache;
-struct duk_ljstate;
-struct duk_strtab_entry;
-
-#ifdef DUK_USE_DEBUG
-struct duk_fixedbuffer;
-#endif
-
-struct duk_bitdecoder_ctx;
-struct duk_bitencoder_ctx;
-struct duk_bufwriter_ctx;
-
-struct duk_token;
-struct duk_re_token;
-struct duk_lexer_point;
-struct duk_lexer_ctx;
-struct duk_lexer_codepoint;
-
-struct duk_compiler_instr;
-struct duk_compiler_func;
-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;
-typedef struct duk_heaphdr_string duk_heaphdr_string;
-typedef struct duk_hstring duk_hstring;
-typedef struct duk_hstring_external duk_hstring_external;
-typedef struct duk_hobject duk_hobject;
-typedef struct duk_hcompiledfunction duk_hcompiledfunction;
-typedef struct duk_hnativefunction duk_hnativefunction;
-typedef struct duk_hbufferobject duk_hbufferobject;
-typedef struct duk_hthread duk_hthread;
-typedef struct duk_hbuffer duk_hbuffer;
-typedef struct duk_hbuffer_fixed duk_hbuffer_fixed;
-typedef struct duk_hbuffer_dynamic duk_hbuffer_dynamic;
-typedef struct duk_hbuffer_external duk_hbuffer_external;
-
-typedef struct duk_propaccessor duk_propaccessor;
-typedef union duk_propvalue duk_propvalue;
-typedef struct duk_propdesc duk_propdesc;
-
-typedef struct duk_heap duk_heap;
-typedef struct duk_breakpoint duk_breakpoint;
-
-typedef struct duk_activation duk_activation;
-typedef struct duk_catcher duk_catcher;
-typedef struct duk_strcache duk_strcache;
-typedef struct duk_ljstate duk_ljstate;
-typedef struct duk_strtab_entry duk_strtab_entry;
-
-#ifdef DUK_USE_DEBUG
-typedef struct duk_fixedbuffer duk_fixedbuffer;
-#endif
-
-typedef struct duk_bitdecoder_ctx duk_bitdecoder_ctx;
-typedef struct duk_bitencoder_ctx duk_bitencoder_ctx;
-typedef struct duk_bufwriter_ctx duk_bufwriter_ctx;
-
-typedef struct duk_token duk_token;
-typedef struct duk_re_token duk_re_token;
-typedef struct duk_lexer_point duk_lexer_point;
-typedef struct duk_lexer_ctx duk_lexer_ctx;
-typedef struct duk_lexer_codepoint duk_lexer_codepoint;
-
-typedef struct duk_compiler_instr duk_compiler_instr;
-typedef struct duk_compiler_func duk_compiler_func;
-typedef struct duk_compiler_ctx duk_compiler_ctx;
-
-typedef struct duk_re_matcher_ctx duk_re_matcher_ctx;
-typedef struct duk_re_compiler_ctx duk_re_compiler_ctx;
-
-#endif /* DUK_FORWDECL_H_INCLUDED */
-#line 1 "duk_tval.h"
-/*
- * Tagged type definition (duk_tval) and accessor macros.
- *
- * Access all fields through the accessor macros, as the representation
- * is quite tricky.
- *
- * There are two packed type alternatives: an 8-byte representation
- * based on an IEEE double (preferred for compactness), and a 12-byte
- * representation (portability). The latter is needed also in e.g.
- * 64-bit environments (it usually pads to 16 bytes per value).
- *
- * Selecting the tagged type format involves many trade-offs (memory
- * use, size and performance of generated code, portability, etc),
- * see doc/types.rst for a detailed discussion (especially of how the
- * IEEE double format is used to pack tagged values).
- *
- * NB: because macro arguments are often expressions, macros should
- * avoid evaluating their argument more than once.
- */
-
-#ifndef DUK_TVAL_H_INCLUDED
-#define DUK_TVAL_H_INCLUDED
-
-/* sanity */
-#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE)
-#error unsupported: cannot determine byte order variant
-#endif
-
-#if defined(DUK_USE_PACKED_TVAL)
-/* ======================================================================== */
-
-/*
- * Packed 8-byte representation
- */
-
-/* use duk_double_union as duk_tval directly */
-typedef union duk_double_union duk_tval;
-
-/* tags */
-#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */
-/* avoid tag 0xfff0, no risk of confusion with negative infinity */
-#if defined(DUK_USE_FASTINT)
-#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */
-#endif
-#define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */
-#define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */
-#define DUK_TAG_NULL 0xfff4UL /* embed: nothing */
-#define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */
-/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */
-#define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */
-#define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */
-#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */
-#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */
-#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */
-
-/* for convenience */
-#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL
-#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL
-
-/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
-#if defined(DUK_USE_64BIT_OPS)
-#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
- } while (0)
-#else
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
- } while (0)
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK__TVAL_SET_TAGGEDPOINTER(v,h,tag) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
- } while (0)
-#endif /* DUK_USE_64BIT_OPS */
-
-#if defined(DUK_USE_64BIT_OPS)
-/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
-#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
- ((duk_uint64_t) (flags)) | \
- (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
- } while (0)
-#else
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
- (((duk_uint64_t) (flags)) << 32) | \
- ((duk_uint64_t) (duk_uint32_t) (fp)); \
- } while (0)
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK__TVAL_SET_LIGHTFUNC(v,fp,flags) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
- } while (0)
-#endif /* DUK_USE_64BIT_OPS */
-
-#if defined(DUK_USE_FASTINT)
-/* Note: masking is done for 'i' to deal with negative numbers correctly */
-#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_SET_FASTINT(v,i) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
- } while (0)
-#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
- (v)->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
- (v)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
- } while (0)
-#else
-#define DUK__TVAL_SET_FASTINT(v,i) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \
- } while (0)
-#define DUK__TVAL_SET_FASTINT_U32(v,i) do { \
- (v)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
- } while (0)
-#endif
-
-#define DUK__TVAL_SET_FASTINT_I32(v,i) do { \
- duk_int64_t duk__tmp = (duk_int64_t) (i); \
- DUK_TVAL_SET_FASTINT((v), duk__tmp); \
- } while (0)
-
-/* XXX: clumsy sign extend and masking of 16 topmost bits */
-#if defined(DUK_USE_DOUBLE_ME)
-#define DUK__TVAL_GET_FASTINT(v) (((duk_int64_t) ((((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI0]) << 32) | ((duk_uint64_t) (v)->ui[DUK_DBL_IDX_UI1]))) << 16 >> 16)
-#else
-#define DUK__TVAL_GET_FASTINT(v) ((((duk_int64_t) (v)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
-#endif
-#define DUK__TVAL_GET_FASTINT_U32(v) ((v)->ui[DUK_DBL_IDX_UI1])
-#define DUK__TVAL_GET_FASTINT_I32(v) ((duk_int32_t) (v)->ui[DUK_DBL_IDX_UI1])
-#endif /* DUK_USE_FASTINT */
-
-#define DUK_TVAL_SET_UNDEFINED(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
- } while (0)
-#define DUK_TVAL_SET_UNUSED(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
- } while (0)
-#define DUK_TVAL_SET_NULL(v) do { \
- (v)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
- } while (0)
-
-#define DUK_TVAL_SET_BOOLEAN(v,val) DUK_DBLUNION_SET_HIGH32((v), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
-
-#define DUK_TVAL_SET_NAN(v) DUK_DBLUNION_SET_NAN_FULL((v))
-
-/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_DOUBLE(v,d) do { \
- duk_double_t duk__dblval; \
- duk__dblval = (d); \
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
- DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
- } while (0)
-#define DUK_TVAL_SET_FASTINT(v,i) DUK__TVAL_SET_FASTINT((v), (i))
-#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK__TVAL_SET_FASTINT_I32((v), (i))
-#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK__TVAL_SET_FASTINT_U32((v), (i))
-#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) duk_tval_set_number_chkfast((v), (d))
-#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
- duk_tval *duk__tv; \
- duk_double_t duk__d; \
- duk__tv = (v); \
- if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
- duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
- DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
- } \
- } while (0)
-#else
-#define DUK_TVAL_SET_DOUBLE(v,d) do { \
- duk_double_t duk__dblval; \
- duk__dblval = (d); \
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
- DUK_DBLUNION_SET_DOUBLE((v), duk__dblval); \
- } while (0)
-#define DUK_TVAL_SET_FASTINT(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i)) /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
-#define DUK_TVAL_SET_FASTINT_U32(v,i) DUK_TVAL_SET_DOUBLE((v), (duk_double_t) (i))
-#define DUK_TVAL_SET_NUMBER_CHKFAST(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_SET_NUMBER(v,d) DUK_TVAL_SET_DOUBLE((v), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
-#endif
-
-#define DUK_TVAL_SET_LIGHTFUNC(v,fp,flags) DUK__TVAL_SET_LIGHTFUNC((v), (fp), (flags))
-#define DUK_TVAL_SET_STRING(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_STRING)
-#define DUK_TVAL_SET_OBJECT(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_OBJECT)
-#define DUK_TVAL_SET_BUFFER(v,h) DUK__TVAL_SET_TAGGEDPOINTER((v), (h), DUK_TAG_BUFFER)
-#define DUK_TVAL_SET_POINTER(v,p) DUK__TVAL_SET_TAGGEDPOINTER((v), (p), DUK_TAG_POINTER)
-
-#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
-
-/* getters */
-#define DUK_TVAL_GET_BOOLEAN(v) ((int) (v)->us[DUK_DBL_IDX_US1])
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
-#define DUK_TVAL_GET_FASTINT(v) DUK__TVAL_GET_FASTINT((v))
-#define DUK_TVAL_GET_FASTINT_U32(v) DUK__TVAL_GET_FASTINT_U32((v))
-#define DUK_TVAL_GET_FASTINT_I32(v) DUK__TVAL_GET_FASTINT_I32((v))
-#define DUK_TVAL_GET_NUMBER(v) duk_tval_get_number_packed((v))
-#else
-#define DUK_TVAL_GET_NUMBER(v) ((v)->d)
-#define DUK_TVAL_GET_DOUBLE(v) ((v)->d)
-#endif
-#define DUK_TVAL_GET_LIGHTFUNC(v,out_fp,out_flags) do { \
- (out_flags) = (v)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
- (out_fp) = (duk_c_function) (v)->ui[DUK_DBL_IDX_UI1]; \
- } while (0)
-#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(v) ((duk_c_function) ((v)->ui[DUK_DBL_IDX_UI1]))
-#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(v) (((int) (v)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
-#define DUK_TVAL_GET_STRING(v) ((duk_hstring *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_OBJECT(v) ((duk_hobject *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_BUFFER(v) ((duk_hbuffer *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_POINTER(v) ((void *) (v)->vp[DUK_DBL_IDX_VP1])
-#define DUK_TVAL_GET_HEAPHDR(v) ((duk_heaphdr *) (v)->vp[DUK_DBL_IDX_VP1])
-
-/* decoding */
-#define DUK_TVAL_GET_TAG(v) ((duk_small_uint_t) (v)->us[DUK_DBL_IDX_US0])
-
-#define DUK_TVAL_IS_UNDEFINED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNDEFINED)
-#define DUK_TVAL_IS_UNUSED(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_UNUSED)
-#define DUK_TVAL_IS_NULL(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_NULL)
-#define DUK_TVAL_IS_BOOLEAN(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BOOLEAN)
-#define DUK_TVAL_IS_BOOLEAN_TRUE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
-#define DUK_TVAL_IS_BOOLEAN_FALSE(v) ((v)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
-#define DUK_TVAL_IS_LIGHTFUNC(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_LIGHTFUNC)
-#define DUK_TVAL_IS_STRING(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_STRING)
-#define DUK_TVAL_IS_OBJECT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_OBJECT)
-#define DUK_TVAL_IS_BUFFER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_BUFFER)
-#define DUK_TVAL_IS_POINTER(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_POINTER)
-#if defined(DUK_USE_FASTINT)
-/* 0xfff0 is -Infinity */
-#define DUK_TVAL_IS_DOUBLE(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
-#define DUK_TVAL_IS_FASTINT(v) (DUK_TVAL_GET_TAG((v)) == DUK_TAG_FASTINT)
-#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff1UL)
-#else
-#define DUK_TVAL_IS_NUMBER(v) (DUK_TVAL_GET_TAG((v)) <= 0xfff0UL)
-#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
-#endif
-
-/* This is performance critical because it appears in every DECREF. */
-#define DUK_TVAL_IS_HEAP_ALLOCATED(v) (DUK_TVAL_GET_TAG((v)) >= DUK_TAG_STRING)
-
-#if defined(DUK_USE_FASTINT)
-DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv);
-#endif
-
-#else /* DUK_USE_PACKED_TVAL */
-/* ======================================================================== */
-
-/*
- * Portable 12-byte representation
- */
-
-/* Note: not initializing all bytes is normally not an issue: Duktape won't
- * read or use the uninitialized bytes so valgrind won't issue warnings.
- * In some special cases a harmless valgrind warning may be issued though.
- * For example, the DumpHeap debugger command writes out a compiled function's
- * 'data' area as is, including any uninitialized bytes, which causes a
- * valgrind warning.
- */
-
-typedef struct duk_tval_struct duk_tval;
-
-struct duk_tval_struct {
- duk_small_uint_t t;
- duk_small_uint_t v_extra;
- union {
- duk_double_t d;
- duk_small_int_t i;
-#if defined(DUK_USE_FASTINT)
- duk_int64_t fi; /* if present, forces 16-byte duk_tval */
-#endif
- void *voidptr;
- duk_hstring *hstring;
- duk_hobject *hobject;
- duk_hcompiledfunction *hcompiledfunction;
- duk_hnativefunction *hnativefunction;
- duk_hthread *hthread;
- duk_hbuffer *hbuffer;
- duk_heaphdr *heaphdr;
- duk_c_function lightfunc;
- } v;
-};
-
-#define DUK__TAG_NUMBER 0 /* not exposed */
-#if defined(DUK_USE_FASTINT)
-#define DUK_TAG_FASTINT 1
-#endif
-#define DUK_TAG_UNDEFINED 2
-#define DUK_TAG_NULL 3
-#define DUK_TAG_BOOLEAN 4
-#define DUK_TAG_POINTER 5
-#define DUK_TAG_LIGHTFUNC 6
-#define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */
-#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */
-#define DUK_TAG_OBJECT 9
-#define DUK_TAG_BUFFER 10
-
-/* DUK__TAG_NUMBER is intentionally first, as it is the default clause in code
- * to support the 8-byte representation. Further, it is a non-heap-allocated
- * type so it should come before DUK_TAG_STRING. Finally, it should not break
- * the tag value ranges covered by case-clauses in a switch-case.
- */
-
-/* setters */
-#define DUK_TVAL_SET_UNDEFINED(tv) do { \
- (tv)->t = DUK_TAG_UNDEFINED; \
- } while (0)
-
-#define DUK_TVAL_SET_UNUSED(tv) do { \
- (tv)->t = DUK_TAG_UNUSED; \
- } while (0)
-
-#define DUK_TVAL_SET_NULL(tv) do { \
- (tv)->t = DUK_TAG_NULL; \
- } while (0)
-
-#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \
- (tv)->t = DUK_TAG_BOOLEAN; \
- (tv)->v.i = (val); \
- } while (0)
-
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_DOUBLE(tv,val) do { \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = (val); \
- } while (0)
-#define DUK_TVAL_SET_FASTINT(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (val); \
- } while (0)
-#define DUK_TVAL_SET_FASTINT_U32(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (duk_int64_t) (val); \
- } while (0)
-#define DUK_TVAL_SET_FASTINT_I32(tv,val) do { \
- (tv)->t = DUK_TAG_FASTINT; \
- (tv)->v.fi = (duk_int64_t) (val); \
- } while (0)
-#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
- duk_tval_set_number_chkfast((tv), (d))
-#define DUK_TVAL_SET_NUMBER(tv,val) \
- DUK_TVAL_SET_DOUBLE((tv), (val))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { \
- duk_tval *duk__tv; \
- duk_double_t duk__d; \
- duk__tv = (v); \
- if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
- duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
- DUK_TVAL_SET_NUMBER_CHKFAST(duk__tv, duk__d); \
- } \
- } while (0)
-#else
-#define DUK_TVAL_SET_DOUBLE(tv,d) \
- DUK_TVAL_SET_NUMBER((tv), (d))
-#define DUK_TVAL_SET_FASTINT(tv,val) \
- DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_U32(tv,val) \
- DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
-#define DUK_TVAL_SET_FASTINT_I32(tv,val) \
- DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
-#define DUK_TVAL_SET_NUMBER(tv,val) do { \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = (val); \
- } while (0)
-#define DUK_TVAL_SET_NUMBER_CHKFAST(tv,d) \
- DUK_TVAL_SET_NUMBER((tv), (d))
-#define DUK_TVAL_CHKFAST_INPLACE(v) do { } while (0)
-#endif /* DUK_USE_FASTINT */
-
-#define DUK_TVAL_SET_POINTER(tv,hptr) do { \
- (tv)->t = DUK_TAG_POINTER; \
- (tv)->v.voidptr = (hptr); \
- } while (0)
-
-#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
- (tv)->t = DUK_TAG_LIGHTFUNC; \
- (tv)->v_extra = (flags); \
- (tv)->v.lightfunc = (duk_c_function) (fp); \
- } while (0)
-
-#define DUK_TVAL_SET_STRING(tv,hptr) do { \
- (tv)->t = DUK_TAG_STRING; \
- (tv)->v.hstring = (hptr); \
- } while (0)
-
-#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \
- (tv)->t = DUK_TAG_OBJECT; \
- (tv)->v.hobject = (hptr); \
- } while (0)
-
-#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \
- (tv)->t = DUK_TAG_BUFFER; \
- (tv)->v.hbuffer = (hptr); \
- } while (0)
-
-#define DUK_TVAL_SET_NAN(tv) do { \
- /* in non-packed representation we don't care about which NaN is used */ \
- (tv)->t = DUK__TAG_NUMBER; \
- (tv)->v.d = DUK_DOUBLE_NAN; \
- } while (0)
-
-#define DUK_TVAL_SET_TVAL(v,x) do { *(v) = *(x); } while (0)
-
-/* getters */
-#define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i)
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
-#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
-#define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi))
-#define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi))
-#if 0
-#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
- (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \
- DUK_TVAL_GET_DOUBLE((tv)))
-#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv))
-#else
-/* This seems reasonable overall. */
-#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
- duk_tval_get_number_unpacked_fastint((tv)) : \
- DUK_TVAL_GET_DOUBLE((tv)))
-#endif
-#else
-#define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d)
-#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
-#endif /* DUK_USE_FASTINT */
-#define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr)
-#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
- (out_flags) = (duk_uint32_t) (tv)->v_extra; \
- (out_fp) = (tv)->v.lightfunc; \
- } while (0)
-#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
-#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra))
-#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
-#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
-#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
-#define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr)
-
-/* decoding */
-#define DUK_TVAL_GET_TAG(tv) ((tv)->t)
-#define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED)
-#define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED)
-#define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL)
-#define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN)
-#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
-#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK__TAG_NUMBER)
-#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT)
-#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER || \
- (tv)->t == DUK_TAG_FASTINT)
-#else
-#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK__TAG_NUMBER)
-#define DUK_TVAL_IS_DOUBLE(v) DUK_TVAL_IS_NUMBER((v))
-#endif /* DUK_USE_FASTINT */
-#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER)
-#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC)
-#define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING)
-#define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT)
-#define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER)
-
-/* This is performance critical because it's needed for every DECREF.
- * Take advantage of the fact that the first heap allocated tag is 8,
- * so that bit 3 is set for all heap allocated tags (and never set for
- * non-heap-allocated tags).
- */
-#if 0
-#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING)
-#endif
-#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08)
-
-#if defined(DUK_USE_FASTINT)
-#if 0
-DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv);
-#endif
-DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
-#endif
-
-#endif /* DUK_USE_PACKED_TVAL */
-
-/*
- * Convenience (independent of representation)
- */
-
-#define DUK_TVAL_SET_BOOLEAN_TRUE(v) DUK_TVAL_SET_BOOLEAN(v, 1)
-#define DUK_TVAL_SET_BOOLEAN_FALSE(v) DUK_TVAL_SET_BOOLEAN(v, 0)
-
-/* Lightfunc flags packing and unpacking. */
-/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss## */
-#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
- ((((duk_int32_t) (lf_flags)) << 16) >> 24)
-#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
- (((lf_flags) >> 4) & 0x0f)
-#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
- ((lf_flags) & 0x0f)
-#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
- (((magic) & 0xff) << 8) | ((length) << 4) | (nargs)
-
-#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
-#define DUK_LFUNC_NARGS_MIN 0x00
-#define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */
-#define DUK_LFUNC_LENGTH_MIN 0x00
-#define DUK_LFUNC_LENGTH_MAX 0x0f
-#define DUK_LFUNC_MAGIC_MIN (-0x80)
-#define DUK_LFUNC_MAGIC_MAX 0x7f
-
-/* fastint constants etc */
-#if defined(DUK_USE_FASTINT)
-#define DUK_FASTINT_MIN (-0x800000000000LL)
-#define DUK_FASTINT_MAX 0x7fffffffffffLL
-#define DUK_FASTINT_BITS 48
-
-DUK_INTERNAL_DECL void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x);
-#endif
-
-#endif /* DUK_TVAL_H_INCLUDED */
-#line 1 "duk_builtins.h"
-/*
- * Automatically generated by genbuiltins.py, do not edit!
- */
-
-#ifndef DUK_BUILTINS_H_INCLUDED
-#define DUK_BUILTINS_H_INCLUDED
-
-#if defined(DUK_USE_ROM_STRINGS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
-#else /* DUK_USE_ROM_STRINGS */
-#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */
-#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
-#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED)
-#define DUK_STRIDX_UC_NULL 1 /* 'Null' */
-#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
-#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
-#define DUK_STRIDX_UC_ARGUMENTS 2 /* 'Arguments' */
-#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
-#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
-#define DUK_STRIDX_UC_OBJECT 3 /* 'Object' */
-#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
-#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
-#define DUK_STRIDX_UC_FUNCTION 4 /* 'Function' */
-#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
-#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
-#define DUK_STRIDX_ARRAY 5 /* 'Array' */
-#define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
-#define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
-#define DUK_STRIDX_UC_STRING 6 /* 'String' */
-#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
-#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
-#define DUK_STRIDX_UC_BOOLEAN 7 /* 'Boolean' */
-#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
-#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
-#define DUK_STRIDX_UC_NUMBER 8 /* 'Number' */
-#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
-#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
-#define DUK_STRIDX_DATE 9 /* 'Date' */
-#define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
-#define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
-#define DUK_STRIDX_REG_EXP 10 /* 'RegExp' */
-#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
-#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
-#define DUK_STRIDX_UC_ERROR 11 /* 'Error' */
-#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
-#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
-#define DUK_STRIDX_MATH 12 /* 'Math' */
-#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
-#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
-#define DUK_STRIDX_JSON 13 /* 'JSON' */
-#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
-#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
-#define DUK_STRIDX_EMPTY_STRING 14 /* '' */
-#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
-#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
-#define DUK_STRIDX_ARRAY_BUFFER 15 /* 'ArrayBuffer' */
-#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
-#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
-#define DUK_STRIDX_DATA_VIEW 16 /* 'DataView' */
-#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
-#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
-#define DUK_STRIDX_INT8_ARRAY 17 /* 'Int8Array' */
-#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
-#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
-#define DUK_STRIDX_UINT8_ARRAY 18 /* 'Uint8Array' */
-#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
-#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
-#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 19 /* 'Uint8ClampedArray' */
-#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
-#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
-#define DUK_STRIDX_INT16_ARRAY 20 /* 'Int16Array' */
-#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
-#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
-#define DUK_STRIDX_UINT16_ARRAY 21 /* 'Uint16Array' */
-#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
-#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
-#define DUK_STRIDX_INT32_ARRAY 22 /* 'Int32Array' */
-#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
-#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
-#define DUK_STRIDX_UINT32_ARRAY 23 /* 'Uint32Array' */
-#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
-#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
-#define DUK_STRIDX_FLOAT32_ARRAY 24 /* 'Float32Array' */
-#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
-#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
-#define DUK_STRIDX_FLOAT64_ARRAY 25 /* 'Float64Array' */
-#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
-#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
-#define DUK_STRIDX_GLOBAL 26 /* 'global' */
-#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
-#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
-#define DUK_STRIDX_OBJ_ENV 27 /* 'ObjEnv' */
-#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
-#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
-#define DUK_STRIDX_DEC_ENV 28 /* 'DecEnv' */
-#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
-#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
-#define DUK_STRIDX_UC_BUFFER 29 /* 'Buffer' */
-#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
-#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
-#define DUK_STRIDX_UC_POINTER 30 /* 'Pointer' */
-#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
-#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
-#define DUK_STRIDX_UC_THREAD 31 /* 'Thread' */
-#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
-#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
-#define DUK_STRIDX_EVAL 32 /* 'eval' */
-#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
-#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
-#define DUK_STRIDX_DEFINE_PROPERTY 33 /* 'defineProperty' */
-#define DUK_HEAP_STRING_DEFINE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFINE_PROPERTY)
-#define DUK_HTHREAD_STRING_DEFINE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFINE_PROPERTY)
-#define DUK_STRIDX_VALUE 34 /* 'value' */
-#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
-#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
-#define DUK_STRIDX_WRITABLE 35 /* 'writable' */
-#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
-#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
-#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */
-#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
-#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
-#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */
-#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
-#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
-#define DUK_STRIDX_JOIN 38 /* 'join' */
-#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
-#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
-#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */
-#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
-#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
-#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */
-#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
-#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
-#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */
-#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
-#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
-#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */
-#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
-#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
-#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */
-#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
-#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
-#define DUK_STRIDX_SOURCE 44 /* 'source' */
-#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
-#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
-#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */
-#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
-#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
-#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */
-#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
-#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
-#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */
-#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
-#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
-#define DUK_STRIDX_ESCAPED_EMPTY_REGEXP 48 /* '(?:)' */
-#define DUK_HEAP_STRING_ESCAPED_EMPTY_REGEXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
-#define DUK_HTHREAD_STRING_ESCAPED_EMPTY_REGEXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ESCAPED_EMPTY_REGEXP)
-#define DUK_STRIDX_INDEX 49 /* 'index' */
-#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
-#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
-#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */
-#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
-#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
-#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */
-#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
-#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
-#define DUK_STRIDX_MESSAGE 52 /* 'message' */
-#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
-#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
-#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */
-#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
-#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
-#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */
-#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
-#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
-#define DUK_STRIDX_LC_STRING 55 /* 'string' */
-#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
-#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
-#define DUK_STRIDX_LC_OBJECT 56 /* 'object' */
-#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
-#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
-#define DUK_STRIDX_LC_UNDEFINED 57 /* 'undefined' */
-#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
-#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
-#define DUK_STRIDX_NAN 58 /* 'NaN' */
-#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
-#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
-#define DUK_STRIDX_INFINITY 59 /* 'Infinity' */
-#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
-#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
-#define DUK_STRIDX_MINUS_INFINITY 60 /* '-Infinity' */
-#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
-#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
-#define DUK_STRIDX_MINUS_ZERO 61 /* '-0' */
-#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
-#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
-#define DUK_STRIDX_COMMA 62 /* ',' */
-#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
-#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
-#define DUK_STRIDX_SPACE 63 /* ' ' */
-#define DUK_HEAP_STRING_SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SPACE)
-#define DUK_HTHREAD_STRING_SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SPACE)
-#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */
-#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
-#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
-#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */
-#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
-#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
-#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */
-#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
-#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
-#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */
-#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
-#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
-#define DUK_STRIDX_CALLEE 68 /* 'callee' */
-#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
-#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
-#define DUK_STRIDX_CALLER 69 /* 'caller' */
-#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
-#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
-#define DUK_STRIDX_HAS 70 /* 'has' */
-#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
-#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
-#define DUK_STRIDX_GET 71 /* 'get' */
-#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
-#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
-#define DUK_STRIDX_DELETE_PROPERTY 72 /* 'deleteProperty' */
-#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
-#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
-#define DUK_STRIDX_ENUMERATE 73 /* 'enumerate' */
-#define DUK_HEAP_STRING_ENUMERATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERATE)
-#define DUK_HTHREAD_STRING_ENUMERATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERATE)
-#define DUK_STRIDX_OWN_KEYS 74 /* 'ownKeys' */
-#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
-#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
-#define DUK_STRIDX_SET_PROTOTYPE_OF 75 /* 'setPrototypeOf' */
-#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
-#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
-#define DUK_STRIDX___PROTO__ 76 /* '__proto__' */
-#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
-#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
-#define DUK_STRIDX_REQUIRE 77 /* 'require' */
-#define DUK_HEAP_STRING_REQUIRE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REQUIRE)
-#define DUK_HTHREAD_STRING_REQUIRE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REQUIRE)
-#define DUK_STRIDX_ID 78 /* 'id' */
-#define DUK_HEAP_STRING_ID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ID)
-#define DUK_HTHREAD_STRING_ID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ID)
-#define DUK_STRIDX_EXPORTS 79 /* 'exports' */
-#define DUK_HEAP_STRING_EXPORTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORTS)
-#define DUK_HTHREAD_STRING_EXPORTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORTS)
-#define DUK_STRIDX_FILENAME 80 /* 'filename' */
-#define DUK_HEAP_STRING_FILENAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILENAME)
-#define DUK_HTHREAD_STRING_FILENAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILENAME)
-#define DUK_STRIDX_TO_STRING 81 /* 'toString' */
-#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
-#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
-#define DUK_STRIDX_TO_JSON 82 /* 'toJSON' */
-#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
-#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
-#define DUK_STRIDX_TYPE 83 /* 'type' */
-#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
-#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
-#define DUK_STRIDX_DATA 84 /* 'data' */
-#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
-#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
-#define DUK_STRIDX_LENGTH 85 /* 'length' */
-#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
-#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
-#define DUK_STRIDX_BYTE_LENGTH 86 /* 'byteLength' */
-#define DUK_HEAP_STRING_BYTE_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_LENGTH)
-#define DUK_HTHREAD_STRING_BYTE_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_LENGTH)
-#define DUK_STRIDX_BYTE_OFFSET 87 /* 'byteOffset' */
-#define DUK_HEAP_STRING_BYTE_OFFSET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTE_OFFSET)
-#define DUK_HTHREAD_STRING_BYTE_OFFSET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTE_OFFSET)
-#define DUK_STRIDX_BYTES_PER_ELEMENT 88 /* 'BYTES_PER_ELEMENT' */
-#define DUK_HEAP_STRING_BYTES_PER_ELEMENT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BYTES_PER_ELEMENT)
-#define DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BYTES_PER_ELEMENT)
-#define DUK_STRIDX_SET 89 /* 'set' */
-#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
-#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
-#define DUK_STRIDX_STACK 90 /* 'stack' */
-#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
-#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
-#define DUK_STRIDX_PC 91 /* 'pc' */
-#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
-#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
-#define DUK_STRIDX_LINE_NUMBER 92 /* 'lineNumber' */
-#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
-#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
-#define DUK_STRIDX_INT_TRACEDATA 93 /* '\xffTracedata' */
-#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
-#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
-#define DUK_STRIDX_NAME 94 /* 'name' */
-#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
-#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
-#define DUK_STRIDX_FILE_NAME 95 /* 'fileName' */
-#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
-#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
-#define DUK_STRIDX_LC_BUFFER 96 /* 'buffer' */
-#define DUK_HEAP_STRING_LC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BUFFER)
-#define DUK_HTHREAD_STRING_LC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BUFFER)
-#define DUK_STRIDX_LC_POINTER 97 /* 'pointer' */
-#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
-#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
-#define DUK_STRIDX_INT_VALUE 98 /* '\xffValue' */
-#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
-#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
-#define DUK_STRIDX_INT_NEXT 99 /* '\xffNext' */
-#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
-#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
-#define DUK_STRIDX_INT_BYTECODE 100 /* '\xffBytecode' */
-#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
-#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
-#define DUK_STRIDX_INT_FORMALS 101 /* '\xffFormals' */
-#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
-#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
-#define DUK_STRIDX_INT_VARMAP 102 /* '\xffVarmap' */
-#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
-#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
-#define DUK_STRIDX_INT_LEXENV 103 /* '\xffLexenv' */
-#define DUK_HEAP_STRING_INT_LEXENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_LEXENV)
-#define DUK_HTHREAD_STRING_INT_LEXENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_LEXENV)
-#define DUK_STRIDX_INT_VARENV 104 /* '\xffVarenv' */
-#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
-#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
-#define DUK_STRIDX_INT_SOURCE 105 /* '\xffSource' */
-#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
-#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
-#define DUK_STRIDX_INT_PC2LINE 106 /* '\xffPc2line' */
-#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
-#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
-#define DUK_STRIDX_INT_ARGS 107 /* '\xffArgs' */
-#define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
-#define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
-#define DUK_STRIDX_INT_MAP 108 /* '\xffMap' */
-#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
-#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
-#define DUK_STRIDX_INT_FINALIZER 109 /* '\xffFinalizer' */
-#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
-#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
-#define DUK_STRIDX_INT_HANDLER 110 /* '\xffHandler' */
-#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER)
-#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER)
-#define DUK_STRIDX_INT_CALLEE 111 /* '\xffCallee' */
-#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
-#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
-#define DUK_STRIDX_INT_THREAD 112 /* '\xffThread' */
-#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
-#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
-#define DUK_STRIDX_INT_REGBASE 113 /* '\xffRegbase' */
-#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
-#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
-#define DUK_STRIDX_INT_TARGET 114 /* '\xffTarget' */
-#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
-#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
-#define DUK_STRIDX_INT_THIS 115 /* '\xffThis' */
-#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
-#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
-#define DUK_STRIDX_COMPILE 116 /* 'compile' */
-#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
-#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
-#define DUK_STRIDX_INPUT 117 /* 'input' */
-#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
-#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
-#define DUK_STRIDX_ERR_CREATE 118 /* 'errCreate' */
-#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
-#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
-#define DUK_STRIDX_ERR_THROW 119 /* 'errThrow' */
-#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
-#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
-#define DUK_STRIDX_MOD_SEARCH 120 /* 'modSearch' */
-#define DUK_HEAP_STRING_MOD_SEARCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_SEARCH)
-#define DUK_HTHREAD_STRING_MOD_SEARCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_SEARCH)
-#define DUK_STRIDX_MOD_LOADED 121 /* 'modLoaded' */
-#define DUK_HEAP_STRING_MOD_LOADED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MOD_LOADED)
-#define DUK_HTHREAD_STRING_MOD_LOADED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MOD_LOADED)
-#define DUK_STRIDX_ENV 122 /* 'env' */
-#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
-#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
-#define DUK_STRIDX_HEX 123 /* 'hex' */
-#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
-#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
-#define DUK_STRIDX_BASE64 124 /* 'base64' */
-#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
-#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
-#define DUK_STRIDX_JX 125 /* 'jx' */
-#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
-#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
-#define DUK_STRIDX_JC 126 /* 'jc' */
-#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
-#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
-#define DUK_STRIDX_RESUME 127 /* 'resume' */
-#define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
-#define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
-#define DUK_STRIDX_FMT 128 /* 'fmt' */
-#define DUK_HEAP_STRING_FMT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FMT)
-#define DUK_HTHREAD_STRING_FMT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FMT)
-#define DUK_STRIDX_RAW 129 /* 'raw' */
-#define DUK_HEAP_STRING_RAW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RAW)
-#define DUK_HTHREAD_STRING_RAW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RAW)
-#define DUK_STRIDX_LC_TRACE 130 /* 'trace' */
-#define DUK_HEAP_STRING_LC_TRACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_TRACE)
-#define DUK_HTHREAD_STRING_LC_TRACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_TRACE)
-#define DUK_STRIDX_LC_DEBUG 131 /* 'debug' */
-#define DUK_HEAP_STRING_LC_DEBUG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_DEBUG)
-#define DUK_HTHREAD_STRING_LC_DEBUG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_DEBUG)
-#define DUK_STRIDX_LC_INFO 132 /* 'info' */
-#define DUK_HEAP_STRING_LC_INFO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_INFO)
-#define DUK_HTHREAD_STRING_LC_INFO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_INFO)
-#define DUK_STRIDX_LC_WARN 133 /* 'warn' */
-#define DUK_HEAP_STRING_LC_WARN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_WARN)
-#define DUK_HTHREAD_STRING_LC_WARN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_WARN)
-#define DUK_STRIDX_LC_ERROR 134 /* 'error' */
-#define DUK_HEAP_STRING_LC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ERROR)
-#define DUK_HTHREAD_STRING_LC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ERROR)
-#define DUK_STRIDX_LC_FATAL 135 /* 'fatal' */
-#define DUK_HEAP_STRING_LC_FATAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FATAL)
-#define DUK_HTHREAD_STRING_LC_FATAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FATAL)
-#define DUK_STRIDX_LC_N 136 /* 'n' */
-#define DUK_HEAP_STRING_LC_N(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_N)
-#define DUK_HTHREAD_STRING_LC_N(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_N)
-#define DUK_STRIDX_LC_L 137 /* 'l' */
-#define DUK_HEAP_STRING_LC_L(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_L)
-#define DUK_HTHREAD_STRING_LC_L(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_L)
-#define DUK_STRIDX_CLOG 138 /* 'clog' */
-#define DUK_HEAP_STRING_CLOG(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLOG)
-#define DUK_HTHREAD_STRING_CLOG(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLOG)
-#define DUK_STRIDX_TO_LOG_STRING 139 /* 'toLogString' */
-#define DUK_HEAP_STRING_TO_LOG_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOG_STRING)
-#define DUK_HTHREAD_STRING_TO_LOG_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOG_STRING)
-#define DUK_STRIDX_JSON_EXT_UNDEFINED 140 /* '{"_undef":true}' */
-#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
-#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
-#define DUK_STRIDX_JSON_EXT_NAN 141 /* '{"_nan":true}' */
-#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
-#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
-#define DUK_STRIDX_JSON_EXT_POSINF 142 /* '{"_inf":true}' */
-#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
-#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
-#define DUK_STRIDX_JSON_EXT_NEGINF 143 /* '{"_ninf":true}' */
-#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
-#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
-#define DUK_STRIDX_JSON_EXT_FUNCTION1 144 /* '{"_func":true}' */
-#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
-#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
-#define DUK_STRIDX_JSON_EXT_FUNCTION2 145 /* '{_func:true}' */
-#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
-#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
-#define DUK_STRIDX_BREAK 146 /* 'break' */
-#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
-#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
-#define DUK_STRIDX_CASE 147 /* 'case' */
-#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
-#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
-#define DUK_STRIDX_CATCH 148 /* 'catch' */
-#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
-#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
-#define DUK_STRIDX_CONTINUE 149 /* 'continue' */
-#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
-#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
-#define DUK_STRIDX_DEBUGGER 150 /* 'debugger' */
-#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
-#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
-#define DUK_STRIDX_DEFAULT 151 /* 'default' */
-#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
-#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
-#define DUK_STRIDX_DELETE 152 /* 'delete' */
-#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
-#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
-#define DUK_STRIDX_DO 153 /* 'do' */
-#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
-#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
-#define DUK_STRIDX_ELSE 154 /* 'else' */
-#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
-#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
-#define DUK_STRIDX_FINALLY 155 /* 'finally' */
-#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
-#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
-#define DUK_STRIDX_FOR 156 /* 'for' */
-#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
-#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
-#define DUK_STRIDX_LC_FUNCTION 157 /* 'function' */
-#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
-#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
-#define DUK_STRIDX_IF 158 /* 'if' */
-#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
-#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
-#define DUK_STRIDX_IN 159 /* 'in' */
-#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
-#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
-#define DUK_STRIDX_INSTANCEOF 160 /* 'instanceof' */
-#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
-#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
-#define DUK_STRIDX_NEW 161 /* 'new' */
-#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
-#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
-#define DUK_STRIDX_RETURN 162 /* 'return' */
-#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
-#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
-#define DUK_STRIDX_SWITCH 163 /* 'switch' */
-#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
-#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
-#define DUK_STRIDX_THIS 164 /* 'this' */
-#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
-#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
-#define DUK_STRIDX_THROW 165 /* 'throw' */
-#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
-#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
-#define DUK_STRIDX_TRY 166 /* 'try' */
-#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
-#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
-#define DUK_STRIDX_TYPEOF 167 /* 'typeof' */
-#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
-#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
-#define DUK_STRIDX_VAR 168 /* 'var' */
-#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
-#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
-#define DUK_STRIDX_CONST 169 /* 'const' */
-#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
-#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
-#define DUK_STRIDX_VOID 170 /* 'void' */
-#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
-#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
-#define DUK_STRIDX_WHILE 171 /* 'while' */
-#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
-#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
-#define DUK_STRIDX_WITH 172 /* 'with' */
-#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
-#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
-#define DUK_STRIDX_CLASS 173 /* 'class' */
-#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
-#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
-#define DUK_STRIDX_ENUM 174 /* 'enum' */
-#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
-#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
-#define DUK_STRIDX_EXPORT 175 /* 'export' */
-#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
-#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
-#define DUK_STRIDX_EXTENDS 176 /* 'extends' */
-#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
-#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
-#define DUK_STRIDX_IMPORT 177 /* 'import' */
-#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
-#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
-#define DUK_STRIDX_SUPER 178 /* 'super' */
-#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
-#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
-#define DUK_STRIDX_LC_NULL 179 /* 'null' */
-#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
-#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
-#define DUK_STRIDX_TRUE 180 /* 'true' */
-#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
-#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
-#define DUK_STRIDX_FALSE 181 /* 'false' */
-#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
-#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
-#define DUK_STRIDX_IMPLEMENTS 182 /* 'implements' */
-#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
-#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
-#define DUK_STRIDX_INTERFACE 183 /* 'interface' */
-#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
-#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
-#define DUK_STRIDX_LET 184 /* 'let' */
-#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
-#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
-#define DUK_STRIDX_PACKAGE 185 /* 'package' */
-#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
-#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
-#define DUK_STRIDX_PRIVATE 186 /* 'private' */
-#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
-#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
-#define DUK_STRIDX_PROTECTED 187 /* 'protected' */
-#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
-#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
-#define DUK_STRIDX_PUBLIC 188 /* 'public' */
-#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
-#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
-#define DUK_STRIDX_STATIC 189 /* 'static' */
-#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
-#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
-#define DUK_STRIDX_YIELD 190 /* 'yield' */
-#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
-#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
-
-#define DUK_HEAP_NUM_STRINGS 191
-#define DUK_STRIDX_START_RESERVED 146
-#define DUK_STRIDX_START_STRICT_RESERVED 182
-#define DUK_STRIDX_END_RESERVED 191 /* exclusive endpoint */
-
-/* To convert a heap stridx to a token number, subtract
- * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
- */
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[1049];
-#endif /* !DUK_SINGLE_FILE */
-#define DUK_STRDATA_MAX_STRLEN 17
-#define DUK_STRDATA_DATA_LENGTH 1049
-#endif /* DUK_USE_ROM_STRINGS */
-
-#if defined(DUK_USE_ROM_OBJECTS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
-#else
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_require(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
-DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[149];
-#endif /* !DUK_SINGLE_FILE */
-#if defined(DUK_USE_BUILTIN_INITJS)
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_initjs_data[187];
-#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTIN_INITJS_DATA_LENGTH 187
-#endif /* DUK_USE_BUILTIN_INITJS */
-#define DUK_BIDX_GLOBAL 0
-#define DUK_BIDX_GLOBAL_ENV 1
-#define DUK_BIDX_OBJECT_CONSTRUCTOR 2
-#define DUK_BIDX_OBJECT_PROTOTYPE 3
-#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
-#define DUK_BIDX_FUNCTION_PROTOTYPE 5
-#define DUK_BIDX_ARRAY_CONSTRUCTOR 6
-#define DUK_BIDX_ARRAY_PROTOTYPE 7
-#define DUK_BIDX_STRING_CONSTRUCTOR 8
-#define DUK_BIDX_STRING_PROTOTYPE 9
-#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 10
-#define DUK_BIDX_BOOLEAN_PROTOTYPE 11
-#define DUK_BIDX_NUMBER_CONSTRUCTOR 12
-#define DUK_BIDX_NUMBER_PROTOTYPE 13
-#define DUK_BIDX_DATE_CONSTRUCTOR 14
-#define DUK_BIDX_DATE_PROTOTYPE 15
-#define DUK_BIDX_REGEXP_CONSTRUCTOR 16
-#define DUK_BIDX_REGEXP_PROTOTYPE 17
-#define DUK_BIDX_ERROR_CONSTRUCTOR 18
-#define DUK_BIDX_ERROR_PROTOTYPE 19
-#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 20
-#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 21
-#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 22
-#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 23
-#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 24
-#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 25
-#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 26
-#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 27
-#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 28
-#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 29
-#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 30
-#define DUK_BIDX_URI_ERROR_PROTOTYPE 31
-#define DUK_BIDX_MATH 32
-#define DUK_BIDX_JSON 33
-#define DUK_BIDX_TYPE_ERROR_THROWER 34
-#define DUK_BIDX_PROXY_CONSTRUCTOR 35
-#define DUK_BIDX_DUKTAPE 36
-#define DUK_BIDX_THREAD_CONSTRUCTOR 37
-#define DUK_BIDX_THREAD_PROTOTYPE 38
-#define DUK_BIDX_BUFFER_CONSTRUCTOR 39
-#define DUK_BIDX_BUFFER_PROTOTYPE 40
-#define DUK_BIDX_POINTER_CONSTRUCTOR 41
-#define DUK_BIDX_POINTER_PROTOTYPE 42
-#define DUK_BIDX_LOGGER_CONSTRUCTOR 43
-#define DUK_BIDX_LOGGER_PROTOTYPE 44
-#define DUK_BIDX_DOUBLE_ERROR 45
-#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 46
-#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 47
-#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 48
-#define DUK_BIDX_DATAVIEW_PROTOTYPE 49
-#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 50
-#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 51
-#define DUK_BIDX_INT8ARRAY_PROTOTYPE 52
-#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 53
-#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 54
-#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 55
-#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 56
-#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 57
-#define DUK_BIDX_INT16ARRAY_PROTOTYPE 58
-#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 59
-#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 60
-#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 61
-#define DUK_BIDX_INT32ARRAY_PROTOTYPE 62
-#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 63
-#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 64
-#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 65
-#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 66
-#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 67
-#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 68
-#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 69
-#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 70
-#define DUK_NUM_BUILTINS 71
-#define DUK_NUM_BIDX_BUILTINS 71
-#define DUK_NUM_ALL_BUILTINS 71
-#if defined(DUK_USE_DOUBLE_LE)
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
-#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
-#elif defined(DUK_USE_DOUBLE_BE)
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
-#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
-#elif defined(DUK_USE_DOUBLE_ME)
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3833];
-#endif /* !DUK_SINGLE_FILE */
-#define DUK_BUILTINS_DATA_LENGTH 3833
-#else
-#error invalid endianness defines
-#endif
-#endif /* DUK_USE_ROM_OBJECTS */
-#endif /* DUK_BUILTINS_H_INCLUDED */
-#line 52 "duk_internal.h"
-
-#line 1 "duk_util.h"
-/*
- * Utilities
- */
-
-#ifndef DUK_UTIL_H_INCLUDED
-#define DUK_UTIL_H_INCLUDED
-
-#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */
-
-#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f])
-
-/*
- * Endian conversion
- */
-
-#if defined(DUK_USE_INTEGER_LE)
-#define DUK_HTON32(x) DUK_BSWAP32((x))
-#define DUK_NTOH32(x) DUK_BSWAP32((x))
-#define DUK_HTON16(x) DUK_BSWAP16((x))
-#define DUK_NTOH16(x) DUK_BSWAP16((x))
-#elif defined(DUK_USE_INTEGER_BE)
-#define DUK_HTON32(x) (x)
-#define DUK_NTOH32(x) (x)
-#define DUK_HTON16(x) (x)
-#define DUK_NTOH16(x) (x)
-#else
-#error internal error, endianness defines broken
-#endif
-
-/*
- * Bitstream decoder
- */
-
-struct duk_bitdecoder_ctx {
- const duk_uint8_t *data;
- duk_size_t offset;
- duk_size_t length;
- duk_uint32_t currval;
- duk_small_int_t currbits;
-};
-
-/*
- * Bitstream encoder
- */
-
-struct duk_bitencoder_ctx {
- duk_uint8_t *data;
- duk_size_t offset;
- duk_size_t length;
- duk_uint32_t currval;
- duk_small_int_t currbits;
- duk_small_int_t truncated;
-};
-
-/*
- * Raw write/read macros for big endian, unaligned basic values.
- * Caller ensures there's enough space. The macros update the pointer
- * argument automatically on resizes. The idiom seems a bit odd, but
- * leads to compact code.
- */
-
-#define DUK_RAW_WRITE_U8(ptr,val) do { \
- *(ptr)++ = (duk_uint8_t) (val); \
- } while (0)
-#define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val))
-#define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val))
-#define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val))
-#define DUK_RAW_WRITE_XUTF8(ptr,val) do { \
- /* 'ptr' is evaluated both as LHS and RHS. */ \
- duk_uint8_t *duk__ptr; \
- duk_small_int_t duk__len; \
- duk__ptr = (duk_uint8_t *) (ptr); \
- duk__len = duk_unicode_encode_xutf8((duk_ucodepoint_t) (val), duk__ptr); \
- duk__ptr += duk__len; \
- (ptr) = duk__ptr; \
- } while (0)
-#define DUK_RAW_WRITE_CESU8(ptr,val) do { \
- /* 'ptr' is evaluated both as LHS and RHS. */ \
- duk_uint8_t *duk__ptr; \
- duk_small_int_t duk__len; \
- duk__ptr = (duk_uint8_t *) (ptr); \
- duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \
- duk__ptr += duk__len; \
- (ptr) = duk__ptr; \
- } while (0)
-
-#define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++))
-#define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr));
-#define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr));
-#define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr));
-
-/*
- * Buffer writer (dynamic buffer only)
- *
- * Helper for writing to a dynamic buffer with a concept of a "spare" area
- * to reduce resizes. You can ensure there is enough space beforehand and
- * then write for a while without further checks, relying on a stable data
- * pointer. Spare handling is automatic so call sites only indicate how
- * much data they need right now.
- *
- * There are several ways to write using bufwriter. The best approach
- * depends mainly on how much performance matters over code footprint.
- * The key issues are (1) ensuring there is space and (2) keeping the
- * pointers consistent. Fast code should ensure space for multiple writes
- * with one ensure call. Fastest inner loop code can temporarily borrow
- * the 'p' pointer but must write it back eventually.
- *
- * Be careful to ensure all macro arguments (other than static pointers like
- * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if
- * necessary (if that's not possible, there should be a note near the macro).
- * Buffer write arguments often contain arithmetic etc so this is
- * particularly important here.
- */
-
-/* XXX: Migrate bufwriter and other read/write helpers to its own header? */
-
-struct duk_bufwriter_ctx {
- duk_uint8_t *p;
- duk_uint8_t *p_base;
- duk_uint8_t *p_limit;
- duk_hbuffer_dynamic *buf;
-};
-
-#define DUK_BW_SPARE_ADD 64
-#define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */
-
-/* Initialization and finalization (compaction), converting to other types. */
-
-#define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \
- duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \
- } while (0)
-#define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \
- duk_bw_init((thr), (bw_ctx), (buf)); \
- } while (0)
-#define DUK_BW_COMPACT(thr,bw_ctx) do { \
- /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \
- duk_bw_compact((thr), (bw_ctx)); \
- } while (0)
-#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
- duk_push_lstring((duk_context *) (thr), \
- (const char *) (bw_ctx)->p_base, \
- (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
- } while (0)
-/* Pointers may be NULL for a while when 'buf' size is zero and before any
- * ENSURE calls have been made. Once an ENSURE has been made, the pointers
- * are required to be non-NULL so that it's always valid to use memcpy() and
- * memmove(), even for zero size.
- */
-#define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \
- DUK_ASSERT_EXPR((bw_ctx) != NULL && \
- (bw_ctx)->buf != NULL && \
- ((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \
- ((bw_ctx)->p != NULL && \
- (bw_ctx)->p_base != NULL && \
- (bw_ctx)->p_limit != NULL && \
- (bw_ctx)->p_limit >= (bw_ctx)->p_base && \
- (bw_ctx)->p >= (bw_ctx)->p_base && \
- (bw_ctx)->p <= (bw_ctx)->p_limit)))
-#define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \
- DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \
- } while (0)
-
-/* Working with the pointer and current size. */
-
-#define DUK_BW_GET_PTR(thr,bw_ctx) \
- ((bw_ctx)->p)
-#define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \
- (bw_ctx)->p = (ptr); \
- } while (0)
-#define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \
- (bw_ctx)->p += (delta); \
- } while (0)
-#define DUK_BW_GET_BASEPTR(thr,bw_ctx) \
- ((bw_ctx)->p_base)
-#define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \
- ((bw_ctx)->p_limit)
-#define DUK_BW_GET_SIZE(thr,bw_ctx) \
- ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base))
-#define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \
- DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
- (bw_ctx)->p = (bw_ctx)->p_base + (sz); \
- } while (0)
-#define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \
- /* Reset to zero size, keep current limit. */ \
- (bw_ctx)->p = (bw_ctx)->p_base; \
- } while (0)
-#define DUK_BW_GET_BUFFER(thr,bw_ctx) \
- ((bw_ctx)->buf)
-
-/* Ensuring (reserving) space. */
-
-#define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \
- duk_size_t duk__sz, duk__space; \
- DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \
- duk__sz = (sz); \
- duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \
- if (duk__space < duk__sz) { \
- (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \
- } \
- } while (0)
-/* NOTE: Multiple evaluation of 'ptr' in this macro. */
-/* XXX: Rework to use an always-inline function? */
-#define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \
- (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \
- (ptr) : \
- ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz))))
-#define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \
- DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p)
-#define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \
- (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \
- DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz)))
-#define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \
- DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \
- } while (0)
-
-/* Miscellaneous. */
-
-#define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \
- (bw_ctx)->p = (ptr); \
- duk_bw_compact((thr), (bw_ctx)); \
- } while (0)
-
-/* Fast write calls which assume you control the spare beforehand.
- * Multibyte write variants exist and use a temporary write pointer
- * because byte writes alias with anything: with a stored pointer
- * explicit pointer load/stores get generated (e.g. gcc -Os).
- */
-
-#define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \
- DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \
- *(bw_ctx)->p++ = (duk_uint8_t) (val); \
- } while (0)
-#define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \
- duk_uint8_t *duk__p; \
- DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \
- duk__p = (bw_ctx)->p; \
- *duk__p++ = (duk_uint8_t) (val1); \
- *duk__p++ = (duk_uint8_t) (val2); \
- (bw_ctx)->p = duk__p; \
- } while (0)
-#define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \
- duk_uint8_t *duk__p; \
- DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \
- duk__p = (bw_ctx)->p; \
- *duk__p++ = (duk_uint8_t) (val1); \
- *duk__p++ = (duk_uint8_t) (val2); \
- *duk__p++ = (duk_uint8_t) (val3); \
- (bw_ctx)->p = duk__p; \
- } while (0)
-#define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
- duk_uint8_t *duk__p; \
- DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \
- duk__p = (bw_ctx)->p; \
- *duk__p++ = (duk_uint8_t) (val1); \
- *duk__p++ = (duk_uint8_t) (val2); \
- *duk__p++ = (duk_uint8_t) (val3); \
- *duk__p++ = (duk_uint8_t) (val4); \
- (bw_ctx)->p = duk__p; \
- } while (0)
-#define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
- duk_uint8_t *duk__p; \
- DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \
- duk__p = (bw_ctx)->p; \
- *duk__p++ = (duk_uint8_t) (val1); \
- *duk__p++ = (duk_uint8_t) (val2); \
- *duk__p++ = (duk_uint8_t) (val3); \
- *duk__p++ = (duk_uint8_t) (val4); \
- *duk__p++ = (duk_uint8_t) (val5); \
- (bw_ctx)->p = duk__p; \
- } while (0)
-#define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
- duk_uint8_t *duk__p; \
- DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \
- duk__p = (bw_ctx)->p; \
- *duk__p++ = (duk_uint8_t) (val1); \
- *duk__p++ = (duk_uint8_t) (val2); \
- *duk__p++ = (duk_uint8_t) (val3); \
- *duk__p++ = (duk_uint8_t) (val4); \
- *duk__p++ = (duk_uint8_t) (val5); \
- *duk__p++ = (duk_uint8_t) (val6); \
- (bw_ctx)->p = duk__p; \
- } while (0)
-#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
- duk_ucodepoint_t duk__cp; \
- duk_small_int_t duk__enc_len; \
- duk__cp = (cp); \
- DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
- duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
- (bw_ctx)->p += duk__enc_len; \
- } while (0)
-#define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \
- duk_ucodepoint_t duk__cp; \
- duk_small_int_t duk__enc_len; \
- duk__cp = (duk_ucodepoint_t) (cp); \
- DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \
- duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \
- (bw_ctx)->p += duk__enc_len; \
- } while (0)
-/* XXX: add temporary duk__p pointer here too; sharing */
-#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
- const void *duk__valptr; \
- duk_size_t duk__valsz; \
- duk__valptr = (const void *) (valptr); \
- duk__valsz = (duk_size_t) (valsz); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
- (bw_ctx)->p += duk__valsz; \
- } while (0)
-#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
- const duk_uint8_t *duk__val; \
- duk_size_t duk__val_len; \
- duk__val = (const duk_uint8_t *) (val); \
- duk__val_len = DUK_STRLEN((const char *) duk__val); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
- duk_size_t duk__val_len; \
- duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
- duk_size_t duk__val_len; \
- duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
- duk_size_t duk__val_len; \
- duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
- duk_size_t duk__val_len; \
- duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-
-/* Append bytes from a slice already in the buffer. */
-#define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \
- duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len))
-
-/* Insert bytes in the middle of the buffer from an external buffer. */
-#define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \
- duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len))
-
-/* Insert bytes in the middle of the buffer from a slice already
- * in the buffer. Source offset is interpreted "before" the operation.
- */
-#define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \
- duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len))
-
-/* Insert a reserved area somewhere in the buffer; caller fills it.
- * Evaluates to a (duk_uint_t *) pointing to the start of the reserved
- * area for convenience.
- */
-#define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \
- duk_bw_insert_raw_area((thr), (bw), (off), (len))
-
-/* Remove a slice from inside buffer. */
-#define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \
- duk_bw_remove_raw_slice((thr), (bw), (off), (len))
-
-/* Safe write calls which will ensure space first. */
-
-#define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \
- DUK_BW_ENSURE((thr), (bw_ctx), 1); \
- DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \
- DUK_BW_ENSURE((thr), (bw_ctx), 2); \
- DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \
- DUK_BW_ENSURE((thr), (bw_ctx), 3); \
- DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
- DUK_BW_ENSURE((thr), (bw_ctx), 4); \
- DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
- DUK_BW_ENSURE((thr), (bw_ctx), 5); \
- DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
- DUK_BW_ENSURE((thr), (bw_ctx), 6); \
- DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \
- DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \
- DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \
- DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \
- DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
- } while (0)
-/* XXX: add temporary duk__p pointer here too; sharing */
-#define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \
- const void *duk__valptr; \
- duk_size_t duk__valsz; \
- duk__valptr = (const void *) (valptr); \
- duk__valsz = (duk_size_t) (valsz); \
- DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
- (bw_ctx)->p += duk__valsz; \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
- const duk_uint8_t *duk__val; \
- duk_size_t duk__val_len; \
- duk__val = (const duk_uint8_t *) (val); \
- duk__val_len = DUK_STRLEN((const char *) duk__val); \
- DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
- duk_size_t duk__val_len; \
- duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
- DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
- duk_size_t duk__val_len; \
- duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
- DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
- duk_size_t duk__val_len; \
- duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
- DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
- duk_size_t duk__val_len; \
- duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
- DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
- DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
- (bw_ctx)->p += duk__val_len; \
- } while (0)
-
-#define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \
- duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len))
-#define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \
- duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len))
-#define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \
- duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len))
-#define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \
- /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \
- duk_bw_insert_ensure_area((thr), (bw), (off), (len))
-#define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \
- /* No difference between raw/ensure because the buffer shrinks. */ \
- DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len))
-
-/*
- * Externs and prototypes
- */
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36];
-DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16];
-DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
-#if defined(DUK_USE_HEX_FASTPATH)
-DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
-DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
-#endif
-#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64];
-DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
-#endif
-#endif /* !DUK_SINGLE_FILE */
-
-/* Note: assumes that duk_util_probe_steps size is 32 */
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
-#endif /* !DUK_SINGLE_FILE */
-#endif
-
-#if defined(DUK_USE_STRHASH_DENSE)
-DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
-#endif
-
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
-DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
-#endif
-
-DUK_INTERNAL_DECL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
-DUK_INTERNAL_DECL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
-DUK_INTERNAL_DECL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value);
-
-DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
-DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
-
-DUK_INTERNAL_DECL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n);
-DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
-
-DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
-DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
-DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz);
-DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx);
-DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
-DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
-DUK_INTERNAL_DECL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len);
-DUK_INTERNAL_DECL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len);
-DUK_INTERNAL_DECL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len);
-DUK_INTERNAL_DECL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len);
-DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
-DUK_INTERNAL_DECL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
-DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
-/* No duk_bw_remove_ensure_slice(), functionality would be identical. */
-
-DUK_INTERNAL_DECL DUK_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL DUK_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL DUK_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
-DUK_INTERNAL_DECL DUK_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
-DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
-#endif
-
-#endif /* DUK_UTIL_H_INCLUDED */
-#line 1 "duk_strings.h"
-/*
- * Shared error messages: declarations and macros
- *
- * Error messages are accessed through macros with fine-grained, explicit
- * error message distinctions. Concrete error messages are selected by the
- * macros and multiple macros can map to the same concrete string to save
- * on code footprint. This allows flexible footprint/verbosity tuning with
- * minimal code impact. There are a few limitations to this approach:
- * (1) switching between plain messages and format strings doesn't work
- * conveniently, and (2) conditional strings are a bit awkward to handle.
- *
- * Because format strings behave differently in the call site (they need to
- * be followed by format arguments), they have a special prefix (DUK_STR_FMT_
- * and duk_str_fmt_).
- *
- * On some compilers using explicit shared strings is preferable; on others
- * it may be better to use straight literals because the compiler will combine
- * them anyway, and such strings won't end up unnecessarily in a symbol table.
- */
-
-#ifndef DUK_ERRMSG_H_INCLUDED
-#define DUK_ERRMSG_H_INCLUDED
-
-#define DUK_STR_INTERNAL_ERROR duk_str_internal_error
-#define DUK_STR_INVALID_COUNT duk_str_invalid_count
-#define DUK_STR_INVALID_CALL_ARGS duk_str_invalid_call_args
-#define DUK_STR_NOT_CONSTRUCTABLE duk_str_not_constructable
-#define DUK_STR_NOT_CALLABLE duk_str_not_callable
-#define DUK_STR_NOT_EXTENSIBLE duk_str_not_extensible
-#define DUK_STR_NOT_WRITABLE duk_str_not_writable
-#define DUK_STR_NOT_CONFIGURABLE duk_str_not_configurable
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_internal_error;
-DUK_INTERNAL_DECL const char *duk_str_invalid_count;
-DUK_INTERNAL_DECL const char *duk_str_invalid_call_args;
-DUK_INTERNAL_DECL const char *duk_str_not_constructable;
-DUK_INTERNAL_DECL const char *duk_str_not_callable;
-DUK_INTERNAL_DECL const char *duk_str_not_extensible;
-DUK_INTERNAL_DECL const char *duk_str_not_writable;
-DUK_INTERNAL_DECL const char *duk_str_not_configurable;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_INVALID_CONTEXT duk_str_invalid_context
-#define DUK_STR_INVALID_INDEX duk_str_invalid_call_args
-#define DUK_STR_PUSH_BEYOND_ALLOC_STACK duk_str_push_beyond_alloc_stack
-#define DUK_STR_NOT_UNDEFINED duk_str_unexpected_type
-#define DUK_STR_NOT_NULL duk_str_unexpected_type
-#define DUK_STR_NOT_BOOLEAN duk_str_unexpected_type
-#define DUK_STR_NOT_NUMBER duk_str_unexpected_type
-#define DUK_STR_NOT_STRING duk_str_unexpected_type
-#define DUK_STR_NOT_OBJECT duk_str_unexpected_type
-#define DUK_STR_NOT_POINTER duk_str_unexpected_type
-#define DUK_STR_NOT_BUFFER duk_str_not_buffer /* still in use with verbose messages */
-#define DUK_STR_UNEXPECTED_TYPE duk_str_unexpected_type
-#define DUK_STR_NOT_THREAD duk_str_unexpected_type
-#define DUK_STR_NOT_COMPILEDFUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_NATIVEFUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_C_FUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_FUNCTION duk_str_unexpected_type
-#define DUK_STR_NOT_REGEXP duk_str_unexpected_type
-#define DUK_STR_DEFAULTVALUE_COERCE_FAILED duk_str_defaultvalue_coerce_failed
-#define DUK_STR_NUMBER_OUTSIDE_RANGE duk_str_number_outside_range
-#define DUK_STR_NOT_OBJECT_COERCIBLE duk_str_not_object_coercible
-#define DUK_STR_STRING_TOO_LONG duk_str_string_too_long
-#define DUK_STR_BUFFER_TOO_LONG duk_str_buffer_too_long
-#define DUK_STR_SPRINTF_TOO_LONG duk_str_sprintf_too_long
-#define DUK_STR_ALLOC_FAILED duk_str_alloc_failed
-#define DUK_STR_POP_TOO_MANY duk_str_pop_too_many
-#define DUK_STR_WRONG_BUFFER_TYPE duk_str_wrong_buffer_type
-#define DUK_STR_ENCODE_FAILED duk_str_encode_failed
-#define DUK_STR_DECODE_FAILED duk_str_decode_failed
-#define DUK_STR_NO_SOURCECODE duk_str_no_sourcecode
-#define DUK_STR_CONCAT_RESULT_TOO_LONG duk_str_concat_result_too_long
-#define DUK_STR_UNIMPLEMENTED duk_str_unimplemented
-#define DUK_STR_UNSUPPORTED duk_str_unsupported
-#define DUK_STR_ARRAY_LENGTH_OVER_2G duk_str_array_length_over_2g
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_invalid_context;
-DUK_INTERNAL_DECL const char *duk_str_push_beyond_alloc_stack;
-DUK_INTERNAL_DECL const char *duk_str_not_buffer;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_type;
-DUK_INTERNAL_DECL const char *duk_str_defaultvalue_coerce_failed;
-DUK_INTERNAL_DECL const char *duk_str_number_outside_range;
-DUK_INTERNAL_DECL const char *duk_str_not_object_coercible;
-DUK_INTERNAL_DECL const char *duk_str_string_too_long;
-DUK_INTERNAL_DECL const char *duk_str_buffer_too_long;
-DUK_INTERNAL_DECL const char *duk_str_sprintf_too_long;
-DUK_INTERNAL_DECL const char *duk_str_alloc_failed;
-DUK_INTERNAL_DECL const char *duk_str_pop_too_many;
-DUK_INTERNAL_DECL const char *duk_str_wrong_buffer_type;
-DUK_INTERNAL_DECL const char *duk_str_encode_failed;
-DUK_INTERNAL_DECL const char *duk_str_decode_failed;
-DUK_INTERNAL_DECL const char *duk_str_no_sourcecode;
-DUK_INTERNAL_DECL const char *duk_str_concat_result_too_long;
-DUK_INTERNAL_DECL const char *duk_str_unimplemented;
-DUK_INTERNAL_DECL const char *duk_str_unsupported;
-DUK_INTERNAL_DECL const char *duk_str_array_length_over_2g;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_FMT_PTR duk_str_fmt_ptr
-#define DUK_STR_FMT_INVALID_JSON duk_str_fmt_invalid_json
-#define DUK_STR_JSONDEC_RECLIMIT duk_str_jsondec_reclimit
-#define DUK_STR_JSONENC_RECLIMIT duk_str_jsonenc_reclimit
-#define DUK_STR_CYCLIC_INPUT duk_str_cyclic_input
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_fmt_ptr;
-DUK_INTERNAL_DECL const char *duk_str_fmt_invalid_json;
-DUK_INTERNAL_DECL const char *duk_str_jsondec_reclimit;
-DUK_INTERNAL_DECL const char *duk_str_jsonenc_reclimit;
-DUK_INTERNAL_DECL const char *duk_str_cyclic_input;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_PROXY_REVOKED duk_str_proxy_revoked
-#define DUK_STR_INVALID_BASE duk_str_invalid_base
-#define DUK_STR_STRICT_CALLER_READ duk_str_strict_caller_read
-#define DUK_STR_PROXY_REJECTED duk_str_proxy_rejected
-#define DUK_STR_INVALID_ARRAY_LENGTH duk_str_invalid_array_length
-#define DUK_STR_ARRAY_LENGTH_WRITE_FAILED duk_str_array_length_write_failed
-#define DUK_STR_ARRAY_LENGTH_NOT_WRITABLE duk_str_array_length_not_writable
-#define DUK_STR_SETTER_UNDEFINED duk_str_setter_undefined
-#define DUK_STR_REDEFINE_VIRT_PROP duk_str_redefine_virt_prop
-#define DUK_STR_INVALID_DESCRIPTOR duk_str_invalid_descriptor
-#define DUK_STR_PROPERTY_IS_VIRTUAL duk_str_property_is_virtual
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_proxy_revoked;
-DUK_INTERNAL_DECL const char *duk_str_invalid_base;
-DUK_INTERNAL_DECL const char *duk_str_strict_caller_read;
-DUK_INTERNAL_DECL const char *duk_str_proxy_rejected;
-DUK_INTERNAL_DECL const char *duk_str_invalid_array_length;
-DUK_INTERNAL_DECL const char *duk_str_array_length_write_failed;
-DUK_INTERNAL_DECL const char *duk_str_array_length_not_writable;
-DUK_INTERNAL_DECL const char *duk_str_setter_undefined;
-DUK_INTERNAL_DECL const char *duk_str_redefine_virt_prop;
-DUK_INTERNAL_DECL const char *duk_str_invalid_descriptor;
-DUK_INTERNAL_DECL const char *duk_str_property_is_virtual;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_PARSE_ERROR duk_str_parse_error
-#define DUK_STR_DUPLICATE_LABEL duk_str_duplicate_label
-#define DUK_STR_INVALID_LABEL duk_str_invalid_label
-#define DUK_STR_INVALID_ARRAY_LITERAL duk_str_invalid_array_literal
-#define DUK_STR_INVALID_OBJECT_LITERAL duk_str_invalid_object_literal
-#define DUK_STR_INVALID_VAR_DECLARATION duk_str_invalid_var_declaration
-#define DUK_STR_CANNOT_DELETE_IDENTIFIER duk_str_cannot_delete_identifier
-#define DUK_STR_INVALID_EXPRESSION duk_str_invalid_expression
-#define DUK_STR_INVALID_LVALUE duk_str_invalid_lvalue
-#define DUK_STR_EXPECTED_IDENTIFIER duk_str_expected_identifier
-#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED duk_str_empty_expr_not_allowed
-#define DUK_STR_INVALID_FOR duk_str_invalid_for
-#define DUK_STR_INVALID_SWITCH duk_str_invalid_switch
-#define DUK_STR_INVALID_BREAK_CONT_LABEL duk_str_invalid_break_cont_label
-#define DUK_STR_INVALID_RETURN duk_str_invalid_return
-#define DUK_STR_INVALID_TRY duk_str_invalid_try
-#define DUK_STR_INVALID_THROW duk_str_invalid_throw
-#define DUK_STR_WITH_IN_STRICT_MODE duk_str_with_in_strict_mode
-#define DUK_STR_FUNC_STMT_NOT_ALLOWED duk_str_func_stmt_not_allowed
-#define DUK_STR_UNTERMINATED_STMT duk_str_unterminated_stmt
-#define DUK_STR_INVALID_ARG_NAME duk_str_invalid_arg_name
-#define DUK_STR_INVALID_FUNC_NAME duk_str_invalid_func_name
-#define DUK_STR_INVALID_GETSET_NAME duk_str_invalid_getset_name
-#define DUK_STR_FUNC_NAME_REQUIRED duk_str_func_name_required
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_parse_error;
-DUK_INTERNAL_DECL const char *duk_str_duplicate_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_array_literal;
-DUK_INTERNAL_DECL const char *duk_str_invalid_object_literal;
-DUK_INTERNAL_DECL const char *duk_str_invalid_var_declaration;
-DUK_INTERNAL_DECL const char *duk_str_cannot_delete_identifier;
-DUK_INTERNAL_DECL const char *duk_str_invalid_expression;
-DUK_INTERNAL_DECL const char *duk_str_invalid_lvalue;
-DUK_INTERNAL_DECL const char *duk_str_expected_identifier;
-DUK_INTERNAL_DECL const char *duk_str_empty_expr_not_allowed;
-DUK_INTERNAL_DECL const char *duk_str_invalid_for;
-DUK_INTERNAL_DECL const char *duk_str_invalid_switch;
-DUK_INTERNAL_DECL const char *duk_str_invalid_break_cont_label;
-DUK_INTERNAL_DECL const char *duk_str_invalid_return;
-DUK_INTERNAL_DECL const char *duk_str_invalid_try;
-DUK_INTERNAL_DECL const char *duk_str_invalid_throw;
-DUK_INTERNAL_DECL const char *duk_str_with_in_strict_mode;
-DUK_INTERNAL_DECL const char *duk_str_func_stmt_not_allowed;
-DUK_INTERNAL_DECL const char *duk_str_unterminated_stmt;
-DUK_INTERNAL_DECL const char *duk_str_invalid_arg_name;
-DUK_INTERNAL_DECL const char *duk_str_invalid_func_name;
-DUK_INTERNAL_DECL const char *duk_str_invalid_getset_name;
-DUK_INTERNAL_DECL const char *duk_str_func_name_required;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM duk_str_invalid_quantifier_no_atom
-#define DUK_STR_INVALID_QUANTIFIER_VALUES duk_str_invalid_quantifier_values
-#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES duk_str_quantifier_too_many_copies
-#define DUK_STR_UNEXPECTED_CLOSING_PAREN duk_str_unexpected_closing_paren
-#define DUK_STR_UNEXPECTED_END_OF_PATTERN duk_str_unexpected_end_of_pattern
-#define DUK_STR_UNEXPECTED_REGEXP_TOKEN duk_str_unexpected_regexp_token
-#define DUK_STR_INVALID_REGEXP_FLAGS duk_str_invalid_regexp_flags
-#define DUK_STR_INVALID_BACKREFS duk_str_invalid_backrefs
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_no_atom;
-DUK_INTERNAL_DECL const char *duk_str_invalid_quantifier_values;
-DUK_INTERNAL_DECL const char *duk_str_quantifier_too_many_copies;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_closing_paren;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_end_of_pattern;
-DUK_INTERNAL_DECL const char *duk_str_unexpected_regexp_token;
-DUK_INTERNAL_DECL const char *duk_str_invalid_regexp_flags;
-DUK_INTERNAL_DECL const char *duk_str_invalid_backrefs;
-#endif /* !DUK_SINGLE_FILE */
-
-#define DUK_STR_VALSTACK_LIMIT duk_str_valstack_limit
-#define DUK_STR_CALLSTACK_LIMIT duk_str_callstack_limit
-#define DUK_STR_CATCHSTACK_LIMIT duk_str_catchstack_limit
-#define DUK_STR_PROTOTYPE_CHAIN_LIMIT duk_str_prototype_chain_limit
-#define DUK_STR_BOUND_CHAIN_LIMIT duk_str_bound_chain_limit
-#define DUK_STR_C_CALLSTACK_LIMIT duk_str_c_callstack_limit
-#define DUK_STR_COMPILER_RECURSION_LIMIT duk_str_compiler_recursion_limit
-#define DUK_STR_BYTECODE_LIMIT duk_str_bytecode_limit
-#define DUK_STR_REG_LIMIT duk_str_reg_limit
-#define DUK_STR_TEMP_LIMIT duk_str_temp_limit
-#define DUK_STR_CONST_LIMIT duk_str_const_limit
-#define DUK_STR_FUNC_LIMIT duk_str_func_limit
-#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT duk_str_regexp_compiler_recursion_limit
-#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT duk_str_regexp_executor_recursion_limit
-#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT duk_str_regexp_executor_step_limit
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_valstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_callstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_catchstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_prototype_chain_limit;
-DUK_INTERNAL_DECL const char *duk_str_bound_chain_limit;
-DUK_INTERNAL_DECL const char *duk_str_c_callstack_limit;
-DUK_INTERNAL_DECL const char *duk_str_compiler_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_bytecode_limit;
-DUK_INTERNAL_DECL const char *duk_str_reg_limit;
-DUK_INTERNAL_DECL const char *duk_str_temp_limit;
-DUK_INTERNAL_DECL const char *duk_str_const_limit;
-DUK_INTERNAL_DECL const char *duk_str_func_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_compiler_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_executor_recursion_limit;
-DUK_INTERNAL_DECL const char *duk_str_regexp_executor_step_limit;
-#endif /* !DUK_SINGLE_FILE */
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const char *duk_str_anon;
-#endif /* !DUK_SINGLE_FILE */
-
-#endif /* DUK_ERRMSG_H_INCLUDED */
-#line 1 "duk_js_bytecode.h"
-/*
- * Ecmascript bytecode
- */
-
-#ifndef DUK_JS_BYTECODE_H_INCLUDED
-#define DUK_JS_BYTECODE_H_INCLUDED
-
-/*
- * Logical instruction layout
- * ==========================
- *
- * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
- * !1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!9!8!7!6!5!4!3!2!1!0!
- * +---------------------------------------------------+-----------+
- * ! C ! B ! A ! OP !
- * +---------------------------------------------------+-----------+
- *
- * OP (6 bits): opcode (DUK_OP_*), access should be fastest
- * A (8 bits): typically a target register number
- * B (9 bits): typically first source register/constant number
- * C (9 bits): typically second source register/constant number
- *
- * Some instructions combine BC or ABC together for larger parameter values.
- * Signed integers (e.g. jump offsets) are encoded as unsigned, with an opcode
- * specific bias. B and C may denote a register or a constant, see
- * DUK_BC_ISREG() and DUK_BC_ISCONST().
- *
- * Note: macro naming is a bit misleading, e.g. "ABC" in macro name but
- * the field layout is logically "CBA".
- */
-
-typedef duk_uint32_t duk_instr_t;
-
-#define DUK_DEC_OP(x) ((x) & 0x3fUL)
-#define DUK_DEC_A(x) (((x) >> 6) & 0xffUL)
-#define DUK_DEC_B(x) (((x) >> 14) & 0x1ffUL)
-#define DUK_DEC_C(x) (((x) >> 23) & 0x1ffUL)
-#define DUK_DEC_BC(x) (((x) >> 14) & 0x3ffffUL)
-#define DUK_DEC_ABC(x) (((x) >> 6) & 0x3ffffffUL)
-
-#define DUK_ENC_OP(op) ((duk_instr_t) (op))
-#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \
- (((duk_instr_t) (abc)) << 6) | \
- ((duk_instr_t) (op)) \
- ))
-#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \
- (((duk_instr_t) (bc)) << 14) | \
- (((duk_instr_t) (a)) << 6) | \
- ((duk_instr_t) (op)) \
- ))
-#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \
- (((duk_instr_t) (c)) << 23) | \
- (((duk_instr_t) (b)) << 14) | \
- (((duk_instr_t) (a)) << 6) | \
- ((duk_instr_t) (op)) \
- ))
-#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C(op,a,b,0)
-#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C(op,a,0,0)
-
-/* Constants should be signed so that signed arithmetic involving them
- * won't cause values to be coerced accidentally to unsigned.
- */
-#define DUK_BC_OP_MIN 0
-#define DUK_BC_OP_MAX 0x3fL
-#define DUK_BC_A_MIN 0
-#define DUK_BC_A_MAX 0xffL
-#define DUK_BC_B_MIN 0
-#define DUK_BC_B_MAX 0x1ffL
-#define DUK_BC_C_MIN 0
-#define DUK_BC_C_MAX 0x1ffL
-#define DUK_BC_BC_MIN 0
-#define DUK_BC_BC_MAX 0x3ffffL
-#define DUK_BC_ABC_MIN 0
-#define DUK_BC_ABC_MAX 0x3ffffffL
-#define DUK_BC_EXTRAOP_MIN DUK_BC_A_MIN
-#define DUK_BC_EXTRAOP_MAX DUK_BC_A_MAX
-
-#define DUK_OP_LDREG 0
-#define DUK_OP_STREG 1
-#define DUK_OP_LDCONST 2
-#define DUK_OP_LDINT 3
-#define DUK_OP_LDINTX 4
-#define DUK_OP_MPUTOBJ 5
-#define DUK_OP_MPUTOBJI 6
-#define DUK_OP_MPUTARR 7
-#define DUK_OP_MPUTARRI 8
-#define DUK_OP_NEW 9
-#define DUK_OP_NEWI 10
-#define DUK_OP_REGEXP 11
-#define DUK_OP_CSREG 12
-#define DUK_OP_CSREGI 13
-#define DUK_OP_GETVAR 14
-#define DUK_OP_PUTVAR 15
-#define DUK_OP_DECLVAR 16
-#define DUK_OP_DELVAR 17
-#define DUK_OP_CSVAR 18
-#define DUK_OP_CSVARI 19
-#define DUK_OP_CLOSURE 20
-#define DUK_OP_GETPROP 21
-#define DUK_OP_PUTPROP 22
-#define DUK_OP_DELPROP 23
-#define DUK_OP_CSPROP 24
-#define DUK_OP_CSPROPI 25
-#define DUK_OP_ADD 26
-#define DUK_OP_SUB 27
-#define DUK_OP_MUL 28
-#define DUK_OP_DIV 29
-#define DUK_OP_MOD 30
-#define DUK_OP_BAND 31
-#define DUK_OP_BOR 32
-#define DUK_OP_BXOR 33
-#define DUK_OP_BASL 34
-#define DUK_OP_BLSR 35
-#define DUK_OP_BASR 36
-#define DUK_OP_EQ 37
-#define DUK_OP_NEQ 38
-#define DUK_OP_SEQ 39
-#define DUK_OP_SNEQ 40
-#define DUK_OP_GT 41
-#define DUK_OP_GE 42
-#define DUK_OP_LT 43
-#define DUK_OP_LE 44
-#define DUK_OP_IF 45
-#define DUK_OP_JUMP 46
-#define DUK_OP_RETURN 47
-#define DUK_OP_CALL 48
-#define DUK_OP_CALLI 49
-#define DUK_OP_TRYCATCH 50
-#define DUK_OP_EXTRA 51
-#define DUK_OP_PREINCR 52 /* pre/post opcode values have constraints, */
-#define DUK_OP_PREDECR 53 /* see duk_js_executor.c */
-#define DUK_OP_POSTINCR 54
-#define DUK_OP_POSTDECR 55
-#define DUK_OP_PREINCV 56
-#define DUK_OP_PREDECV 57
-#define DUK_OP_POSTINCV 58
-#define DUK_OP_POSTDECV 59
-#define DUK_OP_PREINCP 60
-#define DUK_OP_PREDECP 61
-#define DUK_OP_POSTINCP 62
-#define DUK_OP_POSTDECP 63
-#define DUK_OP_NONE 64 /* dummy value used as marker */
-
-/* DUK_OP_EXTRA, sub-operation in A */
-#define DUK_EXTRAOP_NOP 0
-#define DUK_EXTRAOP_INVALID 1
-#define DUK_EXTRAOP_LDTHIS 2
-#define DUK_EXTRAOP_LDUNDEF 3
-#define DUK_EXTRAOP_LDNULL 4
-#define DUK_EXTRAOP_LDTRUE 5
-#define DUK_EXTRAOP_LDFALSE 6
-#define DUK_EXTRAOP_NEWOBJ 7
-#define DUK_EXTRAOP_NEWARR 8
-#define DUK_EXTRAOP_SETALEN 9
-#define DUK_EXTRAOP_TYPEOF 10
-#define DUK_EXTRAOP_TYPEOFID 11
-#define DUK_EXTRAOP_INITENUM 12
-#define DUK_EXTRAOP_NEXTENUM 13
-#define DUK_EXTRAOP_INITSET 14
-#define DUK_EXTRAOP_INITSETI 15
-#define DUK_EXTRAOP_INITGET 16
-#define DUK_EXTRAOP_INITGETI 17
-#define DUK_EXTRAOP_ENDTRY 18
-#define DUK_EXTRAOP_ENDCATCH 19
-#define DUK_EXTRAOP_ENDFIN 20
-#define DUK_EXTRAOP_THROW 21
-#define DUK_EXTRAOP_INVLHS 22
-#define DUK_EXTRAOP_UNM 23
-#define DUK_EXTRAOP_UNP 24
-#define DUK_EXTRAOP_DEBUGGER 25
-#define DUK_EXTRAOP_BREAK 26
-#define DUK_EXTRAOP_CONTINUE 27
-#define DUK_EXTRAOP_BNOT 28
-#define DUK_EXTRAOP_LNOT 29
-#define DUK_EXTRAOP_INSTOF 30
-#define DUK_EXTRAOP_IN 31
-#define DUK_EXTRAOP_LABEL 32
-#define DUK_EXTRAOP_ENDLABEL 33
-
-/* DUK_OP_CALL flags in A */
-#define DUK_BC_CALL_FLAG_TAILCALL (1 << 0)
-#define DUK_BC_CALL_FLAG_EVALCALL (1 << 1)
-
-/* DUK_OP_TRYCATCH flags in A */
-#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0)
-#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1)
-#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2)
-#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3)
-
-/* DUK_OP_RETURN flags in A */
-#define DUK_BC_RETURN_FLAG_HAVE_RETVAL (1 << 0)
-
-/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */
-#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */
-#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */
-
-/* misc constants and helper macros */
-#define DUK_BC_REGLIMIT 256 /* if B/C is >= this value, refers to a const */
-#define DUK_BC_ISREG(x) ((x) < DUK_BC_REGLIMIT)
-#define DUK_BC_ISCONST(x) ((x) >= DUK_BC_REGLIMIT)
-#define DUK_BC_LDINT_BIAS (1L << 17)
-#define DUK_BC_LDINTX_SHIFT 18
-#define DUK_BC_JUMP_BIAS (1L << 25)
-
-#endif /* DUK_JS_BYTECODE_H_INCLUDED */
-#line 1 "duk_lexer.h"
-/*
- * Lexer defines.
- */
-
-#ifndef DUK_LEXER_H_INCLUDED
-#define DUK_LEXER_H_INCLUDED
-
-typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct);
-
-/*
- * A token is interpreted as any possible production of InputElementDiv
- * and InputElementRegExp, see E5 Section 7 in its entirety. Note that
- * the E5 "Token" production does not cover all actual tokens of the
- * language (which is explicitly stated in the specification, Section 7.5).
- * Null and boolean literals are defined as part of both ReservedWord
- * (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions. Here,
- * null and boolean values have literal tokens, and are not reserved
- * words.
- *
- * Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER.
- * The number tokens always have a non-negative value. The unary minus
- * operator in "-1.0" is optimized during compilation to yield a single
- * negative constant.
- *
- * Token numbering is free except that reserved words are required to be
- * in a continuous range and in a particular order. See genstrings.py.
- */
-
-#define DUK_LEXER_INITCTX(ctx) duk_lexer_initctx((ctx))
-
-#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt))
-
-#define DUK_LEXER_GETPOINT(ctx,pt) do { (pt)->offset = (ctx)->window[0].offset; \
- (pt)->line = (ctx)->window[0].line; } while (0)
-
-/* currently 6 characters of lookup are actually needed (duk_lexer.c) */
-#define DUK_LEXER_WINDOW_SIZE 6
-#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
-#define DUK_LEXER_BUFFER_SIZE 64
-#endif
-
-#define DUK_TOK_MINVAL 0
-
-/* returned after EOF (infinite amount) */
-#define DUK_TOK_EOF 0
-
-/* identifier names (E5 Section 7.6) */
-#define DUK_TOK_IDENTIFIER 1
-
-/* reserved words: keywords */
-#define DUK_TOK_START_RESERVED 2
-#define DUK_TOK_BREAK 2
-#define DUK_TOK_CASE 3
-#define DUK_TOK_CATCH 4
-#define DUK_TOK_CONTINUE 5
-#define DUK_TOK_DEBUGGER 6
-#define DUK_TOK_DEFAULT 7
-#define DUK_TOK_DELETE 8
-#define DUK_TOK_DO 9
-#define DUK_TOK_ELSE 10
-#define DUK_TOK_FINALLY 11
-#define DUK_TOK_FOR 12
-#define DUK_TOK_FUNCTION 13
-#define DUK_TOK_IF 14
-#define DUK_TOK_IN 15
-#define DUK_TOK_INSTANCEOF 16
-#define DUK_TOK_NEW 17
-#define DUK_TOK_RETURN 18
-#define DUK_TOK_SWITCH 19
-#define DUK_TOK_THIS 20
-#define DUK_TOK_THROW 21
-#define DUK_TOK_TRY 22
-#define DUK_TOK_TYPEOF 23
-#define DUK_TOK_VAR 24
-#define DUK_TOK_CONST 25
-#define DUK_TOK_VOID 26
-#define DUK_TOK_WHILE 27
-#define DUK_TOK_WITH 28
-
-/* reserved words: future reserved words */
-#define DUK_TOK_CLASS 29
-#define DUK_TOK_ENUM 30
-#define DUK_TOK_EXPORT 31
-#define DUK_TOK_EXTENDS 32
-#define DUK_TOK_IMPORT 33
-#define DUK_TOK_SUPER 34
-
-/* "null", "true", and "false" are always reserved words.
- * Note that "get" and "set" are not!
- */
-#define DUK_TOK_NULL 35
-#define DUK_TOK_TRUE 36
-#define DUK_TOK_FALSE 37
-
-/* reserved words: additional future reserved words in strict mode */
-#define DUK_TOK_START_STRICT_RESERVED 38 /* inclusive */
-#define DUK_TOK_IMPLEMENTS 38
-#define DUK_TOK_INTERFACE 39
-#define DUK_TOK_LET 40
-#define DUK_TOK_PACKAGE 41
-#define DUK_TOK_PRIVATE 42
-#define DUK_TOK_PROTECTED 43
-#define DUK_TOK_PUBLIC 44
-#define DUK_TOK_STATIC 45
-#define DUK_TOK_YIELD 46
-
-#define DUK_TOK_END_RESERVED 47 /* exclusive */
-
-/* "get" and "set" are tokens but NOT ReservedWords. They are currently
- * parsed and identifiers and these defines are actually now unused.
- */
-#define DUK_TOK_GET 47
-#define DUK_TOK_SET 48
-
-/* punctuators (unlike the spec, also includes "/" and "/=") */
-#define DUK_TOK_LCURLY 49
-#define DUK_TOK_RCURLY 50
-#define DUK_TOK_LBRACKET 51
-#define DUK_TOK_RBRACKET 52
-#define DUK_TOK_LPAREN 53
-#define DUK_TOK_RPAREN 54
-#define DUK_TOK_PERIOD 55
-#define DUK_TOK_SEMICOLON 56
-#define DUK_TOK_COMMA 57
-#define DUK_TOK_LT 58
-#define DUK_TOK_GT 59
-#define DUK_TOK_LE 60
-#define DUK_TOK_GE 61
-#define DUK_TOK_EQ 62
-#define DUK_TOK_NEQ 63
-#define DUK_TOK_SEQ 64
-#define DUK_TOK_SNEQ 65
-#define DUK_TOK_ADD 66
-#define DUK_TOK_SUB 67
-#define DUK_TOK_MUL 68
-#define DUK_TOK_DIV 69
-#define DUK_TOK_MOD 70
-#define DUK_TOK_INCREMENT 71
-#define DUK_TOK_DECREMENT 72
-#define DUK_TOK_ALSHIFT 73 /* named "arithmetic" because result is signed */
-#define DUK_TOK_ARSHIFT 74
-#define DUK_TOK_RSHIFT 75
-#define DUK_TOK_BAND 76
-#define DUK_TOK_BOR 77
-#define DUK_TOK_BXOR 78
-#define DUK_TOK_LNOT 79
-#define DUK_TOK_BNOT 80
-#define DUK_TOK_LAND 81
-#define DUK_TOK_LOR 82
-#define DUK_TOK_QUESTION 83
-#define DUK_TOK_COLON 84
-#define DUK_TOK_EQUALSIGN 85
-#define DUK_TOK_ADD_EQ 86
-#define DUK_TOK_SUB_EQ 87
-#define DUK_TOK_MUL_EQ 88
-#define DUK_TOK_DIV_EQ 89
-#define DUK_TOK_MOD_EQ 90
-#define DUK_TOK_ALSHIFT_EQ 91
-#define DUK_TOK_ARSHIFT_EQ 92
-#define DUK_TOK_RSHIFT_EQ 93
-#define DUK_TOK_BAND_EQ 94
-#define DUK_TOK_BOR_EQ 95
-#define DUK_TOK_BXOR_EQ 96
-
-/* literals (E5 Section 7.8), except null, true, false, which are treated
- * like reserved words (above).
- */
-#define DUK_TOK_NUMBER 97
-#define DUK_TOK_STRING 98
-#define DUK_TOK_REGEXP 99
-
-#define DUK_TOK_MAXVAL 99 /* inclusive */
-
-/* Convert heap string index to a token (reserved words) */
-#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
-
-/* Sanity check */
-#if (DUK_TOK_MAXVAL > 255)
-#error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits
-#endif
-
-/* Sanity checks for string and token defines */
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC)
-#error mismatch in token defines
-#endif
-#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD)
-#error mismatch in token defines
-#endif
-
-/* Regexp tokens */
-#define DUK_RETOK_EOF 0
-#define DUK_RETOK_DISJUNCTION 1
-#define DUK_RETOK_QUANTIFIER 2
-#define DUK_RETOK_ASSERT_START 3
-#define DUK_RETOK_ASSERT_END 4
-#define DUK_RETOK_ASSERT_WORD_BOUNDARY 5
-#define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY 6
-#define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD 7
-#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8
-#define DUK_RETOK_ATOM_PERIOD 9
-#define DUK_RETOK_ATOM_CHAR 10
-#define DUK_RETOK_ATOM_DIGIT 11
-#define DUK_RETOK_ATOM_NOT_DIGIT 12
-#define DUK_RETOK_ATOM_WHITE 13
-#define DUK_RETOK_ATOM_NOT_WHITE 14
-#define DUK_RETOK_ATOM_WORD_CHAR 15
-#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16
-#define DUK_RETOK_ATOM_BACKREFERENCE 17
-#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18
-#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19
-#define DUK_RETOK_ATOM_START_CHARCLASS 20
-#define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED 21
-#define DUK_RETOK_ATOM_END_GROUP 22
-
-/* Constants for duk_lexer_ctx.buf. */
-#define DUK_LEXER_TEMP_BUF_LIMIT 256
-
-/* A token value. Can be memcpy()'d, but note that slot1/slot2 values are on the valstack.
- * Some fields (like num, str1, str2) are only valid for specific token types and may have
- * stale values otherwise.
- */
-struct duk_token {
- duk_small_int_t t; /* token type (with reserved word identification) */
- duk_small_int_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
- duk_double_t num; /* numeric value of token */
- duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
- duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
- duk_size_t start_offset; /* start byte offset of token in lexer input */
- duk_int_t start_line; /* start line of token (first char) */
- duk_int_t num_escapes; /* number of escapes and line continuations (for directive prologue) */
- duk_bool_t lineterm; /* token was preceded by a lineterm */
- duk_bool_t allow_auto_semi; /* token allows automatic semicolon insertion (eof or preceded by newline) */
-};
-
-#define DUK_RE_QUANTIFIER_INFINITE ((duk_uint32_t) 0xffffffffUL)
-
-/* A regexp token value. */
-struct duk_re_token {
- duk_small_int_t t; /* token type */
- duk_small_int_t greedy;
- duk_uint_fast32_t num; /* numeric value (character, count) */
- duk_uint_fast32_t qmin;
- duk_uint_fast32_t qmax;
-};
-
-/* A structure for 'snapshotting' a point for rewinding */
-struct duk_lexer_point {
- duk_size_t offset;
- duk_int_t line;
-};
-
-/* Lexer codepoint with additional info like offset/line number */
-struct duk_lexer_codepoint {
- duk_codepoint_t codepoint;
- duk_size_t offset;
- duk_int_t line;
-};
-
-/* Lexer context. Same context is used for Ecmascript and Regexp parsing. */
-struct duk_lexer_ctx {
-#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
- duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */
- duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE];
-#else
- duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */
-#endif
-
- duk_hthread *thr; /* thread; minimizes argument passing */
-
- const duk_uint8_t *input; /* input string (may be a user pointer) */
- duk_size_t input_length; /* input byte length */
- duk_size_t input_offset; /* input offset for window leading edge (not window[0]) */
- duk_int_t input_line; /* input linenumber at input_offset (not window[0]), init to 1 */
-
- duk_idx_t slot1_idx; /* valstack slot for 1st token value */
- duk_idx_t slot2_idx; /* valstack slot for 2nd token value */
- duk_idx_t buf_idx; /* valstack slot for temp buffer */
- duk_hbuffer_dynamic *buf; /* temp accumulation buffer */
- duk_bufwriter_ctx bw; /* bufwriter for temp accumulation */
-
- duk_int_t token_count; /* number of tokens parsed */
- duk_int_t token_limit; /* maximum token count before error (sanity backstop) */
-};
-
-/*
- * Prototypes
- */
-
-DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
-
-DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
-
-DUK_INTERNAL_DECL
-void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
- duk_token *out_token,
- duk_bool_t strict_mode,
- duk_bool_t regexp_mode);
-#ifdef DUK_USE_REGEXP_SUPPORT
-DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
-DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
-#endif /* DUK_USE_REGEXP_SUPPORT */
-
-#endif /* DUK_LEXER_H_INCLUDED */
-#line 1 "duk_js_compiler.h"
-/*
- * Ecmascript compiler.
- */
-
-#ifndef DUK_JS_COMPILER_H_INCLUDED
-#define DUK_JS_COMPILER_H_INCLUDED
-
-/* ecmascript compiler limits */
-#define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */
-
-/* maximum loopcount for peephole optimization */
-#define DUK_COMPILER_PEEPHOLE_MAXITER 3
-
-/* maximum bytecode length in instructions */
-#define DUK_COMPILER_MAX_BYTECODE_LENGTH (256L * 1024L * 1024L) /* 1 GB */
-
-/*
- * Compiler intermediate values
- *
- * Intermediate values describe either plain values (e.g. strings or
- * numbers) or binary operations which have not yet been coerced into
- * either a left-hand-side or right-hand-side role (e.g. object property).
- */
-
-#define DUK_IVAL_NONE 0 /* no value */
-#define DUK_IVAL_PLAIN 1 /* register, constant, or value */
-#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
-#define DUK_IVAL_ARITH_EXTRAOP 3 /* binary arithmetic using extraops; DUK_EXTRAOP_INSTOF etc */
-#define DUK_IVAL_PROP 4 /* property access */
-#define DUK_IVAL_VAR 5 /* variable access */
-
-#define DUK_ISPEC_NONE 0 /* no value */
-#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */
-#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */
-
-/* bit mask which indicates that a regconst is a constant instead of a register */
-#define DUK_JS_CONST_MARKER 0x80000000UL
-
-/* type to represent a reg/const reference during compilation */
-typedef duk_uint32_t duk_regconst_t;
-
-/* type to represent a straight register reference, with <0 indicating none */
-typedef duk_int32_t duk_reg_t;
-
-typedef struct {
- duk_small_uint_t t; /* DUK_ISPEC_XXX */
- duk_regconst_t regconst;
- duk_idx_t valstack_idx; /* always set; points to a reserved valstack slot */
-} duk_ispec;
-
-typedef struct {
- /*
- * PLAIN: x1
- * ARITH: x1 <op> x2
- * PROP: x1.x2
- * VAR: x1 (name)
- */
-
- /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */
- duk_small_uint_t t; /* DUK_IVAL_XXX */
- duk_small_uint_t op; /* bytecode opcode (or extraop) for binary ops */
- duk_ispec x1;
- duk_ispec x2;
-} duk_ivalue;
-
-/*
- * Bytecode instruction representation during compilation
- *
- * Contains the actual instruction and (optionally) debug info.
- */
-
-struct duk_compiler_instr {
- duk_instr_t ins;
-#if defined(DUK_USE_PC2LINE)
- duk_uint32_t line;
-#endif
-};
-
-/*
- * Compiler state
- */
-
-#define DUK_LABEL_FLAG_ALLOW_BREAK (1 << 0)
-#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1 << 1)
-
-#define DUK_DECL_TYPE_VAR 0
-#define DUK_DECL_TYPE_FUNC 1
-
-/* XXX: optimize to 16 bytes */
-typedef struct {
- duk_small_uint_t flags;
- duk_int_t label_id; /* numeric label_id (-1 reserved as marker) */
- duk_hstring *h_label; /* borrowed label name */
- duk_int_t catch_depth; /* catch depth at point of definition */
- duk_int_t pc_label; /* pc of label statement:
- * pc+1: break jump site
- * pc+2: continue jump site
- */
-
- /* Fast jumps (which avoid longjmp) jump directly to the jump sites
- * which are always known even while the iteration/switch statement
- * is still being parsed. A final peephole pass "straightens out"
- * the jumps.
- */
-} duk_labelinfo;
-
-/* Compiling state of one function, eventually converted to duk_hcompiledfunction */
-struct duk_compiler_func {
- /* These pointers are at the start of the struct so that they pack
- * nicely. Mixing pointers and integer values is bad on some
- * platforms (e.g. if int is 32 bits and pointers are 64 bits).
- */
-
- duk_bufwriter_ctx bw_code; /* bufwriter for code */
-
- duk_hstring *h_name; /* function name (borrowed reference), ends up in _name */
- /* h_code: held in bw_code */
- duk_hobject *h_consts; /* array */
- duk_hobject *h_funcs; /* array of function templates: [func1, offset1, line1, func2, offset2, line2]
- * offset/line points to closing brace to allow skipping on pass 2
- */
- duk_hobject *h_decls; /* array of declarations: [ name1, val1, name2, val2, ... ]
- * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars)
- * record function and variable declarations in pass 1
- */
- duk_hobject *h_labelnames; /* array of active label names */
- duk_hbuffer_dynamic *h_labelinfos; /* C array of duk_labelinfo */
- duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */
- duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
-
- /* value stack indices for tracking objects */
- /* code_idx: not needed */
- duk_idx_t consts_idx;
- duk_idx_t funcs_idx;
- duk_idx_t decls_idx;
- duk_idx_t labelnames_idx;
- duk_idx_t labelinfos_idx;
- duk_idx_t argnames_idx;
- duk_idx_t varmap_idx;
-
- /* temp reg handling */
- duk_reg_t temp_first; /* first register that is a temporary (below: variables) */
- duk_reg_t temp_next; /* next temporary register to allocate */
- duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
-
- /* shuffle registers if large number of regs/consts */
- duk_reg_t shuffle1;
- duk_reg_t shuffle2;
- duk_reg_t shuffle3;
-
- /* stats for current expression being parsed */
- duk_int_t nud_count;
- duk_int_t led_count;
- duk_int_t paren_level; /* parenthesis count, 0 = top level */
- duk_bool_t expr_lhs; /* expression is left-hand-side compatible */
- duk_bool_t allow_in; /* current paren level allows 'in' token */
-
- /* misc */
- duk_int_t stmt_next; /* statement id allocation (running counter) */
- duk_int_t label_next; /* label id allocation (running counter) */
- duk_int_t catch_depth; /* catch stack depth */
- duk_int_t with_depth; /* with stack depth (affects identifier lookups) */
- duk_int_t fnum_next; /* inner function numbering */
- duk_int_t num_formals; /* number of formal arguments */
- duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_int_t min_line; /* XXX: typing (duk_hcompiledfunction has duk_uint32_t) */
- duk_int_t max_line;
-#endif
-
- /* status booleans */
- duk_bool_t is_function; /* is an actual function (not global/eval code) */
- duk_bool_t is_eval; /* is eval code */
- duk_bool_t is_global; /* is global code */
- duk_bool_t is_setget; /* is a setter/getter */
- duk_bool_t is_decl; /* is a function declaration (as opposed to function expression) */
- duk_bool_t is_strict; /* function is strict */
- duk_bool_t is_notail; /* function must not be tail called */
- duk_bool_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
- duk_bool_t in_scanning; /* parsing in "scanning" phase (first pass) */
- duk_bool_t may_direct_eval; /* function may call direct eval */
- duk_bool_t id_access_arguments; /* function refers to 'arguments' identifier */
- duk_bool_t id_access_slow; /* function makes one or more slow path accesses */
- duk_bool_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
- duk_bool_t needs_shuffle; /* function needs shuffle registers */
- duk_bool_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
-};
-
-struct duk_compiler_ctx {
- duk_hthread *thr;
-
- /* filename being compiled (ends up in functions' '_filename' property) */
- duk_hstring *h_filename; /* borrowed reference */
-
- /* lexing (tokenization) state (contains two valstack slot indices) */
- duk_lexer_ctx lex;
-
- /* current and previous token for parsing */
- duk_token prev_token;
- duk_token curr_token;
- duk_idx_t tok11_idx; /* curr_token slot1 (matches 'lex' slot1_idx) */
- duk_idx_t tok12_idx; /* curr_token slot2 (matches 'lex' slot2_idx) */
- duk_idx_t tok21_idx; /* prev_token slot1 */
- duk_idx_t tok22_idx; /* prev_token slot2 */
-
- /* recursion limit */
- duk_int_t recursion_depth;
- duk_int_t recursion_limit;
-
- /* code emission temporary */
- duk_int_t emit_jumpslot_pc;
-
- /* current function being compiled (embedded instead of pointer for more compact access) */
- duk_compiler_func curr_func;
-};
-
-/*
- * Prototypes
- */
-
-#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */
-#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */
-#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */
-
-DUK_INTERNAL_DECL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags);
-
-#endif /* DUK_JS_COMPILER_H_INCLUDED */
-#line 1 "duk_regexp.h"
-/*
- * Regular expression structs, constants, and bytecode defines.
- */
-
-#ifndef DUK_REGEXP_H_INCLUDED
-#define DUK_REGEXP_H_INCLUDED
-
-/* maximum bytecode copies for {n,m} quantifiers */
-#define DUK_RE_MAX_ATOM_COPIES 1000
-
-/* regexp compilation limits */
-#define DUK_RE_COMPILE_TOKEN_LIMIT 100000000L /* 1e8 */
-
-/* regexp execution limits */
-#define DUK_RE_EXECUTE_STEPS_LIMIT 1000000000L /* 1e9 */
-
-/* regexp opcodes */
-#define DUK_REOP_MATCH 1
-#define DUK_REOP_CHAR 2
-#define DUK_REOP_PERIOD 3
-#define DUK_REOP_RANGES 4
-#define DUK_REOP_INVRANGES 5
-#define DUK_REOP_JUMP 6
-#define DUK_REOP_SPLIT1 7
-#define DUK_REOP_SPLIT2 8
-#define DUK_REOP_SQMINIMAL 9
-#define DUK_REOP_SQGREEDY 10
-#define DUK_REOP_SAVE 11
-#define DUK_REOP_WIPERANGE 12
-#define DUK_REOP_LOOKPOS 13
-#define DUK_REOP_LOOKNEG 14
-#define DUK_REOP_BACKREFERENCE 15
-#define DUK_REOP_ASSERT_START 16
-#define DUK_REOP_ASSERT_END 17
-#define DUK_REOP_ASSERT_WORD_BOUNDARY 18
-#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19
-
-/* flags */
-#define DUK_RE_FLAG_GLOBAL (1 << 0)
-#define DUK_RE_FLAG_IGNORE_CASE (1 << 1)
-#define DUK_RE_FLAG_MULTILINE (1 << 2)
-
-struct duk_re_matcher_ctx {
- duk_hthread *thr;
-
- duk_uint32_t re_flags;
- const duk_uint8_t *input;
- const duk_uint8_t *input_end;
- const duk_uint8_t *bytecode;
- const duk_uint8_t *bytecode_end;
- const duk_uint8_t **saved; /* allocated from valstack (fixed buffer) */
- duk_uint32_t nsaved;
- duk_uint32_t recursion_depth;
- duk_uint32_t recursion_limit;
- duk_uint32_t steps_count;
- duk_uint32_t steps_limit;
-};
-
-struct duk_re_compiler_ctx {
- duk_hthread *thr;
-
- duk_uint32_t re_flags;
- duk_lexer_ctx lex;
- duk_re_token curr_token;
- duk_bufwriter_ctx bw;
- duk_uint32_t captures; /* highest capture number emitted so far (used as: ++captures) */
- duk_uint32_t highest_backref;
- duk_uint32_t recursion_depth;
- duk_uint32_t recursion_limit;
- duk_uint32_t nranges; /* internal temporary value, used for char classes */
-};
-
-/*
- * Prototypes
- */
-
-DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */
-
-#endif /* DUK_REGEXP_H_INCLUDED */
-#line 1 "duk_heaphdr.h"
-/*
- * Heap header definition and assorted macros, including ref counting.
- * Access all fields through the accessor macros.
- */
-
-#ifndef DUK_HEAPHDR_H_INCLUDED
-#define DUK_HEAPHDR_H_INCLUDED
-
-/*
- * Common heap header
- *
- * All heap objects share the same flags and refcount fields. Objects other
- * than strings also need to have a single or double linked list pointers
- * for insertion into the "heap allocated" list. Strings are held in the
- * heap-wide string table so they don't need link pointers.
- *
- * Technically, 'h_refcount' must be wide enough to guarantee that it cannot
- * wrap (otherwise objects might be freed incorrectly after wrapping). This
- * means essentially that the refcount field must be as wide as data pointers.
- * On 64-bit platforms this means that the refcount needs to be 64 bits even
- * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on
- * this might be reasonable in the future.
- *
- * Heap header size on 32-bit platforms: 8 bytes without reference counting,
- * 16 bytes with reference counting.
- */
-
-struct duk_heaphdr {
- duk_uint32_t h_flags;
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
-#if defined(DUK_USE_REFCOUNT16)
- duk_uint16_t h_refcount16;
-#else
- duk_size_t h_refcount;
-#endif
-#endif
-
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t h_next16;
-#else
- duk_heaphdr *h_next;
-#endif
-
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
- /* refcounting requires direct heap frees, which in turn requires a dual linked heap */
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t h_prev16;
-#else
- duk_heaphdr *h_prev;
-#endif
-#endif
-
- /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the
- * struct won't align nicely to 4 bytes. This 16-bit extra field
- * is added to make the alignment clean; the field can be used by
- * heap objects when 16-bit packing is used. This field is now
- * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be
- * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP;
- * this only matter to low memory environments anyway.
- */
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t h_extra16;
-#endif
-};
-
-struct duk_heaphdr_string {
- /* 16 bits would be enough for shared heaphdr flags and duk_hstring
- * flags. The initial parts of duk_heaphdr_string and duk_heaphdr
- * must match so changing the flags field size here would be quite
- * awkward. However, to minimize struct size, we can pack at least
- * 16 bits of duk_hstring data into the flags field.
- */
- duk_uint32_t h_flags;
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
-#if defined(DUK_USE_REFCOUNT16)
- duk_uint16_t h_refcount16;
- duk_uint16_t h_strextra16; /* round out to 8 bytes */
-#else
- duk_size_t h_refcount;
-#endif
-#endif
-};
-
-#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL
-#define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
-
- /* 2 bits for heap type */
-#define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */
-#define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */
-
-#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
-#define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n))
-#define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
-#define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
-
-#define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */
-#define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */
-#define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */
-#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */
-#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */
-
-#define DUK_HTYPE_MIN 1
-#define DUK_HTYPE_STRING 1
-#define DUK_HTYPE_OBJECT 2
-#define DUK_HTYPE_BUFFER 3
-#define DUK_HTYPE_MAX 3
-
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HEAPHDR_GET_NEXT(heap,h) \
- ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16))
-#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
- (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \
- } while (0)
-#else
-#define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next)
-#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
- (h)->h_next = (val); \
- } while (0)
-#endif
-
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HEAPHDR_GET_PREV(heap,h) \
- ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16))
-#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
- (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \
- } while (0)
-#else
-#define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev)
-#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
- (h)->h_prev = (val); \
- } while (0)
-#endif
-#endif
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
-#if defined(DUK_USE_REFCOUNT16)
-#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16)
-#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
- (h)->h_refcount16 = (val); \
- } while (0)
-#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */
-#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */
-#else
-#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount)
-#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
- (h)->h_refcount = (val); \
- } while (0)
-#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */
-#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */
-#endif
-#else
-/* refcount macros not defined without refcounting, caller must #ifdef now */
-#endif /* DUK_USE_REFERENCE_COUNTING */
-
-/*
- * Note: type is treated as a field separate from flags, so some masking is
- * involved in the macros below.
- */
-
-#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags)
-
-#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
-#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \
- (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
- } while (0)
-
-#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
-#define DUK_HEAPHDR_SET_TYPE(h,val) do { \
- (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
- } while (0)
-
-#define DUK_HEAPHDR_HTYPE_VALID(h) ( \
- DUK_HEAPHDR_GET_TYPE((h)) >= DUK_HTYPE_MIN && \
- DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
- )
-
-#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \
- (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
- ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
- } while (0)
-
-#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \
- DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
- (h)->h_flags |= (bits); \
- } while (0)
-
-#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \
- DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
- (h)->h_flags &= ~((bits)); \
- } while (0)
-
-#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0)
-
-#define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
-#define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
-#define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
-
-#define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
-#define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
-#define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
-
-#define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
-#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
-#define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
-
-#define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
-#define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
-#define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
-
-#define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
-#define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
-#define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
-
-/* get or set a range of flags; m=first bit number, n=number of bits */
-#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL))
-
-#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \
- (h)->h_flags = \
- ((h)->h_flags & (~(((1 << (n)) - 1) << (m)))) \
- | ((v) << (m)); \
- } while (0)
-
-/* init pointer fields to null */
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
-#define DUK_HEAPHDR_INIT_NULLS(h) do { \
- DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
- DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \
- } while (0)
-#else
-#define DUK_HEAPHDR_INIT_NULLS(h) do { \
- DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
- } while (0)
-#endif
-
-#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */
-
-/*
- * Assert helpers
- */
-
-/* Check that prev/next links are consistent: if e.g. h->prev is != NULL,
- * h->prev->next should point back to h.
- */
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_ASSERTIONS)
-#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do { \
- if ((h) != NULL) { \
- duk_heaphdr *h__prev, *h__next; \
- h__prev = DUK_HEAPHDR_GET_PREV((heap), (h)); \
- h__next = DUK_HEAPHDR_GET_NEXT((heap), (h)); \
- DUK_ASSERT(h__prev == NULL || (DUK_HEAPHDR_GET_NEXT((heap), h__prev) == (h))); \
- DUK_ASSERT(h__next == NULL || (DUK_HEAPHDR_GET_PREV((heap), h__next) == (h))); \
- } \
- } while (0)
-#else
-#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0)
-#endif
-
-/*
- * Reference counting helper macros. The macros take a thread argument
- * and must thus always be executed in a specific thread context. The
- * thread argument is needed for features like finalization. Currently
- * it is not required for INCREF, but it is included just in case.
- *
- * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
- * defined without DUK_USE_REFERENCE_COUNTING, so caller must #ifdef
- * around them.
- */
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
-
-#if defined(DUK_USE_ROM_OBJECTS)
-/* With ROM objects "needs refcount update" is true when the value is
- * heap allocated and is not a ROM object.
- */
-/* XXX: double evaluation for 'tv' argument. */
-#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \
- (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv))))
-#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h)))
-#else /* DUK_USE_ROM_OBJECTS */
-/* Without ROM objects "needs refcount update" == is heap allocated. */
-#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv))
-#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1
-#endif /* DUK_USE_ROM_OBJECTS */
-
-/* Fast variants, inline refcount operations except for refzero handling.
- * Can be used explicitly when speed is always more important than size.
- * For a good compiler and a single file build, these are basically the
- * same as a forced inline.
- */
-#define DUK_TVAL_INCREF_FAST(thr,tv) do { \
- duk_tval *duk__tv = (tv); \
- DUK_ASSERT(duk__tv != NULL); \
- if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
- duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
- DUK_ASSERT(duk__h != NULL); \
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
- DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
- } \
- } while (0)
-#define DUK_TVAL_DECREF_FAST(thr,tv) do { \
- duk_tval *duk__tv = (tv); \
- DUK_ASSERT(duk__tv != NULL); \
- if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
- duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
- DUK_ASSERT(duk__h != NULL); \
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
- if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
- duk_heaphdr_refzero((thr), duk__h); \
- } \
- } \
- } while (0)
-#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
- duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
- DUK_ASSERT(duk__h != NULL); \
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
- if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
- DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
- } \
- } while (0)
-#define DUK_HEAPHDR_DECREF_FAST(thr,h) do { \
- duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
- DUK_ASSERT(duk__h != NULL); \
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
- if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
- if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
- duk_heaphdr_refzero((thr), duk__h); \
- } \
- } \
- } while (0)
-
-/* Slow variants, call to a helper to reduce code size.
- * Can be used explicitly when size is always more important than speed.
- */
-#define DUK_TVAL_INCREF_SLOW(thr,tv) do { \
- duk_tval_incref((tv)); \
- } while (0)
-#define DUK_TVAL_DECREF_SLOW(thr,tv) do { \
- duk_tval_decref((thr), (tv)); \
- } while (0)
-#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { \
- duk_heaphdr_incref((duk_heaphdr *) (h)); \
- } while (0)
-#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { \
- duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); \
- } while (0)
-
-/* Default variants. Selection depends on speed/size preference.
- * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
- * is about +1kB for _FAST variants.
- */
-#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv))
-#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv))
-#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h))
-#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST((thr),(h))
-#else
-#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv))
-#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv))
-#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h))
-#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h))
-#endif
-
-/* Casting convenience. */
-#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
-#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
-#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
-#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) (h))
-#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HNATIVEFUNCTION_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HNATIVEFUNCTION_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HBUFFEROBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HBUFFEROBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
-#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF((thr),(duk_heaphdr *) &(h)->obj)
-
-/* Convenience for some situations; the above macros don't allow NULLs
- * for performance reasons.
- */
-#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
- if ((h) != NULL) { \
- DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
- } \
- } while (0)
-#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
- if ((h) != NULL) { \
- DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
- } \
- } while (0)
-
-/*
- * Macros to set a duk_tval and update refcount of the target (decref the
- * old value and incref the new value if necessary). This is both performance
- * and footprint critical; any changes made should be measured for size/speed.
- */
-
-#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_UNDEFINED(tv__dst); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_UNUSED(tv__dst); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_NULL(tv__dst); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_NAN(tv__dst); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-#else
-#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
- DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
-#endif /* DUK_USE_FASTINT */
-
-#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_STRING(tv__dst, (newval)); \
- DUK_HSTRING_INCREF((thr), (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
- DUK_HOBJECT_INCREF((thr), (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
- DUK_HBUFFER_INCREF((thr), (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups,
- * etc, so it's very important for performance. Measure when changing.
- *
- * NOTE: the source and destination duk_tval pointers may be the same, and
- * the macros MUST deal with that correctly.
- */
-
-/* Original idiom used, minimal code size. */
-#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
- duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
- tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
- DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_TVAL_INCREF((thr), tv__src); \
- DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
- } while (0)
-
-/* Faster alternative: avoid making a temporary copy of tvptr_dst and use
- * fast incref/decref macros.
- */
-#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \
- duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
- tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
- DUK_TVAL_INCREF_FAST((thr), tv__src); \
- if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \
- h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
- DUK_ASSERT(h__obj != NULL); \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
- } else { \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- } \
- } while (0)
-
-/* XXX: no optimized variants yet */
-#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
-#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
-#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
-#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
-#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
-#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
-#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
-#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
-#else
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
-#endif /* DUK_USE_FASTINT */
-#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
-#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
-#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
-#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
-#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
-
-#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-/* Optimized for speed. */
-#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1
-#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1
-#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
-#else
-/* Optimized for size. */
-#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
-#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
-#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
-#endif
-
-#else /* DUK_USE_REFERENCE_COUNTING */
-
-#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */
-#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */
-#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */
-#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */
-#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */
-#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */
-#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */
-#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */
-#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */
-#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */
-#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HCOMPILEDFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HCOMPILEDFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HNATIVEFUNCTION_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HNATIVEFUNCTION_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HBUFFEROBJECT_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HBUFFEROBJECT_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */
-#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */
-#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
-#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
-
-#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_UNDEFINED(tv__dst); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_UNUSED(tv__dst); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_NULL(tv__dst); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_NUMBER_CHKFAST(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_NAN(tv__dst); \
- DUK_UNREF((thr)); \
- } while (0)
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT_I32(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_FASTINT_U32(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-#else
-#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
- DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
-#endif /* DUK_USE_FASTINT */
-
-#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_STRING(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
- duk_tval *tv__dst; tv__dst = (tvptr_dst); \
- DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
- duk_tval *tv__dst, *tv__src; \
- tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
- DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
- DUK_UNREF((thr)); \
- } while (0)
-
-#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
-#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
-#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
-#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
-#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
-#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
-#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
-#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
-#if defined(DUK_USE_FASTINT)
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_FASTINT_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_FASTINT_I32_UPDREF_ALT0
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_FASTINT_U32_UPDREF_ALT0
-#else
-#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
-#define DUK_TVAL_SET_FASTINT_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
-#define DUK_TVAL_SET_FASTINT_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
-#endif /* DUK_USE_FASTINT */
-#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
-#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
-#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
-#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
-#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
-
-#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
-#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
-#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
-
-#endif /* DUK_USE_REFERENCE_COUNTING */
-
-#endif /* DUK_HEAPHDR_H_INCLUDED */
-#line 1 "duk_api_internal.h"
-/*
- * Internal API calls which have (stack and other) semantics similar
- * to the public API.
- */
-
-#ifndef DUK_API_INTERNAL_H_INCLUDED
-#define DUK_API_INTERNAL_H_INCLUDED
-
-/* duk_push_sprintf constants */
-#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
-#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
-
-/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not
- * blamed as source of error for error fileName / lineNumber.
- */
-#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
-
-/* Valstack resize flags */
-#define DUK_VSRESIZE_FLAG_SHRINK (1 << 0)
-#define DUK_VSRESIZE_FLAG_COMPACT (1 << 1)
-#define DUK_VSRESIZE_FLAG_THROW (1 << 2)
-
-/* Current convention is to use duk_size_t for value stack sizes and global indices,
- * and duk_idx_t for local frame indices.
- */
-DUK_INTERNAL_DECL
-duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags);
-
-#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index);
-#endif
-
-DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv);
-
-/* Push the current 'this' binding; throw TypeError if binding is not object
- * coercible (CheckObjectCoercible).
- */
-DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_context *ctx);
-
-/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
-DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx);
-
-/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
-DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx);
-
-/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
- * make sure there's an active callstack entry. Note that the returned pointer
- * is unstable with regards to side effects.
- */
-DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx);
-
-/* XXX: add fastint support? */
-#define duk_push_u64(ctx,val) \
- duk_push_number((ctx), (duk_double_t) (val))
-#define duk_push_i64(ctx,val) \
- duk_push_number((ctx), (duk_double_t) (val))
-
-/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
-#define duk_push_u32(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val))
-#define duk_push_i32(ctx,val) \
- duk_push_int((ctx), (duk_int_t) (val))
-
-/* sometimes stack and array indices need to go on the stack */
-#define duk_push_idx(ctx,val) \
- duk_push_int((ctx), (duk_int_t) (val))
-#define duk_push_uarridx(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val))
-#define duk_push_size_t(ctx,val) \
- duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
-
-DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index);
-
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
-
-#if 0 /* This would be pointless: unexpected type and lightfunc would both return NULL */
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
-#endif
-DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
-
-#if 0 /*unused*/
-DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index);
-#endif
-
-DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index);
-#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
-DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index);
-#endif
-DUK_INTERNAL_DECL void duk_to_object_class_string_top(duk_context *ctx);
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h);
-#endif
-
-DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
-DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
-DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval);
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index);
-#endif
-
-DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index);
-
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum);
-
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index);
-
-DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h);
-DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx);
-DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h);
-DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h);
-#define duk_push_hthread(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-#define duk_push_hcompiledfunction(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-#define duk_push_hnativefunction(ctx,h) \
- duk_push_hobject((ctx), (duk_hobject *) (h))
-DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
-DUK_INTERNAL_DECL duk_idx_t duk_push_object_internal(duk_context *ctx);
-DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
-DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
-
-DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz);
-DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv);
-DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv);
-DUK_INTERNAL_DECL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
-
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index);
-DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv);
-#endif
-
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [val] */
-DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [val] -> [] */
-DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
-DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx); /* [] -> [] */
-
-DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
-
-DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags); /* [key val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags); /* [val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
-DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags); /* [] -> [] */
-
-/* These are macros for now, but could be separate functions to reduce code
- * footprint (check call site count before refactoring).
- */
-#define duk_xdef_prop_wec(ctx,obj_index) \
- duk_xdef_prop((ctx), (obj_index), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_index_wec(ctx,obj_index,arr_index) \
- duk_xdef_prop_index((ctx), (obj_index), (arr_index), DUK_PROPDESC_FLAGS_WEC)
-#define duk_xdef_prop_stridx_wec(ctx,obj_index,stridx) \
- duk_xdef_prop_stridx((ctx), (obj_index), (stridx), DUK_PROPDESC_FLAGS_WEC)
-
-/* Set object 'length'. */
-DUK_INTERNAL_DECL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length);
-
-/* Raw internal valstack access macros: access is unsafe so call site
- * must have a guarantee that the index is valid. When that is the case,
- * using these macro results in faster and smaller code than duk_get_tval().
- * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
- */
-#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \
- (DUK_ASSERT_EXPR((idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
-#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \
- (DUK_ASSERT_EXPR((idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
-#define DUK_GET_TVAL_NEGIDX(ctx,idx) \
- (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx))
-#define DUK_GET_TVAL_POSIDX(ctx,idx) \
- (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx))
-#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \
- (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx)))
-#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \
- (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx)))
-
-#endif /* DUK_API_INTERNAL_H_INCLUDED */
-#line 1 "duk_hstring.h"
-/*
- * Heap string representation.
- *
- * Strings are byte sequences ordinarily stored in extended UTF-8 format,
- * allowing values larger than the official UTF-8 range (used internally)
- * and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format).
- * Strings may also be invalid UTF-8 altogether which is the case e.g. with
- * strings used as internal property names and raw buffers converted to
- * strings. In such cases the 'clen' field contains an inaccurate value.
- *
- * Ecmascript requires support for 32-bit long strings. However, since each
- * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only
- * support about 1.4G codepoint long strings in extreme cases. This is not
- * really a practical issue.
- */
-
-#ifndef DUK_HSTRING_H_INCLUDED
-#define DUK_HSTRING_H_INCLUDED
-
-/* Impose a maximum string length for now. Restricted artificially to
- * ensure adding a heap header length won't overflow size_t. The limit
- * should be synchronized with DUK_HBUFFER_MAX_BYTELEN.
- *
- * E5.1 makes provisions to support strings longer than 4G characters.
- * This limit should be eliminated on 64-bit platforms (and increased
- * closer to maximum support on 32-bit platforms).
- */
-
-#if defined(DUK_USE_STRLEN16)
-#define DUK_HSTRING_MAX_BYTELEN (0x0000ffffUL)
-#else
-#define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL)
-#endif
-
-/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings),
- * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not,
- * regexp bytecode is), and "contains non-BMP characters". These are not
- * needed right now.
- */
-
-#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */
-#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */
-#define DUK_HSTRING_FLAG_INTERNAL DUK_HEAPHDR_USER_FLAG(2) /* string is internal */
-#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(3) /* string is a reserved word (non-strict) */
-#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (strict) */
-#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(5) /* string is 'eval' or 'arguments' */
-#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(6) /* string data is external (duk_hstring_external) */
-
-#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
-#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_HAS_INTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
-#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
-#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
-#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
-#define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
-
-#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
-#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_SET_INTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
-#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
-#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
-#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
-#define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
-
-#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
-#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
-#define DUK_HSTRING_CLEAR_INTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_INTERNAL)
-#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
-#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
-#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
-#define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
-
-#if 0 /* Slightly smaller code without explicit flag, but explicit flag
- * is very useful when 'clen' is dropped.
- */
-#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x)))
-#endif
-#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x))
-#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0)
-
-#if defined(DUK_USE_STRHASH16)
-#define DUK_HSTRING_GET_HASH(x) ((x)->hdr.h_flags >> 16)
-#define DUK_HSTRING_SET_HASH(x,v) do { \
- (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \
- } while (0)
-#else
-#define DUK_HSTRING_GET_HASH(x) ((x)->hash)
-#define DUK_HSTRING_SET_HASH(x,v) do { \
- (x)->hash = (v); \
- } while (0)
-#endif
-
-#if defined(DUK_USE_STRLEN16)
-#define DUK_HSTRING_GET_BYTELEN(x) ((x)->hdr.h_strextra16)
-#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
- (x)->hdr.h_strextra16 = (v); \
- } while (0)
-#if defined(DUK_USE_HSTRING_CLEN)
-#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16)
-#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
- (x)->clen16 = (v); \
- } while (0)
-#else
-#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
-#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
- DUK_ASSERT(0); /* should never be called */ \
- } while (0)
-#endif
-#else
-#define DUK_HSTRING_GET_BYTELEN(x) ((x)->blen)
-#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
- (x)->blen = (v); \
- } while (0)
-#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen)
-#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
- (x)->clen = (v); \
- } while (0)
-#endif
-
-#if defined(DUK_USE_HSTRING_EXTDATA)
-#define DUK_HSTRING_GET_EXTDATA(x) \
- ((x)->extdata)
-#define DUK_HSTRING_GET_DATA(x) \
- (DUK_HSTRING_HAS_EXTDATA((x)) ? \
- DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1)))
-#else
-#define DUK_HSTRING_GET_DATA(x) \
- ((const duk_uint8_t *) ((x) + 1))
-#endif
-
-#define DUK_HSTRING_GET_DATA_END(x) \
- (DUK_HSTRING_GET_DATA((x)) + (x)->blen)
-
-/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */
-#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL)
-
-/* get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
- * avoids helper call if string has no array index value.
- */
-#define DUK_HSTRING_GET_ARRIDX_FAST(h) \
- (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
-
-/* slower but more compact variant */
-#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \
- (duk_js_to_arrayindex_string_helper((h)))
-
-/*
- * Misc
- */
-
-struct duk_hstring {
- /* Smaller heaphdr than for other objects, because strings are held
- * in string intern table which requires no link pointers. Much of
- * the 32-bit flags field is unused by flags, so we can stuff a 16-bit
- * field in there.
- */
- duk_heaphdr_string hdr;
-
- /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the
- * shared heap header. Good hashing needs more hash bits though.
- */
-
- /* string hash */
-#if defined(DUK_USE_STRHASH16)
- /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */
-#else
- duk_uint32_t hash;
-#endif
-
- /* length in bytes (not counting NUL term) */
-#if defined(DUK_USE_STRLEN16)
- /* placed in duk_heaphdr_string */
-#else
- duk_uint32_t blen;
-#endif
-
- /* length in codepoints (must be E5 compatible) */
-#if defined(DUK_USE_STRLEN16)
-#if defined(DUK_USE_HSTRING_CLEN)
- duk_uint16_t clen16;
-#else
- /* computed live */
-#endif
-#else
- duk_uint32_t clen;
-#endif
-
- /*
- * String value of 'blen+1' bytes follows (+1 for NUL termination
- * convenience for C API). No alignment needs to be guaranteed
- * for strings, but fields above should guarantee alignment-by-4
- * (but not alignment-by-8).
- */
-};
-
-/* The external string struct is defined even when the feature is inactive. */
-struct duk_hstring_external {
- duk_hstring str;
-
- /*
- * For an external string, the NUL-terminated string data is stored
- * externally. The user must guarantee that data behind this pointer
- * doesn't change while it's used.
- */
-
- const duk_uint8_t *extdata;
-};
-
-/*
- * Prototypes
- */
-
-DUK_INTERNAL_DECL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos);
-
-#if !defined(DUK_USE_HSTRING_CLEN)
-DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
-#endif
-
-#endif /* DUK_HSTRING_H_INCLUDED */
-#line 1 "duk_hobject.h"
-/*
- * Heap object representation.
- *
- * Heap objects are used for Ecmascript objects, arrays, and functions,
- * but also for internal control like declarative and object environment
- * records. Compiled functions, native functions, and threads are also
- * objects but with an extended C struct.
- *
- * Objects provide the required Ecmascript semantics and exotic behaviors
- * especially for property access.
- *
- * Properties are stored in three conceptual parts:
- *
- * 1. A linear 'entry part' contains ordered key-value-attributes triples
- * and is the main method of string properties.
- *
- * 2. An optional linear 'array part' is used for array objects to store a
- * (dense) range of [0,N[ array indexed entries with default attributes
- * (writable, enumerable, configurable). If the array part would become
- * sparse or non-default attributes are required, the array part is
- * abandoned and moved to the 'entry part'.
- *
- * 3. An optional 'hash part' is used to optimize lookups of the entry
- * part; it is used only for objects with sufficiently many properties
- * and can be abandoned without loss of information.
- *
- * These three conceptual parts are stored in a single memory allocated area.
- * This minimizes memory allocation overhead but also means that all three
- * parts are resized together, and makes property access a bit complicated.
- */
-
-#ifndef DUK_HOBJECT_H_INCLUDED
-#define DUK_HOBJECT_H_INCLUDED
-
-/* Object flag. There are currently 26 flag bits available. Make sure
- * this stays in sync with debugger object inspection code.
- */
-#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
-#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
-#define DUK_HOBJECT_FLAG_BOUND DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */
-#define DUK_HOBJECT_FLAG_COMPILEDFUNCTION DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompiledfunction) */
-#define DUK_HOBJECT_FLAG_NATIVEFUNCTION DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnativefunction) */
-#define DUK_HOBJECT_FLAG_BUFFEROBJECT DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufferobject) (always exotic) */
-#define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */
-#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */
-#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */
-#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */
-#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompiledfunction) */
-#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
-#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
-#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */
-#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
-#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
-#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
-#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */
-#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */
-
-#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
-#define DUK_HOBJECT_FLAG_CLASS_BITS 5
-
-#define DUK_HOBJECT_GET_CLASS_NUMBER(h) \
- DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)
-#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \
- DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v))
-
-#define DUK_HOBJECT_GET_CLASS_MASK(h) \
- (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS))
-
-/* Macro for creating flag initializer from a class number.
- * Unsigned type cast is needed to avoid warnings about coercing
- * a signed integer to an unsigned one; the largest class values
- * have the highest bit (bit 31) set which causes this.
- */
-#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
-
-/* E5 Section 8.6.2 + custom classes */
-#define DUK_HOBJECT_CLASS_UNUSED 0
-#define DUK_HOBJECT_CLASS_ARGUMENTS 1
-#define DUK_HOBJECT_CLASS_ARRAY 2
-#define DUK_HOBJECT_CLASS_BOOLEAN 3
-#define DUK_HOBJECT_CLASS_DATE 4
-#define DUK_HOBJECT_CLASS_ERROR 5
-#define DUK_HOBJECT_CLASS_FUNCTION 6
-#define DUK_HOBJECT_CLASS_JSON 7
-#define DUK_HOBJECT_CLASS_MATH 8
-#define DUK_HOBJECT_CLASS_NUMBER 9
-#define DUK_HOBJECT_CLASS_OBJECT 10
-#define DUK_HOBJECT_CLASS_REGEXP 11
-#define DUK_HOBJECT_CLASS_STRING 12
-#define DUK_HOBJECT_CLASS_GLOBAL 13
-#define DUK_HOBJECT_CLASS_OBJENV 14 /* custom */
-#define DUK_HOBJECT_CLASS_DECENV 15 /* custom */
-#define DUK_HOBJECT_CLASS_BUFFER 16 /* custom; implies DUK_HOBJECT_IS_BUFFEROBJECT */
-#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */
-#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */
-#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFFEROBJECT */
-#define DUK_HOBJECT_CLASS_DATAVIEW 20
-#define DUK_HOBJECT_CLASS_INT8ARRAY 21
-#define DUK_HOBJECT_CLASS_UINT8ARRAY 22
-#define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23
-#define DUK_HOBJECT_CLASS_INT16ARRAY 24
-#define DUK_HOBJECT_CLASS_UINT16ARRAY 25
-#define DUK_HOBJECT_CLASS_INT32ARRAY 26
-#define DUK_HOBJECT_CLASS_UINT32ARRAY 27
-#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28
-#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29
-#define DUK_HOBJECT_CLASS_MAX 29
-
-/* class masks */
-#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
-#define DUK_HOBJECT_CMASK_UNUSED (1UL << DUK_HOBJECT_CLASS_UNUSED)
-#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
-#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY)
-#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
-#define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE)
-#define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR)
-#define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION)
-#define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON)
-#define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH)
-#define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER)
-#define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT)
-#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP)
-#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING)
-#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL)
-#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV)
-#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV)
-#define DUK_HOBJECT_CMASK_BUFFER (1UL << DUK_HOBJECT_CLASS_BUFFER)
-#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER)
-#define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD)
-#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
-#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
-#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
-#define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY)
-#define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY)
-#define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY)
-#define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY)
-#define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY)
-#define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY)
-#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
-#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
-
-#define DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS \
- (DUK_HOBJECT_CMASK_BUFFER | \
- DUK_HOBJECT_CMASK_ARRAYBUFFER | \
- DUK_HOBJECT_CMASK_DATAVIEW | \
- DUK_HOBJECT_CMASK_INT8ARRAY | \
- DUK_HOBJECT_CMASK_UINT8ARRAY | \
- DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \
- DUK_HOBJECT_CMASK_INT16ARRAY | \
- DUK_HOBJECT_CMASK_UINT16ARRAY | \
- DUK_HOBJECT_CMASK_INT32ARRAY | \
- DUK_HOBJECT_CMASK_UINT32ARRAY | \
- DUK_HOBJECT_CMASK_FLOAT32ARRAY | \
- DUK_HOBJECT_CMASK_FLOAT64ARRAY)
-
-#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
-#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
-#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
-#define DUK_HOBJECT_IS_ARRAY(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY)
-#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_IS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_IS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
-
-#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-
-#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_BOUND | \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-
-#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
- DUK_HOBJECT_FLAG_BOUND | \
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION | \
- DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-
-/* object has any exotic behavior(s) */
-#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
- DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
- DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
- DUK_HOBJECT_FLAG_BUFFEROBJECT | \
- DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
-
-#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
-
-#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
-#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_HAS_BOUND(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_HAS_BUFFEROBJECT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
-#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
-#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
-#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
-#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
-#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
-#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_HAS_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
-#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
-#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
-#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
-#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
-
-#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
-#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_SET_BOUND(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_SET_COMPILEDFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_SET_NATIVEFUNCTION(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_SET_BUFFEROBJECT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
-#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
-#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
-#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
-#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
-#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
-#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_SET_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
-#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
-#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
-#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
-#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
-
-#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
-#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
-#define DUK_HOBJECT_CLEAR_BOUND(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUND)
-#define DUK_HOBJECT_CLEAR_COMPILEDFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPILEDFUNCTION)
-#define DUK_HOBJECT_CLEAR_NATIVEFUNCTION(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATIVEFUNCTION)
-#define DUK_HOBJECT_CLEAR_BUFFEROBJECT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFFEROBJECT)
-#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
-#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
-#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
-#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
-#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
-#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
-#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
-#define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
-#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
-#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
-#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
-#define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
-#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
-
-/* flags used for property attributes in duk_propdesc and packed flags */
-#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */
-#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */
-#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored
- * (used by e.g. buffer virtual properties)
- */
-#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
- DUK_PROPDESC_FLAG_ENUMERABLE | \
- DUK_PROPDESC_FLAG_CONFIGURABLE | \
- DUK_PROPDESC_FLAG_ACCESSOR)
-
-/* additional flags which are passed in the same flags argument as property
- * flags but are not stored in object properties.
- */
-#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */
-
-/* convenience */
-#define DUK_PROPDESC_FLAGS_NONE 0
-#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE)
-#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE)
-#define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE)
-#define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE)
-#define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
-#define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
-#define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \
- DUK_PROPDESC_FLAG_ENUMERABLE | \
- DUK_PROPDESC_FLAG_CONFIGURABLE)
-
-/* flags for duk_hobject_get_own_propdesc() and variants */
-#define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */
-#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */
-
-/*
- * Macro for object validity check
- *
- * Assert for currently guaranteed relations between flags, for instance.
- */
-
-#define DUK_ASSERT_HOBJECT_VALID(h) do { \
- DUK_ASSERT((h) != NULL); \
- DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \
- DUK_ASSERT(!DUK_HOBJECT_IS_BUFFEROBJECT((h)) || \
- (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_BUFFER || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT16ARRAY || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT16ARRAY || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT32ARRAY || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \
- DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \
- } while (0)
-
-/*
- * Macros to access the 'props' allocation.
- */
-
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HOBJECT_GET_PROPS(heap,h) \
- ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16))
-#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
- ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
- } while (0)
-#else
-#define DUK_HOBJECT_GET_PROPS(heap,h) \
- ((h)->props)
-#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
- (h)->props = (duk_uint8_t *) (x); \
- } while (0)
-#endif
-
-#if defined(DUK_USE_HOBJECT_LAYOUT_1)
-/* LAYOUT 1 */
-#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
- ((duk_hstring **) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) \
- ))
-#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
- ((duk_propvalue *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \
- ))
-#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
- ((duk_uint8_t *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
- ))
-#define DUK_HOBJECT_A_GET_BASE(heap,h) \
- ((duk_tval *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \
- ))
-#define DUK_HOBJECT_H_GET_BASE(heap,h) \
- ((duk_uint32_t *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
- DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
- ))
-#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
- ( \
- (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
- (n_arr) * sizeof(duk_tval) + \
- (n_hash) * sizeof(duk_uint32_t) \
- )
-#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \
- (set_e_k) = (duk_hstring **) (void *) (p_base); \
- (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \
- (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \
- (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \
- (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
- } while (0)
-#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
-/* LAYOUT 2 */
-#if (DUK_USE_ALIGN_BY == 4)
-#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03)
-#elif (DUK_USE_ALIGN_BY == 8)
-#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07)
-#elif (DUK_USE_ALIGN_BY == 1)
-#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0
-#else
-#error invalid DUK_USE_ALIGN_BY
-#endif
-#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
- ((duk_hstring **) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
- ))
-#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
- ((duk_propvalue *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) \
- ))
-#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
- ((duk_uint8_t *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
- ))
-#define DUK_HOBJECT_A_GET_BASE(heap,h) \
- ((duk_tval *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
- DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \
- ))
-#define DUK_HOBJECT_H_GET_BASE(heap,h) \
- ((duk_uint32_t *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
- DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \
- DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
- ))
-#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
- ( \
- (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
- DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \
- (n_arr) * sizeof(duk_tval) + \
- (n_hash) * sizeof(duk_uint32_t) \
- )
-#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \
- (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
- (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \
- (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \
- (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \
- sizeof(duk_uint8_t) * (n_ent) + \
- DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \
- (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
- } while (0)
-#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
-/* LAYOUT 3 */
-#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
- ((duk_hstring **) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \
- DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
- ))
-#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
- ((duk_propvalue *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) \
- ))
-#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
- ((duk_uint8_t *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
- DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \
- DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \
- ))
-#define DUK_HOBJECT_A_GET_BASE(heap,h) \
- ((duk_tval *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
- ))
-#define DUK_HOBJECT_H_GET_BASE(heap,h) \
- ((duk_uint32_t *) (void *) ( \
- DUK_HOBJECT_GET_PROPS((heap), (h)) + \
- DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
- DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
- ))
-#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
- ( \
- (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \
- (n_arr) * sizeof(duk_tval) + \
- (n_hash) * sizeof(duk_uint32_t) \
- )
-#define DUK_HOBJECT_P_SET_REALLOC_PTRS(p_base,set_e_k,set_e_pv,set_e_f,set_a,set_h,n_ent,n_arr,n_hash) do { \
- (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
- (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \
- (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \
- (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \
- (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \
- } while (0)
-#else
-#error invalid hobject layout defines
-#endif /* hobject property layout */
-
-#define DUK_HOBJECT_P_ALLOC_SIZE(h) \
- DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h)))
-
-#define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
-#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
-#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
-#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
-#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
-#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
-#define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
-#define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
-
-#define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \
- DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \
- } while (0)
-#define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \
- DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \
- } while (0)
-#define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \
- DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \
- } while (0)
-#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \
- DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \
- } while (0)
-#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \
- 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)) = (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); \
- } while (0)
-#define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \
- DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */
-#define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \
- DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \
- } while (0)
-
-#define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \
- DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \
- } while (0)
-
-#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \
- DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \
- } while (0)
-
-#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0)
-#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
-#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
-#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
-
-#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
-#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
-#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
-#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
-
-#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
-#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
-#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
-#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
-
-#define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0)
-#define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
-#define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
-#define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
-
-#define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL
-#define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL
-
-/*
- * Macros for accessing size fields
- */
-
-#if defined(DUK_USE_OBJSIZES16)
-#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16)
-#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0)
-#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16)
-#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0)
-#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++)
-#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16)
-#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0)
-#if defined(DUK_USE_HOBJECT_HASH_PART)
-#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16)
-#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0)
-#else
-#define DUK_HOBJECT_GET_HSIZE(h) 0
-#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
-#endif
-#else
-#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size)
-#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0)
-#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next)
-#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0)
-#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++)
-#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size)
-#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0)
-#if defined(DUK_USE_HOBJECT_HASH_PART)
-#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size)
-#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0)
-#else
-#define DUK_HOBJECT_GET_HSIZE(h) 0
-#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
-#endif
-#endif
-
-/*
- * Misc
- */
-
-/* Maximum prototype traversal depth. Sanity limit which handles e.g.
- * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4).
- */
-#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
-
-/* Maximum traversal depth for "bound function" chains. */
-#define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L
-
-/*
- * Ecmascript [[Class]]
- */
-
-/* range check not necessary because all 4-bit values are mapped */
-#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)]
-
-#define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \
- DUK_HEAP_GET_STRING( \
- (heap), \
- DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \
- )
-
-/*
- * Macros for property handling
- */
-
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
- ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16))
-#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
- (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
- } while (0)
-#else
-#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
- ((h)->prototype)
-#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
- (h)->prototype = (x); \
- } while (0)
-#endif
-
-/* note: this updates refcounts */
-#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
-
-/*
- * Resizing and hash behavior
- */
-
-/* Sanity limit on max number of properties (allocated, not necessarily used).
- * This is somewhat arbitrary, but if we're close to 2**32 properties some
- * algorithms will fail (e.g. hash size selection, next prime selection).
- * Also, we use negative array/entry table indices to indicate 'not found',
- * so anything above 0x80000000 will cause trouble now.
- */
-#if defined(DUK_USE_OBJSIZES16)
-#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL
-#else
-#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */
-#endif
-
-/* higher value conserves memory; also note that linear scan is cache friendly */
-#define DUK_HOBJECT_E_USE_HASH_LIMIT 32
-
-/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */
-#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */
-
-/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */
-#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */
-
-/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */
-/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */
-#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */
-
-/* internal align target for props allocation, must be 2*n for some n */
-#if (DUK_USE_ALIGN_BY == 4)
-#define DUK_HOBJECT_ALIGN_TARGET 4
-#elif (DUK_USE_ALIGN_BY == 8)
-#define DUK_HOBJECT_ALIGN_TARGET 8
-#elif (DUK_USE_ALIGN_BY == 1)
-#define DUK_HOBJECT_ALIGN_TARGET 1
-#else
-#error invalid DUK_USE_ALIGN_BY
-#endif
-
-/* controls for minimum entry part growth */
-#define DUK_HOBJECT_E_MIN_GROW_ADD 16
-#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
-
-/* controls for minimum array part growth */
-#define DUK_HOBJECT_A_MIN_GROW_ADD 16
-#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
-
-/* probe sequence */
-#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
-#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
-
-/*
- * PC-to-line constants
- */
-
-#define DUK_PC2LINE_SKIP 64
-
-/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */
-#define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8)
-
-/*
- * Struct defs
- */
-
-struct duk_propaccessor {
- duk_hobject *get;
- duk_hobject *set;
-};
-
-union duk_propvalue {
- /* The get/set pointers could be 16-bit pointer compressed but it
- * would make no difference on 32-bit platforms because duk_tval is
- * 8 bytes or more anyway.
- */
- duk_tval v;
- duk_propaccessor a;
-};
-
-struct duk_propdesc {
- /* read-only values 'lifted' for ease of use */
- duk_small_int_t flags;
- duk_hobject *get;
- duk_hobject *set;
-
- /* for updating (all are set to < 0 for virtual properties) */
- duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */
- duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */
- duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */
-};
-
-struct duk_hobject {
- duk_heaphdr hdr;
-
- /*
- * 'props' contains {key,value,flags} entries, optional array entries, and
- * an optional hash lookup table for non-array entries in a single 'sliced'
- * allocation. There are several layout options, which differ slightly in
- * generated code size/speed and alignment/padding; duk_features.h selects
- * the layout used.
- *
- * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1):
- *
- * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
- * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
- * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
- * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
- * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
- * 0xffffffffUL = unused, 0xfffffffeUL = deleted
- *
- * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2):
- *
- * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
- * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
- * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable)
- * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
- * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
- * 0xffffffffUL = unused, 0xfffffffeUL = deleted
- *
- * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3):
- *
- * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
- * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
- * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
- * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
- * 0xffffffffUL = unused, 0xfffffffeUL = deleted
- * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
- *
- * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms
- * requiring 4 or 8 byte alignment. This ensures proper alignment
- * for the entries, at the cost of memory footprint. However, it's
- * probably preferable to use another layout on such platforms instead.
- *
- * In layout 2, the key and value parts are swapped to avoid padding
- * the key array on platforms requiring alignment by 8. The flags part
- * is padded to get alignment for array entries. The 'e_next' count does
- * not need to be rounded as in layout 1.
- *
- * In layout 3, entry values and array values are always aligned properly,
- * and assuming pointers are at most 8 bytes, so are the entry keys. Hash
- * indices will be properly aligned (assuming pointers are at least 4 bytes).
- * Finally, flags don't need additional alignment. This layout provides
- * compact allocations without padding (even on platforms with alignment
- * requirements) at the cost of a bit slower lookups.
- *
- * Objects with few keys don't have a hash index; keys are looked up linearly,
- * which is cache efficient because the keys are consecutive. Larger objects
- * have a hash index part which contains integer indexes to the entries part.
- *
- * A single allocation reduces memory allocation overhead but requires more
- * work when any part needs to be resized. A sliced allocation for entries
- * makes linear key matching faster on most platforms (more locality) and
- * skimps on flags size (which would be followed by 3 bytes of padding in
- * most architectures if entries were placed in a struct).
- *
- * 'props' also contains internal properties distinguished with a non-BMP
- * prefix. Often used properties should be placed early in 'props' whenever
- * possible to make accessing them as fast a possible.
- */
-
-#if defined(DUK_USE_HEAPPTR16)
- /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like
- * duk_hcompiledfunction) are not free to use h_extra16 for this reason.
- */
-#else
- duk_uint8_t *props;
-#endif
-
- /* prototype: the only internal property lifted outside 'e' as it is so central */
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t prototype16;
-#else
- duk_hobject *prototype;
-#endif
-
-#if defined(DUK_USE_OBJSIZES16)
- duk_uint16_t e_size16;
- duk_uint16_t e_next16;
- duk_uint16_t a_size16;
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- duk_uint16_t h_size16;
-#endif
-#else
- duk_uint32_t e_size; /* entry part size */
- duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */
- duk_uint32_t a_size; /* array part size (entirely gc reachable) */
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- duk_uint32_t h_size; /* hash part size or 0 if unused */
-#endif
-#endif
-};
-
-/*
- * Exposed data
- */
-
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
-#endif /* !DUK_SINGLE_FILE */
-
-/*
- * Prototypes
- */
-
-/* alloc and init */
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-#if 0 /* unused */
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags);
-#endif
-DUK_INTERNAL_DECL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL_DECL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags);
-
-/* low-level property functions */
-DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
-DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
-DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs);
-DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags);
-
-/* XXX: when optimizing for guaranteed property slots, use a guaranteed
- * slot for internal value; this call can then access it directly.
- */
-#define duk_hobject_get_internal_value_tval_ptr(heap,obj) \
- duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap)))
-
-/* core property functions */
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
-
-/* internal property functions */
-#define DUK_DELPROP_FLAG_THROW (1 << 0)
-#define DUK_DELPROP_FLAG_FORCE (1 << 1)
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
-DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags);
-DUK_INTERNAL_DECL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length); /* XXX: duk_uarridx_t? */
-DUK_INTERNAL_DECL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj);
-DUK_INTERNAL_DECL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj); /* XXX: duk_uarridx_t? */
-
-/* helpers for defineProperty() and defineProperties() */
-DUK_INTERNAL_DECL
-void duk_hobject_prepare_property_descriptor(duk_context *ctx,
- duk_idx_t idx_in,
- duk_uint_t *out_defprop_flags,
- duk_idx_t *out_idx_value,
- duk_hobject **out_getter,
- duk_hobject **out_setter);
-DUK_INTERNAL_DECL
-void duk_hobject_define_property_helper(duk_context *ctx,
- duk_uint_t defprop_flags,
- duk_hobject *obj,
- duk_hstring *key,
- duk_idx_t idx_value,
- duk_hobject *get,
- duk_hobject *set);
-
-/* Object built-in methods */
-DUK_INTERNAL_DECL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx);
-DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags);
-
-/* internal properties */
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
-DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
-
-/* hobject management functions */
-DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
-
-/* ES6 proxy */
-#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
-DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj);
-#endif
-
-/* enumeration */
-DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags);
-DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags);
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value);
-
-/* macros */
-DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
-
-/* finalization */
-DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj);
-
-/* pc2line */
-#if defined(DUK_USE_PC2LINE)
-DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
-DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc);
-#endif
-
-/* misc */
-DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop);
-
-#endif /* DUK_HOBJECT_H_INCLUDED */
-#line 1 "duk_hcompiledfunction.h"
-/*
- * Heap compiled function (Ecmascript function) representation.
- *
- * There is a single data buffer containing the Ecmascript function's
- * bytecode, constants, and inner functions.
- */
-
-#ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED
-#define DUK_HCOMPILEDFUNCTION_H_INCLUDED
-
-/*
- * Field accessor macros
- */
-
-/* XXX: casts could be improved, especially for GET/SET DATA */
-
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
- ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
-#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
- (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
- } while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
- ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
-#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
- (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
- } while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
- ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
-#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
- (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
- } while (0)
-#else
-#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
- ((duk_hbuffer_fixed *) (void *) (h)->data)
-#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
- (h)->data = (duk_hbuffer *) (v); \
- } while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h) \
- ((h)->funcs)
-#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v) do { \
- (h)->funcs = (v); \
- } while (0)
-#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h) \
- ((h)->bytecode)
-#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v) do { \
- (h)->bytecode = (v); \
- } while (0)
-#endif
-
-/*
- * Accessor macros for function specific data areas
- */
-
-/* Note: assumes 'data' is always a fixed buffer */
-#define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(heap,h) \
- DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h)))
-
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap,h) \
- ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((heap), (h)))
-
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap,h) \
- DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h))
-
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap,h) \
- DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h))
-
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap,h) \
- ((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h)))
-
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap,h) \
- ((duk_hobject **) (void *) DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h)))
-
-/* XXX: double evaluation of DUK_HCOMPILEDFUNCTION_GET_DATA() */
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_END(heap,h) \
- ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + \
- DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA((heap), h))))
-
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(heap,h) \
- ( \
- (duk_size_t) \
- ( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((heap), (h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((heap), (h))) \
- ) \
- )
-
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(heap,h) \
- ( \
- (duk_size_t) \
- ( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((heap), (h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((heap), (h))) \
- ) \
- )
-
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap,h) \
- ( \
- (duk_size_t) \
- ( \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((heap),(h))) - \
- ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((heap),(h))) \
- ) \
- )
-
-#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
-
-#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
-
-#define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(heap,h) \
- ((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
-
-
-/*
- * Main struct
- */
-
-struct duk_hcompiledfunction {
- /* shared object part */
- duk_hobject obj;
-
- /*
- * Pointers to function data area for faster access. Function
- * data is a buffer shared between all closures of the same
- * "template" function. The data buffer is always fixed (non-
- * dynamic, hence stable), with a layout as follows:
- *
- * constants (duk_tval)
- * inner functions (duk_hobject *)
- * bytecode (duk_instr_t)
- *
- * Note: bytecode end address can be computed from 'data' buffer
- * size. It is not strictly necessary functionally, assuming
- * bytecode never jumps outside its allocated area. However,
- * it's a safety/robustness feature for avoiding the chance of
- * executing random data as bytecode due to a compiler error.
- *
- * Note: values in the data buffer must be incref'd (they will
- * be decref'd on release) for every compiledfunction referring
- * to the 'data' element.
- */
-
- /* Data area, fixed allocation, stable data ptrs. */
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t data16;
-#else
- duk_hbuffer *data;
-#endif
-
- /* No need for constants pointer (= same as data).
- *
- * When using 16-bit packing alignment to 4 is nice. 'funcs' will be
- * 4-byte aligned because 'constants' are duk_tvals. For now the
- * inner function pointers are not compressed, so that 'bytecode' will
- * also be 4-byte aligned.
- */
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t funcs16;
- duk_uint16_t bytecode16;
-#else
- duk_hobject **funcs;
- duk_instr_t *bytecode;
-#endif
-
- /*
- * 'nregs' registers are allocated on function entry, at most 'nargs'
- * are initialized to arguments, and the rest to undefined. Arguments
- * above 'nregs' are not mapped to registers. All registers in the
- * active stack range must be initialized because they are GC reachable.
- * 'nargs' is needed so that if the function is given more than 'nargs'
- * arguments, the additional arguments do not 'clobber' registers
- * beyond 'nregs' which must be consistently initialized to undefined.
- *
- * Usually there is no need to know which registers are mapped to
- * local variables. Registers may be allocated to variable in any
- * way (even including gaps). However, a register-variable mapping
- * must be the same for the duration of the function execution and
- * the register cannot be used for anything else.
- *
- * When looking up variables by name, the '_Varmap' map is used.
- * When an activation closes, registers mapped to arguments are
- * copied into the environment record based on the same map. The
- * reverse map (from register to variable) is not currently needed
- * at run time, except for debugging, so it is not maintained.
- */
-
- duk_uint16_t nregs; /* regs to allocate */
- duk_uint16_t nargs; /* number of arguments allocated to regs */
-
- /*
- * Additional control information is placed into the object itself
- * as internal properties to avoid unnecessary fields for the
- * majority of functions. The compiler tries to omit internal
- * control fields when possible.
- *
- * Function templates:
- *
- * {
- * name: "func", // declaration, named function expressions
- * fileName: <debug info for creating nice errors>
- * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
- * _Formals: [ "arg1", "arg2" ],
- * _Source: "function func(arg1, arg2) { ... }",
- * _Pc2line: <debug info for pc-to-line mapping>,
- * }
- *
- * Function instances:
- *
- * {
- * length: 2,
- * prototype: { constructor: <func> },
- * caller: <thrower>,
- * arguments: <thrower>,
- * name: "func", // declaration, named function expressions
- * fileName: <debug info for creating nice errors>
- * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
- * _Formals: [ "arg1", "arg2" ],
- * _Source: "function func(arg1, arg2) { ... }",
- * _Pc2line: <debug info for pc-to-line mapping>,
- * _Varenv: <variable environment of closure>,
- * _Lexenv: <lexical environment of closure (if differs from _Varenv)>
- * }
- *
- * More detailed description of these properties can be found
- * in the documentation.
- */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- /* Line number range for function. Needed during debugging to
- * determine active breakpoints.
- */
- duk_uint32_t start_line;
- duk_uint32_t end_line;
-#endif
-};
-
-#endif /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */
-#line 1 "duk_hnativefunction.h"
-/*
- * Heap native function representation.
- */
-
-#ifndef DUK_HNATIVEFUNCTION_H_INCLUDED
-#define DUK_HNATIVEFUNCTION_H_INCLUDED
-
-#define DUK_HNATIVEFUNCTION_NARGS_VARARGS ((duk_int16_t) -1)
-#define DUK_HNATIVEFUNCTION_NARGS_MAX ((duk_int16_t) 0x7fff)
-
-struct duk_hnativefunction {
- /* shared object part */
- duk_hobject obj;
-
- duk_c_function func;
- duk_int16_t nargs;
- duk_int16_t magic;
-
- /* The 'magic' field allows an opaque 16-bit field to be accessed by the
- * Duktape/C function. This allows, for instance, the same native function
- * to be used for a set of very similar functions, with the 'magic' field
- * providing the necessary non-argument flags / values to guide the behavior
- * of the native function. The value is signed on purpose: it is easier to
- * convert a signed value to unsigned (simply AND with 0xffff) than vice
- * versa.
- *
- * Note: cannot place nargs/magic into the heaphdr flags, because
- * duk_hobject takes almost all flags already (and needs the spare).
- */
-};
-
-#endif /* DUK_HNATIVEFUNCTION_H_INCLUDED */
-#line 1 "duk_hbufferobject.h"
-/*
- * Heap Buffer object representation. Used for all Buffer variants.
- */
-
-#ifndef DUK_HBUFFEROBJECT_H_INCLUDED
-#define DUK_HBUFFEROBJECT_H_INCLUDED
-
-/* All element accessors are host endian now (driven by TypedArray spec). */
-#define DUK_HBUFFEROBJECT_ELEM_UINT8 0
-#define DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED 1
-#define DUK_HBUFFEROBJECT_ELEM_INT8 2
-#define DUK_HBUFFEROBJECT_ELEM_UINT16 3
-#define DUK_HBUFFEROBJECT_ELEM_INT16 4
-#define DUK_HBUFFEROBJECT_ELEM_UINT32 5
-#define DUK_HBUFFEROBJECT_ELEM_INT32 6
-#define DUK_HBUFFEROBJECT_ELEM_FLOAT32 7
-#define DUK_HBUFFEROBJECT_ELEM_FLOAT64 8
-#define DUK_HBUFFEROBJECT_ELEM_MAX 8
-
-#define DUK_ASSERT_HBUFFEROBJECT_VALID(h) do { \
- DUK_ASSERT((h) != NULL); \
- DUK_ASSERT((h)->shift <= 3); \
- DUK_ASSERT((h)->elem_type <= DUK_HBUFFEROBJECT_ELEM_MAX); \
- DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8) || \
- ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) || \
- ((h)->shift == 0 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT8) || \
- ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT16) || \
- ((h)->shift == 1 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT16) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT32) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_INT32) || \
- ((h)->shift == 2 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT32) || \
- ((h)->shift == 3 && (h)->elem_type == DUK_HBUFFEROBJECT_ELEM_FLOAT64)); \
- DUK_ASSERT((h)->is_view == 0 || (h)->is_view == 1); \
- DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) (h))); \
- if ((h)->buf == NULL) { \
- DUK_ASSERT((h)->offset == 0); \
- DUK_ASSERT((h)->length == 0); \
- } else { \
- /* No assertions for offset or length; in particular, \
- * it's OK for length to be longer than underlying \
- * buffer. Just ensure they don't wrap when added. \
- */ \
- DUK_ASSERT((h)->offset + (h)->length >= (h)->offset); \
- } \
- } while (0)
-
-/* Get the current data pointer (caller must ensure buf != NULL) as a
- * duk_uint8_t ptr.
- */
-#define DUK_HBUFFEROBJECT_GET_SLICE_BASE(heap,h) \
- (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
- (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
-
-/* True if slice is full, i.e. offset is zero and length covers the entire
- * buffer. This status may change independently of the duk_hbufferobject if
- * the underlying buffer is dynamic and changes without the hbufferobject
- * being changed.
- */
-#define DUK_HBUFFEROBJECT_FULL_SLICE(h) \
- (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
- ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
-
-/* Validate that the whole slice [0,length[ is contained in the underlying
- * buffer. Caller must ensure 'buf' != NULL.
- */
-#define DUK_HBUFFEROBJECT_VALID_SLICE(h) \
- (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
- ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
-
-/* Validate byte read/write for virtual 'offset', i.e. check that the
- * offset, taking into account h->offset, is within the underlying
- * buffer size. This is a safety check which is needed to ensure
- * that even a misconfigured duk_hbufferobject never causes memory
- * unsafe behavior (e.g. if an underlying dynamic buffer changes
- * after being setup). Caller must ensure 'buf' != NULL.
- */
-#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_INCL(h,off) \
- (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
- ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
-
-#define DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h,off) \
- (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
- ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
-
-/* Clamp an input byte length (already assumed to be within the nominal
- * duk_hbufferobject 'length') to the current dynamic buffer limits to
- * yield a byte length limit that's safe for memory accesses. This value
- * can be invalidated by any side effect because it may trigger a user
- * callback that resizes the underlying buffer.
- */
-#define DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h,len) \
- (DUK_ASSERT_EXPR((h) != NULL), \
- duk_hbufferobject_clamp_bytelength((h), (len)))
-
-struct duk_hbufferobject {
- /* Shared object part. */
- duk_hobject obj;
-
- /* Underlying buffer (refcounted), may be NULL. */
- duk_hbuffer *buf;
-
- /* Slice and accessor information.
- *
- * Because the underlying buffer may be dynamic, these may be
- * invalidated by the buffer being modified so that both offset
- * and length should be validated before every access. Behavior
- * when the underlying buffer has changed doesn't need to be clean:
- * virtual 'length' doesn't need to be affected, reads can return
- * zero/NaN, and writes can be ignored.
- *
- * Note that a data pointer cannot be precomputed because 'buf' may
- * be dynamic and its pointer unstable.
- */
-
- duk_uint_t offset; /* byte offset to buf */
- duk_uint_t length; /* byte index limit for element access, exclusive */
- duk_uint8_t shift; /* element size shift:
- * 0 = u8/i8
- * 1 = u16/i16
- * 2 = u32/i32/float
- * 3 = double
- */
- duk_uint8_t elem_type; /* element type */
- duk_uint8_t is_view;
-};
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL_DECL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len);
-#endif
-DUK_INTERNAL_DECL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
-DUK_INTERNAL_DECL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
-
-#endif /* DUK_HBUFFEROBJECT_H_INCLUDED */
-#line 1 "duk_hthread.h"
-/*
- * Heap thread object representation.
- *
- * duk_hthread is also the 'context' (duk_context) for exposed APIs
- * which mostly operate on the topmost frame of the value stack.
- */
-
-#ifndef DUK_HTHREAD_H_INCLUDED
-#define DUK_HTHREAD_H_INCLUDED
-
-/*
- * Stack constants
- */
-
-#define DUK_VALSTACK_GROW_STEP 128 /* roughly 1 kiB */
-#define DUK_VALSTACK_SHRINK_THRESHOLD 256 /* roughly 2 kiB */
-#define DUK_VALSTACK_SHRINK_SPARE 64 /* roughly 0.5 kiB */
-#define DUK_VALSTACK_INITIAL_SIZE 128 /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */
-#define DUK_VALSTACK_INTERNAL_EXTRA 64 /* internal extra elements assumed on function entry,
- * always added to user-defined 'extra' for e.g. the
- * duk_check_stack() call.
- */
-#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
- /* number of elements guaranteed to be user accessible
- * (in addition to call arguments) on Duktape/C function entry.
- */
-
-/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM
- * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare
- * requirements.
- */
-
-#define DUK_VALSTACK_DEFAULT_MAX 1000000L
-
-#define DUK_CALLSTACK_GROW_STEP 8 /* roughly 256 bytes */
-#define DUK_CALLSTACK_SHRINK_THRESHOLD 16 /* roughly 512 bytes */
-#define DUK_CALLSTACK_SHRINK_SPARE 8 /* roughly 256 bytes */
-#define DUK_CALLSTACK_INITIAL_SIZE 8
-#define DUK_CALLSTACK_DEFAULT_MAX 10000L
-
-#define DUK_CATCHSTACK_GROW_STEP 4 /* roughly 64 bytes */
-#define DUK_CATCHSTACK_SHRINK_THRESHOLD 8 /* roughly 128 bytes */
-#define DUK_CATCHSTACK_SHRINK_SPARE 4 /* roughly 64 bytes */
-#define DUK_CATCHSTACK_INITIAL_SIZE 4
-#define DUK_CATCHSTACK_DEFAULT_MAX 10000L
-
-/*
- * Activation defines
- */
-
-#define DUK_ACT_FLAG_STRICT (1 << 0) /* function executes in strict mode */
-#define DUK_ACT_FLAG_TAILCALLED (1 << 1) /* activation has tail called one or more times */
-#define DUK_ACT_FLAG_CONSTRUCT (1 << 2) /* function executes as a constructor (called via "new") */
-#define DUK_ACT_FLAG_PREVENT_YIELD (1 << 3) /* activation prevents yield (native call or "new") */
-#define DUK_ACT_FLAG_DIRECT_EVAL (1 << 4) /* activation is a direct eval call */
-#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1 << 5) /* activation has active breakpoint(s) */
-
-#define DUK_ACT_GET_FUNC(act) ((act)->func)
-
-/*
- * Flags for __FILE__ / __LINE__ registered into tracedata
- */
-
-#define DUK_TB_FLAG_NOBLAME_FILELINE (1 << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
-
-/*
- * Catcher defines
- */
-
-/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
-#define DUK_CAT_TYPE_MASK 0x0000000fUL
-#define DUK_CAT_TYPE_BITS 4
-#define DUK_CAT_LABEL_MASK 0xffffff00UL
-#define DUK_CAT_LABEL_BITS 24
-#define DUK_CAT_LABEL_SHIFT 8
-
-#define DUK_CAT_FLAG_CATCH_ENABLED (1 << 4) /* catch part will catch */
-#define DUK_CAT_FLAG_FINALLY_ENABLED (1 << 5) /* finally part will catch */
-#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1 << 6) /* request to create catch binding */
-#define DUK_CAT_FLAG_LEXENV_ACTIVE (1 << 7) /* catch or with binding is currently active */
-
-#define DUK_CAT_TYPE_UNKNOWN 0
-#define DUK_CAT_TYPE_TCF 1
-#define DUK_CAT_TYPE_LABEL 2
-
-#define DUK_CAT_GET_TYPE(c) ((c)->flags & DUK_CAT_TYPE_MASK)
-#define DUK_CAT_GET_LABEL(c) (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT)
-
-#define DUK_CAT_HAS_CATCH_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED)
-#define DUK_CAT_HAS_FINALLY_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED)
-#define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED)
-#define DUK_CAT_HAS_LEXENV_ACTIVE(c) ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE)
-
-#define DUK_CAT_SET_CATCH_ENABLED(c) do { \
- (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \
- } while (0)
-#define DUK_CAT_SET_FINALLY_ENABLED(c) do { \
- (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \
- } while (0)
-#define DUK_CAT_SET_CATCH_BINDING_ENABLED(c) do { \
- (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
- } while (0)
-#define DUK_CAT_SET_LEXENV_ACTIVE(c) do { \
- (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \
- } while (0)
-
-#define DUK_CAT_CLEAR_CATCH_ENABLED(c) do { \
- (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \
- } while (0)
-#define DUK_CAT_CLEAR_FINALLY_ENABLED(c) do { \
- (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \
- } while (0)
-#define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c) do { \
- (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
- } while (0)
-#define DUK_CAT_CLEAR_LEXENV_ACTIVE(c) do { \
- (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \
- } while (0)
-
-/*
- * Thread defines
- */
-
-#if defined(DUK_USE_ROM_STRINGS)
-#define DUK_HTHREAD_GET_STRING(thr,idx) \
- ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
-#else /* DUK_USE_ROM_STRINGS */
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HTHREAD_GET_STRING(thr,idx) \
- ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)]))
-#else
-#define DUK_HTHREAD_GET_STRING(thr,idx) \
- ((thr)->strs[(idx)])
-#endif
-#endif /* DUK_USE_ROM_STRINGS */
-
-#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1])
-
-/* values for the state field */
-#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */
-#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */
-#define DUK_HTHREAD_STATE_RESUMED 3 /* thread resumed another thread (active but not running) */
-#define DUK_HTHREAD_STATE_YIELDED 4 /* thread has yielded */
-#define DUK_HTHREAD_STATE_TERMINATED 5 /* thread has terminated */
-
-/* Executor interrupt default interval when nothing else requires a
- * smaller value. The default interval must be small enough to allow
- * for reasonable execution timeout checking but large enough to keep
- * impact on execution performance low.
- */
-#if defined(DUK_USE_INTERRUPT_COUNTER)
-#define DUK_HTHREAD_INTCTR_DEFAULT (256L * 1024L)
-#endif
-
-/*
- * Assert context is valid: non-NULL pointer, fields look sane.
- *
- * This is used by public API call entrypoints to catch invalid 'ctx' pointers
- * as early as possible; invalid 'ctx' pointers cause very odd and difficult to
- * diagnose behavior so it's worth checking even when the check is not 100%.
- */
-
-#if defined(DUK_USE_PREFER_SIZE)
-#define DUK_ASSERT_CTX_VSSIZE(ctx) /*nop*/
-#else
-#define DUK_ASSERT_CTX_VSSIZE(ctx) \
- DUK_ASSERT((duk_size_t) (((duk_hthread *) (ctx))->valstack_end - ((duk_hthread *) (ctx))->valstack) == \
- ((duk_hthread *) (ctx))->valstack_size)
-#endif
-#define DUK_ASSERT_CTX_VALID(ctx) do { \
- DUK_ASSERT((ctx) != NULL); \
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (ctx)) == DUK_HTYPE_OBJECT); \
- DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (ctx))); \
- DUK_ASSERT(((duk_hthread *) (ctx))->unused1 == 0); \
- DUK_ASSERT(((duk_hthread *) (ctx))->unused2 == 0); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack != NULL); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack_bottom); \
- DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack_top); \
- DUK_ASSERT_CTX_VSSIZE((ctx)); \
- } while (0)
-
-/*
- * Struct defines
- */
-
-/* XXX: for a memory-code tradeoff, remove 'func' and make it's access either a function
- * or a macro. This would make the activation 32 bytes long on 32-bit platforms again.
- */
-
-/* Note: it's nice if size is 2^N (at least for 32-bit platforms). */
-struct duk_activation {
- duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */
- duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
- duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */
- duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- /* Previous value of 'func' caller, restored when unwound. Only in use
- * when 'func' is non-strict.
- */
- duk_hobject *prev_caller;
-#endif
-
- duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_uint32_t prev_line; /* needed for stepping */
-#endif
- duk_small_uint_t flags;
-
- /* idx_bottom and idx_retval are only used for book-keeping of
- * Ecmascript-initiated calls, to allow returning to an Ecmascript
- * function properly. They are duk_size_t to match the convention
- * that value stack sizes are duk_size_t and local frame indices
- * are duk_idx_t.
- */
-
- /* Bottom of valstack for this activation, used to reset
- * valstack_bottom on return; index is absolute. Note:
- * idx_top not needed because top is set to 'nregs' always
- * when returning to an Ecmascript activation.
- */
- duk_size_t idx_bottom;
-
- /* Return value when returning to this activation (points to caller
- * reg, not callee reg); index is absolute (only set if activation is
- * not topmost).
- *
- * Note: idx_bottom is always set, while idx_retval is only applicable
- * for activations below the topmost one. Currently idx_retval for
- * the topmost activation is considered garbage (and it not initialized
- * on entry or cleared on return; may contain previous or garbage
- * values).
- */
- duk_size_t idx_retval;
-
- /* Current 'this' binding is the value just below idx_bottom.
- * Previously, 'this' binding was handled with an index to the
- * (calling) valstack. This works for everything except tail
- * calls, which must not "cumulate" valstack temps.
- */
-};
-
-/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */
-struct duk_catcher {
- duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */
- /* (reference is valid as long activation exists) */
- duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
- duk_size_t callstack_index; /* callstack index of related activation */
- duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */
- duk_uint32_t flags; /* type and control flags, label number */
-};
-
-struct duk_hthread {
- /* Shared object part */
- duk_hobject obj;
-
- /* Pointer to bytecode executor's 'curr_pc' variable. Used to copy
- * the current PC back into the topmost activation when activation
- * state is about to change (or "syncing" is otherwise needed). This
- * is rather awkward but important for performance, see execution.rst.
- */
- duk_instr_t **ptr_curr_pc;
-
- /* Backpointers. */
- duk_heap *heap;
-
- /* Current strictness flag: affects API calls. */
- duk_uint8_t strict;
-
- /* Thread state. */
- duk_uint8_t state;
- duk_uint8_t unused1;
- duk_uint8_t unused2;
-
- /* Sanity limits for stack sizes. */
- duk_size_t valstack_max;
- duk_size_t callstack_max;
- duk_size_t catchstack_max;
-
- /* XXX: Valstack, callstack, and catchstack are currently assumed
- * to have non-NULL pointers. Relaxing this would not lead to big
- * benefits (except perhaps for terminated threads).
- */
-
- /* Value stack: these are expressed as pointers for faster stack manipulation.
- * [valstack,valstack_top[ is GC-reachable, [valstack_top,valstack_end[ is
- * not GC-reachable but kept initialized as 'undefined'.
- */
- duk_tval *valstack; /* start of valstack allocation */
- duk_tval *valstack_end; /* end of valstack allocation (exclusive) */
- duk_tval *valstack_bottom; /* bottom of current frame */
- duk_tval *valstack_top; /* top of current frame (exclusive) */
-#if !defined(DUK_USE_PREFER_SIZE)
- duk_size_t valstack_size; /* cached: valstack_end - valstack (in entries, not bytes) */
-#endif
-
- /* Call stack. [0,callstack_top[ is GC reachable. */
- duk_activation *callstack;
- duk_size_t callstack_size; /* allocation size */
- duk_size_t callstack_top; /* next to use, highest used is top - 1 */
- duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */
-
- /* Catch stack. [0,catchstack_top[ is GC reachable. */
- duk_catcher *catchstack;
- duk_size_t catchstack_size; /* allocation size */
- duk_size_t catchstack_top; /* next to use, highest used is top - 1 */
-
- /* Yield/resume book-keeping. */
- duk_hthread *resumer; /* who resumed us (if any) */
-
- /* Current compiler state (if any), used for augmenting SyntaxErrors. */
- duk_compiler_ctx *compile_ctx;
-
-#if defined(DUK_USE_INTERRUPT_COUNTER)
- /* Interrupt counter for triggering a slow path check for execution
- * timeout, debugger interaction such as breakpoints, etc. The value
- * is valid for the current running thread, and both the init and
- * counter values are copied whenever a thread switch occurs. It's
- * important for the counter to be conveniently accessible for the
- * bytecode executor inner loop for performance reasons.
- */
- duk_int_t interrupt_counter; /* countdown state */
- duk_int_t interrupt_init; /* start value for current countdown */
-#endif
-
- /* Builtin-objects; may or may not be shared with other threads,
- * threads existing in different "compartments" will have different
- * built-ins. Must be stored on a per-thread basis because there
- * is no intermediate structure for a thread group / compartment.
- * This takes quite a lot of space, currently 43x4 = 172 bytes on
- * 32-bit platforms.
- *
- * In some cases the builtins array could be ROM based, but it's
- * sometimes edited (e.g. for sandboxing) so it's better to keep
- * this array in RAM.
- */
- duk_hobject *builtins[DUK_NUM_BUILTINS];
-
- /* Convenience copies from heap/vm for faster access. */
-#if defined(DUK_USE_ROM_STRINGS)
- /* No field needed when strings are in ROM. */
-#else
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *strs16;
-#else
- duk_hstring **strs;
-#endif
-#endif
-};
-
-/*
- * Prototypes
- */
-
-DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to);
-DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
-DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
-
-DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top);
-
-DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr);
-DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
-#endif
-DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act);
-DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
-
-#endif /* DUK_HTHREAD_H_INCLUDED */
-#line 1 "duk_hbuffer.h"
-/*
- * Heap buffer representation.
- *
- * Heap allocated user data buffer which is either:
- *
- * 1. A fixed size buffer (data follows header statically)
- * 2. A dynamic size buffer (data pointer follows header)
- *
- * The data pointer for a variable size buffer of zero size may be NULL.
- */
-
-#ifndef DUK_HBUFFER_H_INCLUDED
-#define DUK_HBUFFER_H_INCLUDED
-
-/*
- * Flags
- *
- * Fixed buffer: 0
- * Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC
- * External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL
- */
-
-#define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */
-#define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */
-
-#define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
-#define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
-
-#define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
-#define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
-
-#define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
-#define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
-
-/*
- * Misc defines
- */
-
-/* Impose a maximum buffer length for now. Restricted artificially to
- * ensure resize computations or adding a heap header length won't
- * overflow size_t and that a signed duk_int_t can hold a buffer
- * length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN.
- */
-
-#if defined(DUK_USE_BUFLEN16)
-#define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL)
-#else
-/* Intentionally not 0x7fffffffUL; at least JSON code expects that
- * 2*len + 2 fits in 32 bits.
- */
-#define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL)
-#endif
-
-/*
- * Field access
- */
-
-/* Get/set the current user visible size, without accounting for a dynamic
- * buffer's "spare" (= usable size).
- */
-#if defined(DUK_USE_BUFLEN16)
-/* size stored in duk_heaphdr unused flag bits */
-#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
-#define DUK_HBUFFER_SET_SIZE(x,v) do { \
- duk_size_t duk__v; \
- duk__v = (v); \
- DUK_ASSERT(duk__v <= 0xffffUL); \
- (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \
- } while (0)
-#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
- (x)->hdr.h_flags += ((dv) << 16); \
- } while (0)
-#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
- (x)->hdr.h_flags -= ((dv) << 16); \
- } while (0)
-#else
-#define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size)
-#define DUK_HBUFFER_SET_SIZE(x,v) do { \
- ((duk_hbuffer *) (x))->size = (v); \
- } while (0)
-#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
- (x)->size += (dv); \
- } while (0)
-#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
- (x)->size -= (dv); \
- } while (0)
-#endif
-
-#define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
-#define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x))
-
-#define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
-#define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
-#define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv))
-#define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv))
-
-#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
-#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
-
-#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1))
-
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \
- ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16))
-#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
- ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
- } while (0)
-#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
- ((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \
- } while (0)
-#else
-#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc)
-#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
- (x)->curr_alloc = (void *) (v); \
- } while (0)
-#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
- (x)->curr_alloc = (void *) NULL; \
- } while (0)
-#endif
-
-/* No pointer compression because pointer is potentially outside of
- * Duktape heap.
- */
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
- ((void *) (x)->curr_alloc)
-#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
- (x)->curr_alloc = (void *) (v); \
- } while (0)
-#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
- (x)->curr_alloc = (void *) NULL; \
- } while (0)
-#else
-#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
- ((void *) (x)->curr_alloc)
-#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
- (x)->curr_alloc = (void *) (v); \
- } while (0)
-#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
- (x)->curr_alloc = (void *) NULL; \
- } while (0)
-#endif
-
-/* Get a pointer to the current buffer contents (matching current allocation
- * size). May be NULL for zero size dynamic/external buffer.
- */
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
- DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
- ( \
- DUK_HBUFFER_HAS_EXTERNAL((x)) ? \
- DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \
- DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \
- ) : \
- DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
- )
-#else
-/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external
- * have the same layout so checking for fixed vs. dynamic (or external) is enough.
- */
-#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
- DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
- DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \
- DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
- )
-#endif
-
-/*
- * Structs
- */
-
-/* Shared prefix for all buffer types. */
-struct duk_hbuffer {
- duk_heaphdr hdr;
-
- /* It's not strictly necessary to track the current size, but
- * it is useful for writing robust native code.
- */
-
- /* Current size (not counting a dynamic buffer's "spare"). */
-#if defined(DUK_USE_BUFLEN16)
- /* Stored in duk_heaphdr unused flags. */
-#else
- duk_size_t size;
-#endif
-
- /*
- * Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC
- * flag.
- *
- * If the flag is clear (the buffer is a fixed size one), the buffer
- * data follows the header directly, consisting of 'size' bytes.
- *
- * If the flag is set, the actual buffer is allocated separately, and
- * a few control fields follow the header. Specifically:
- *
- * - a "void *" pointing to the current allocation
- * - a duk_size_t indicating the full allocated size (always >= 'size')
- *
- * If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated
- * by user code, so that Duktape won't be able to resize it and won't
- * free it. This allows buffers to point to e.g. an externally
- * allocated structure such as a frame buffer.
- *
- * Unlike strings, no terminator byte (NUL) is guaranteed after the
- * data. This would be convenient, but would pad aligned user buffers
- * unnecessarily upwards in size. For instance, if user code requested
- * a 64-byte dynamic buffer, 65 bytes would actually be allocated which
- * would then potentially round upwards to perhaps 68 or 72 bytes.
- */
-};
-
-/* Fixed buffer; data follows struct, with proper alignment guaranteed by
- * struct size.
- */
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
-#pragma pack(push, 8)
-#endif
-struct duk_hbuffer_fixed {
- /* A union is used here as a portable struct size / alignment trick:
- * by adding a 32-bit or a 64-bit (unused) union member, the size of
- * the struct is effectively forced to be a multiple of 4 or 8 bytes
- * (respectively) without increasing the size of the struct unless
- * necessary.
- */
- union {
- struct {
- duk_heaphdr hdr;
-#if defined(DUK_USE_BUFLEN16)
- /* Stored in duk_heaphdr unused flags. */
-#else
- duk_size_t size;
-#endif
- } s;
-#if (DUK_USE_ALIGN_BY == 4)
- duk_uint32_t dummy_for_align4;
-#elif (DUK_USE_ALIGN_BY == 8)
- duk_double_t dummy_for_align8;
-#elif (DUK_USE_ALIGN_BY == 1)
- /* no extra padding */
-#else
-#error invalid DUK_USE_ALIGN_BY
-#endif
- } u;
-
- /*
- * Data follows the struct header. The struct size is padded by the
- * compiler based on the struct members. This guarantees that the
- * buffer data will be aligned-by-4 but not necessarily aligned-by-8.
- *
- * On platforms where alignment does not matter, the struct padding
- * could be removed (if there is any). On platforms where alignment
- * by 8 is required, the struct size must be forced to be a multiple
- * of 8 by some means. Without it, some user code may break, and also
- * Duktape itself breaks (e.g. the compiler stores duk_tvals in a
- * dynamic buffer).
- */
-}
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
-__attribute__ ((aligned (8)))
-#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
-__attribute__ ((aligned (8)))
-#endif
-;
-#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
-#pragma pack(pop)
-#endif
-
-/* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using
- * heap allocation primitives. Also used for external buffers when low memory
- * options are not used.
- */
-struct duk_hbuffer_dynamic {
- duk_heaphdr hdr;
-
-#if defined(DUK_USE_BUFLEN16)
- /* Stored in duk_heaphdr unused flags. */
-#else
- duk_size_t size;
-#endif
-
-#if defined(DUK_USE_HEAPPTR16)
- /* Stored in duk_heaphdr h_extra16. */
-#else
- void *curr_alloc; /* may be NULL if alloc_size == 0 */
-#endif
-
- /*
- * Allocation size for 'curr_alloc' is alloc_size. There is no
- * automatic NUL terminator for buffers (see above for rationale).
- *
- * 'curr_alloc' is explicitly allocated with heap allocation
- * primitives and will thus always have alignment suitable for
- * e.g. duk_tval and an IEEE double.
- */
-};
-
-/* External buffer with 'curr_alloc' managed by user code and pointing to an
- * arbitrary address. When heap pointer compression is not used, this struct
- * has the same layout as duk_hbuffer_dynamic.
- */
-struct duk_hbuffer_external {
- duk_heaphdr hdr;
-
-#if defined(DUK_USE_BUFLEN16)
- /* Stored in duk_heaphdr unused flags. */
-#else
- duk_size_t size;
-#endif
-
- /* Cannot be compressed as a heap pointer because may point to
- * an arbitrary address.
- */
- void *curr_alloc; /* may be NULL if alloc_size == 0 */
-};
-
-/*
- * Prototypes
- */
-
-DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata);
-DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */
-
-/* dynamic buffer ops */
-DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size);
-DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
-
-#endif /* DUK_HBUFFER_H_INCLUDED */
-#line 1 "duk_heap.h"
-/*
- * Heap structure.
- *
- * Heap contains allocated heap objects, interned strings, and built-in
- * strings for one or more threads.
- */
-
-#ifndef DUK_HEAP_H_INCLUDED
-#define DUK_HEAP_H_INCLUDED
-
-/* alloc function typedefs in duktape.h */
-
-/*
- * Heap flags
- */
-
-#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */
-#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
-#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */
-#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */
-#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */
-#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */
-
-#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
-#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
- (heap)->flags |= (bits); \
- } while (0)
-#define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \
- (heap)->flags &= ~(bits); \
- } while (0)
-
-#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
-#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
-#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
-#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
-
-#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
-#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
-#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
-#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
-
-#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
-#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
-#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
-#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
-#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
-#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
-
-/*
- * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
- */
-
-#define DUK_LJ_TYPE_UNKNOWN 0 /* unused */
-#define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */
-#define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */
-#define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */
-#define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */
-#define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */
-#define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */
-#define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */
-
-/*
- * Mark-and-sweep flags
- *
- * These are separate from heap level flags now but could be merged.
- * The heap structure only contains a 'base mark-and-sweep flags'
- * field and the GC caller can impose further flags.
- */
-
-#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */
-#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */
-#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */
-#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */
-#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */
-
-/*
- * Thread switching
- *
- * To switch heap->curr_thread, use the macro below so that interrupt counters
- * get updated correctly. The macro allows a NULL target thread because that
- * happens e.g. in call handling.
- */
-
-#if defined(DUK_USE_INTERRUPT_COUNTER)
-#define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr))
-#else
-#define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \
- (heap)->curr_thread = (newthr); \
- } while (0)
-#endif
-
-/*
- * Other heap related defines
- */
-
-/* Mark-and-sweep interval is relative to combined count of objects and
- * strings kept in the heap during the latest mark-and-sweep pass.
- * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is
- * decreased by each (re)allocation attempt (regardless of size), and each
- * refzero processed object.
- *
- * 'SKIP' indicates how many (re)allocations to wait until a retry if
- * GC is skipped because there is no thread do it with yet (happens
- * only during init phases).
- */
-#if defined(DUK_USE_MARK_AND_SWEEP)
-#if defined(DUK_USE_REFERENCE_COUNTING)
-#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */
-#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
-#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
-#else
-#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */
-#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
-#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
-#endif
-#endif
-
-/* Stringcache is used for speeding up char-offset-to-byte-offset
- * translations for non-ASCII strings.
- */
-#define DUK_HEAP_STRCACHE_SIZE 4
-#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */
-
-/* helper to insert a (non-string) heap object into heap allocated list */
-#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr))
-
-/*
- * Stringtable
- */
-
-/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */
-#define DUK_STRTAB_INITIAL_SIZE 17
-
-/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */
-#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap)
-
-/* resizing parameters */
-#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */
-#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */
-#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */
-
-#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */
-#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL
-
-/* probe sequence (open addressing) */
-#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
-#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
-
-/* fixed top level hashtable size (separate chaining) */
-#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE
-
-/*
- * Built-in strings
- */
-
-/* heap string indices are autogenerated in duk_strings.h */
-#if defined(DUK_USE_ROM_STRINGS)
-#define DUK_HEAP_GET_STRING(heap,idx) \
- ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
-#else /* DUK_USE_ROM_STRINGS */
-#if defined(DUK_USE_HEAPPTR16)
-#define DUK_HEAP_GET_STRING(heap,idx) \
- ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)]))
-#else
-#define DUK_HEAP_GET_STRING(heap,idx) \
- ((heap)->strs[(idx)])
-#endif
-#endif /* DUK_USE_ROM_STRINGS */
-
-/*
- * Raw memory calls: relative to heap, but no GC interaction
- */
-
-#define DUK_ALLOC_RAW(heap,size) \
- ((heap)->alloc_func((heap)->heap_udata, (size)))
-
-#define DUK_REALLOC_RAW(heap,ptr,newsize) \
- ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize)))
-
-#define DUK_FREE_RAW(heap,ptr) \
- ((heap)->free_func((heap)->heap_udata, (void *) (ptr)))
-
-/*
- * Memory calls: relative to heap, GC interaction, but no error throwing.
- *
- * XXX: Currently a mark-and-sweep triggered by memory allocation will run
- * using the heap->heap_thread. This thread is also used for running
- * mark-and-sweep finalization; this is not ideal because it breaks the
- * isolation between multiple global environments.
- *
- * Notes:
- *
- * - DUK_FREE() is required to ignore NULL and any other possible return
- * value of a zero-sized alloc/realloc (same as ANSI C free()).
- *
- * - There is no DUK_REALLOC_ZEROED because we don't assume to know the
- * old size. Caller must zero the reallocated memory.
- *
- * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered
- * by an allocation failure might invalidate the original 'ptr', thus
- * causing a realloc retry to use an invalid pointer. Example: we're
- * reallocating the value stack and a finalizer resizes the same value
- * stack during mark-and-sweep. The indirect variant requests for the
- * current location of the pointer being reallocated using a callback
- * right before every realloc attempt; this circuitous approach is used
- * to avoid strict aliasing issues in a more straightforward indirect
- * pointer (void **) approach. Note: the pointer in the storage
- * location is read but is NOT updated; the caller must do that.
- */
-
-/* callback for indirect reallocs, request for current pointer */
-typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
-
-#define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size))
-#define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size))
-#define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize))
-#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
-#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr))
-
-/*
- * Memory constants
- */
-
-#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this
- * many times. A single mark-and-sweep round is
- * not guaranteed to free all unreferenced memory
- * because of finalization (in fact, ANY number of
- * rounds is strictly not enough).
- */
-
-#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode
- * for mark-and-sweep.
- */
-
-/*
- * Debugger support
- */
-
-/* Maximum number of breakpoints. Only breakpoints that are set are
- * consulted so increasing this has no performance impact.
- */
-#define DUK_HEAP_MAX_BREAKPOINTS 16
-
-/* Opcode interval for a Date-based status/peek rate limit check. Only
- * relevant when debugger is attached. Requesting a timestamp may be a
- * slow operation on some platforms so this shouldn't be too low. On the
- * other hand a high value makes Duktape react to a pause request slowly.
- */
-#define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000
-
-/* Milliseconds between status notify and transport peeks. */
-#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
-
-/* Step types */
-#define DUK_STEP_TYPE_NONE 0
-#define DUK_STEP_TYPE_INTO 1
-#define DUK_STEP_TYPE_OVER 2
-#define DUK_STEP_TYPE_OUT 3
-
-struct duk_breakpoint {
- duk_hstring *filename;
- duk_uint32_t line;
-};
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL)
-#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \
- (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \
- (heap)->dbg_step_thread = NULL; \
- (heap)->dbg_step_csindex = 0; \
- (heap)->dbg_step_startline = 0; \
- } while (0)
-#define DUK_HEAP_SET_PAUSED(heap) do { \
- (heap)->dbg_paused = 1; \
- (heap)->dbg_state_dirty = 1; \
- DUK_HEAP_CLEAR_STEP_STATE((heap)); \
- } while (0)
-#define DUK_HEAP_CLEAR_PAUSED(heap) do { \
- (heap)->dbg_paused = 0; \
- (heap)->dbg_state_dirty = 1; \
- DUK_HEAP_CLEAR_STEP_STATE((heap)); \
- } while (0)
-#define DUK_HEAP_IS_PAUSED(heap) ((heap)->dbg_paused)
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
-/*
- * String cache should ideally be at duk_hthread level, but that would
- * cause string finalization to slow down relative to the number of
- * threads; string finalization must check the string cache for "weak"
- * references to the string being finalized to avoid dead pointers.
- *
- * Thus, string caches are now at the heap level now.
- */
-
-struct duk_strcache {
- duk_hstring *h;
- duk_uint32_t bidx;
- duk_uint32_t cidx;
-};
-
-/*
- * Longjmp state, contains the information needed to perform a longjmp.
- * Longjmp related values are written to value1, value2, and iserror.
- */
-
-struct duk_ljstate {
- duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
- duk_small_uint_t type; /* longjmp type */
- duk_bool_t iserror; /* isError flag for yield */
- duk_tval value1; /* 1st related value (type specific) */
- duk_tval value2; /* 2nd related value (type specific) */
-};
-
-/*
- * Stringtable entry for fixed size stringtable
- */
-
-struct duk_strtab_entry {
-#if defined(DUK_USE_HEAPPTR16)
- /* A 16-bit listlen makes sense with 16-bit heap pointers: there
- * won't be space for 64k strings anyway.
- */
- duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */
- union {
- duk_uint16_t strlist16;
- duk_uint16_t str16;
- } u;
-#else
- duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */
- union {
- duk_hstring **strlist;
- duk_hstring *str;
- } u;
-#endif
-};
-
-/*
- * Main heap structure
- */
-
-struct duk_heap {
- duk_small_uint_t flags;
-
- /* Allocator functions. */
- duk_alloc_function alloc_func;
- duk_realloc_function realloc_func;
- duk_free_function free_func;
-
- /* Heap udata, used for allocator functions but also for other heap
- * level callbacks like pointer compression, etc.
- */
- void *heap_udata;
-
- /* Precomputed pointers when using 16-bit heap pointer packing. */
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t heapptr_null16;
- duk_uint16_t heapptr_deleted16;
-#endif
-
- /* Fatal error handling, called e.g. when a longjmp() is needed but
- * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not
- * declared as "noreturn" because doing that for typedefs is a bit
- * challenging portability-wise.
- */
- duk_fatal_function fatal_func;
-
- /* allocated heap objects */
- duk_heaphdr *heap_allocated;
-
- /* work list for objects whose refcounts are zero but which have not been
- * "finalized"; avoids recursive C calls when refcounts go to zero in a
- * chain of objects.
- */
-#if defined(DUK_USE_REFERENCE_COUNTING)
- duk_heaphdr *refzero_list;
- duk_heaphdr *refzero_list_tail;
-#endif
-
-#if defined(DUK_USE_MARK_AND_SWEEP)
- /* mark-and-sweep control */
-#if defined(DUK_USE_VOLUNTARY_GC)
- duk_int_t mark_and_sweep_trigger_counter;
-#endif
- duk_int_t mark_and_sweep_recursion_depth;
-
- /* mark-and-sweep flags automatically active (used for critical sections) */
- duk_small_uint_t mark_and_sweep_base_flags;
-
- /* work list for objects to be finalized (by mark-and-sweep) */
- duk_heaphdr *finalize_list;
-#endif
-
- /* longjmp state */
- duk_ljstate lj;
-
- /* marker for detecting internal "double faults", see duk_error_throw.c */
- duk_bool_t handling_error;
-
- /* heap thread, used internally and for finalization */
- duk_hthread *heap_thread;
-
- /* current thread */
- duk_hthread *curr_thread; /* currently running thread */
-
- /* heap level "stash" object (e.g., various reachability roots) */
- duk_hobject *heap_object;
-
- /* duk_handle_call / duk_handle_safe_call recursion depth limiting */
- duk_int_t call_recursion_depth;
- duk_int_t call_recursion_limit;
-
- /* mix-in value for computing string hashes; should be reasonably unpredictable */
- duk_uint32_t hash_seed;
-
- /* rnd_state for duk_util_tinyrandom.c */
- duk_uint32_t rnd_state;
-
- /* For manual debugging: instruction count based on executor and
- * interrupt counter book-keeping. Inspect debug logs to see how
- * they match up.
- */
-#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
- duk_int_t inst_count_exec;
- duk_int_t inst_count_interrupt;
-#endif
-
- /* debugger */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */
- duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */
- duk_debug_write_function dbg_write_cb; /* required */
- duk_debug_peek_function dbg_peek_cb;
- duk_debug_read_flush_function dbg_read_flush_cb;
- duk_debug_write_flush_function dbg_write_flush_cb;
- duk_debug_request_function dbg_request_cb;
- duk_debug_detached_function dbg_detached_cb;
- void *dbg_udata;
-
- /* debugger state, only relevant when attached */
- duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
- duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */
- duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
- duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
- duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
- duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */
- duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */
- duk_size_t dbg_step_csindex; /* callstack index */
- duk_uint32_t dbg_step_startline; /* starting line number */
- duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
- duk_small_uint_t dbg_breakpoint_count;
- duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
- /* XXX: make active breakpoints actual copies instead of pointers? */
-
- /* These are for rate limiting Status notifications and transport peeking. */
- duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
- duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
- duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
-
- /* Used to support single-byte stream lookahead. */
- duk_bool_t dbg_have_next_byte;
- duk_uint8_t dbg_next_byte;
-#endif
-
- /* string intern table (weak refs) */
-#if defined(DUK_USE_STRTAB_PROBE)
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *strtable16;
-#else
- duk_hstring **strtable;
-#endif
- duk_uint32_t st_size; /* alloc size in elements */
- duk_uint32_t st_used; /* used elements (includes DELETED) */
-#endif
-
- /* XXX: static alloc is OK until separate chaining stringtable
- * resizing is implemented.
- */
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE];
-#endif
-
- /* string access cache (codepoint offset -> byte offset) for fast string
- * character looping; 'weak' reference which needs special handling in GC.
- */
- duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
-
- /* built-in strings */
-#if defined(DUK_USE_ROM_STRINGS)
- /* No field needed when strings are in ROM. */
-#else
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS];
-#else
- duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
-#endif
-#endif
-};
-
-/*
- * Prototypes
- */
-
-DUK_INTERNAL_DECL
-duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
- duk_realloc_function realloc_func,
- duk_free_function free_func,
- void *heap_udata,
- duk_fatal_function fatal_func);
-DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
-DUK_INTERNAL_DECL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h);
-DUK_INTERNAL_DECL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h);
-DUK_INTERNAL_DECL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h);
-DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
-
-DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
-#endif
-#if defined(DUK_USE_INTERRUPT_COUNTER)
-DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
-#endif
-
-#if 0 /*unused*/
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
-#endif
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
-#if 0 /*unused*/
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val);
-#endif
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val);
-DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
-#if defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h);
-#endif
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
-DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap);
-#endif
-DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap);
-#if defined(DUK_USE_DEBUG)
-DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap);
-#endif
-
-
-DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
-DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
-
-#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
-DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size);
-DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize);
-DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
-#endif
-
-DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
-DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
-DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
-DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
-DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
-
-#ifdef DUK_USE_REFERENCE_COUNTING
-#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
-#endif
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_tval_incref_allownull(duk_tval *tv);
-#endif
-DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv);
-#endif
-#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
-#endif
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_heaphdr_incref_allownull(duk_heaphdr *h);
-#endif
-DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
-DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr);
-#else
-/* no refcounting */
-#endif
-
-#if defined(DUK_USE_MARK_AND_SWEEP)
-DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
-#endif
-
-DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
-
-#endif /* DUK_HEAP_H_INCLUDED */
-#line 1 "duk_debugger.h"
-#ifndef DUK_DEBUGGER_H_INCLUDED
-#define DUK_DEBUGGER_H_INCLUDED
-
-/* Debugger protocol version is defined in the public API header. */
-
-/* Initial bytes for markers. */
-#define DUK_DBG_IB_EOM 0x00
-#define DUK_DBG_IB_REQUEST 0x01
-#define DUK_DBG_IB_REPLY 0x02
-#define DUK_DBG_IB_ERROR 0x03
-#define DUK_DBG_IB_NOTIFY 0x04
-
-/* Other initial bytes. */
-#define DUK_DBG_IB_INT4 0x10
-#define DUK_DBG_IB_STR4 0x11
-#define DUK_DBG_IB_STR2 0x12
-#define DUK_DBG_IB_BUF4 0x13
-#define DUK_DBG_IB_BUF2 0x14
-#define DUK_DBG_IB_UNUSED 0x15
-#define DUK_DBG_IB_UNDEFINED 0x16
-#define DUK_DBG_IB_NULL 0x17
-#define DUK_DBG_IB_TRUE 0x18
-#define DUK_DBG_IB_FALSE 0x19
-#define DUK_DBG_IB_NUMBER 0x1a
-#define DUK_DBG_IB_OBJECT 0x1b
-#define DUK_DBG_IB_POINTER 0x1c
-#define DUK_DBG_IB_LIGHTFUNC 0x1d
-#define DUK_DBG_IB_HEAPPTR 0x1e
-/* The short string/integer initial bytes starting from 0x60 don't have
- * defines now.
- */
-
-/* Error codes. */
-#define DUK_DBG_ERR_UNKNOWN 0x00
-#define DUK_DBG_ERR_UNSUPPORTED 0x01
-#define DUK_DBG_ERR_TOOMANY 0x02
-#define DUK_DBG_ERR_NOTFOUND 0x03
-#define DUK_DBG_ERR_APPLICATION 0x04
-
-/* Commands and notifys initiated by Duktape. */
-#define DUK_DBG_CMD_STATUS 0x01
-#define DUK_DBG_CMD_PRINT 0x02
-#define DUK_DBG_CMD_ALERT 0x03
-#define DUK_DBG_CMD_LOG 0x04
-#define DUK_DBG_CMD_THROW 0x05
-#define DUK_DBG_CMD_DETACHING 0x06
-#define DUK_DBG_CMD_APPNOTIFY 0x07
-
-/* Commands initiated by debug client. */
-#define DUK_DBG_CMD_BASICINFO 0x10
-#define DUK_DBG_CMD_TRIGGERSTATUS 0x11
-#define DUK_DBG_CMD_PAUSE 0x12
-#define DUK_DBG_CMD_RESUME 0x13
-#define DUK_DBG_CMD_STEPINTO 0x14
-#define DUK_DBG_CMD_STEPOVER 0x15
-#define DUK_DBG_CMD_STEPOUT 0x16
-#define DUK_DBG_CMD_LISTBREAK 0x17
-#define DUK_DBG_CMD_ADDBREAK 0x18
-#define DUK_DBG_CMD_DELBREAK 0x19
-#define DUK_DBG_CMD_GETVAR 0x1a
-#define DUK_DBG_CMD_PUTVAR 0x1b
-#define DUK_DBG_CMD_GETCALLSTACK 0x1c
-#define DUK_DBG_CMD_GETLOCALS 0x1d
-#define DUK_DBG_CMD_EVAL 0x1e
-#define DUK_DBG_CMD_DETACH 0x1f
-#define DUK_DBG_CMD_DUMPHEAP 0x20
-#define DUK_DBG_CMD_GETBYTECODE 0x21
-#define DUK_DBG_CMD_APPREQUEST 0x22
-#define DUK_DBG_CMD_GETHEAPOBJINFO 0x23
-#define DUK_DBG_CMD_GETOBJPROPDESC 0x24
-#define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25
-
-/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
- * The remaining flags are specific to the debugger.
- */
-#define DUK_DBG_PROPFLAG_INTERNAL (1 << 8)
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
-
-DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr);
-
-DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length);
-DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr);
-
-DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length);
-DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr);
-DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr);
-DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr);
-/* XXX: exposed duk_debug_read_pointer */
-/* XXX: exposed duk_debug_read_buffer */
-/* XXX: exposed duk_debug_read_hbuffer */
-#if 0
-DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr);
-#endif
-#if defined(DUK_USE_DEBUGGER_INSPECT)
-DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr);
-#endif
-DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr);
-
-DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length);
-DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x);
-DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr);
-#if defined(DUK_USE_DEBUGGER_INSPECT)
-DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr);
-#endif
-DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val);
-DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x);
-DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x);
-DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length);
-DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data);
-DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h);
-DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length);
-DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h);
-DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr);
-#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
-DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
-#endif
-DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj);
-DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv);
-#if 0 /* unused */
-DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command);
-#endif
-DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg);
-DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command);
-DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
-
-DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
-DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr);
-#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
-DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal);
-#endif
-
-DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc);
-DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
-
-DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
-DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
-#endif
-
-#endif /* DUK_DEBUGGER_H_INCLUDED */
-#line 1 "duk_debug.h"
-/*
- * Debugging macros, DUK_DPRINT() and its variants in particular.
- *
- * DUK_DPRINT() allows formatted debug prints, and supports standard
- * and Duktape specific formatters. See duk_debug_vsnprintf.c for details.
- *
- * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros
- * for technical reasons. They are concretely used to hide 'x' from the
- * compiler when the corresponding log level is disabled. This allows
- * clean builds on non-C99 compilers, at the cost of more verbose code.
- * Examples:
- *
- * DUK_D(DUK_DPRINT("foo"));
- * DUK_DD(DUK_DDPRINT("foo"));
- * DUK_DDD(DUK_DDDPRINT("foo"));
- *
- * This approach is preferable to the old "double parentheses" hack because
- * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can
- * no longer be added transparently without going through globals, which
- * works poorly with threading.
- */
-
-#ifndef DUK_DEBUG_H_INCLUDED
-#define DUK_DEBUG_H_INCLUDED
-
-#ifdef DUK_USE_DEBUG
-
-#if defined(DUK_USE_DPRINT)
-#define DUK_D(x) x
-#else
-#define DUK_D(x) do { } while (0) /* omit */
-#endif
-
-#if defined(DUK_USE_DDPRINT)
-#define DUK_DD(x) x
-#else
-#define DUK_DD(x) do { } while (0) /* omit */
-#endif
-
-#if defined(DUK_USE_DDDPRINT)
-#define DUK_DDD(x) x
-#else
-#define DUK_DDD(x) do { } while (0) /* omit */
-#endif
-
-/*
- * Exposed debug macros: debugging enabled
- */
-
-#define DUK_LEVEL_DEBUG 1
-#define DUK_LEVEL_DDEBUG 2
-#define DUK_LEVEL_DDDEBUG 3
-
-#ifdef DUK_USE_VARIADIC_MACROS
-
-/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
- * possible compile time, but waste some space with shared function names.
- */
-#define DUK__DEBUG_LOG(lev,...) duk_debug_log((duk_small_int_t) (lev), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, DUK_FUNC_MACRO, __VA_ARGS__);
-
-#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
-
-#ifdef DUK_USE_DDPRINT
-#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
-#else
-#define DUK_DDPRINT(...)
-#endif
-
-#ifdef DUK_USE_DDDPRINT
-#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
-#else
-#define DUK_DDDPRINT(...)
-#endif
-
-#else /* DUK_USE_VARIADIC_MACROS */
-
-#define DUK__DEBUG_STASH(lev) \
- (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
- duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
- (void) DUK_SNPRINTF(duk_debug_line_stash, DUK_DEBUG_STASH_SIZE, "%ld", (long) DUK_LINE_MACRO), \
- duk_debug_line_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
- (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
- duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0; \
- (void) (duk_debug_level_stash = (lev))
-
-/* Without variadic macros resort to comma expression trickery to handle debug
- * prints. This generates a lot of harmless warnings. These hacks are not
- * needed normally because DUK_D() and friends will hide the entire debug log
- * statement from the compiler.
- */
-
-#ifdef DUK_USE_DPRINT
-#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */
-#else
-#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
-#endif
-
-#ifdef DUK_USE_DDPRINT
-#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */
-#else
-#define DUK_DDPRINT 0 && /* args */
-#endif
-
-#ifdef DUK_USE_DDDPRINT
-#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */
-#else
-#define DUK_DDDPRINT 0 && /* args */
-#endif
-
-#endif /* DUK_USE_VARIADIC_MACROS */
-
-#else /* DUK_USE_DEBUG */
-
-/*
- * Exposed debug macros: debugging disabled
- */
-
-#define DUK_D(x) do { } while (0) /* omit */
-#define DUK_DD(x) do { } while (0) /* omit */
-#define DUK_DDD(x) do { } while (0) /* omit */
-
-#ifdef DUK_USE_VARIADIC_MACROS
-
-#define DUK_DPRINT(...)
-#define DUK_DDPRINT(...)
-#define DUK_DDDPRINT(...)
-
-#else /* DUK_USE_VARIADIC_MACROS */
-
-#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
-#define DUK_DDPRINT 0 && /* args */
-#define DUK_DDDPRINT 0 && /* args */
-
-#endif /* DUK_USE_VARIADIC_MACROS */
-
-#endif /* DUK_USE_DEBUG */
-
-/*
- * Structs
- */
-
-#ifdef DUK_USE_DEBUG
-struct duk_fixedbuffer {
- duk_uint8_t *buffer;
- duk_size_t length;
- duk_size_t offset;
- duk_bool_t truncated;
-};
-#endif
-
-/*
- * Prototypes
- */
-
-#ifdef DUK_USE_DEBUG
-DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
-#if 0 /*unused*/
-DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
-#endif
-DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
-
-#ifdef DUK_USE_VARIADIC_MACROS
-DUK_INTERNAL_DECL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
-#else /* DUK_USE_VARIADIC_MACROS */
-/* parameter passing, not thread safe */
-#define DUK_DEBUG_STASH_SIZE 128
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL_DECL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL_DECL duk_small_int_t duk_debug_level_stash;
-#endif
-DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
-#endif /* DUK_USE_VARIADIC_MACROS */
-
-DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
-DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
-DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
-DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
-DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size);
-DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
-
-#endif /* DUK_USE_DEBUG */
-
-#endif /* DUK_DEBUG_H_INCLUDED */
-#line 1 "duk_error.h"
-/*
- * Error handling macros, assertion macro, error codes.
- *
- * There are three level of 'errors':
- *
- * 1. Ordinary errors, relative to a thread, cause a longjmp, catchable.
- * 2. Fatal errors, relative to a heap, cause fatal handler to be called.
- * 3. Panic errors, unrelated to a heap and cause a process exit.
- *
- * Panics are used by the default fatal error handler and by debug code
- * such as assertions. By providing a proper fatal error handler, user
- * code can avoid panics in non-debug builds.
- */
-
-#ifndef DUK_ERROR_H_INCLUDED
-#define DUK_ERROR_H_INCLUDED
-
-/*
- * Error codes: defined in duktape.h
- *
- * Error codes are used as a shorthand to throw exceptions from inside
- * the implementation. The appropriate Ecmascript object is constructed
- * based on the code. Ecmascript code throws objects directly. The error
- * codes are defined in the public API header because they are also used
- * by calling code.
- */
-
-/*
- * Normal error
- *
- * Normal error is thrown with a longjmp() through the current setjmp()
- * catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap
- * identifies the throwing thread.
- *
- * Error formatting is usually unnecessary. The error macros provide a
- * zero argument version (no formatting) and separate macros for small
- * argument counts. Variadic macros are not used to avoid portability
- * issues and avoid the need for stash-based workarounds when they're not
- * available. Vararg calls are avoided for non-formatted error calls
- * because vararg call sites are larger than normal, and there are a lot
- * of call sites with no formatting.
- *
- * Note that special formatting provided by debug macros is NOT available.
- *
- * The _RAW variants allow the caller to specify file and line. This makes
- * it easier to write checked calls which want to use the call site of the
- * checked function, not the error macro call inside the checked function.
- */
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-
-/* Because there are quite many call sites, pack error code (require at most
- * 8-bit) into a single argument.
- */
-#define DUK_ERROR(thr,err,msg) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
- } while (0)
-#define DUK_ERROR_RAW(thr,file,line,err,msg) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
- } while (0)
-
-#define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
- } while (0)
-#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
- } while (0)
-
-#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
- } while (0)
-#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
- } while (0)
-
-#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
- } while (0)
-#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
- } while (0)
-
-#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
- } while (0)
-#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \
- duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
- DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
- duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
- } while (0)
-
-#else /* DUK_USE_VERBOSE_ERRORS */
-
-#define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err))
-#define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err))
-
-#define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt))
-#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
-
-#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt))
-#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
-
-#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt))
-#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
-
-#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt))
-#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
-
-#endif /* DUK_USE_VERBOSE_ERRORS */
-
-/*
- * Fatal error
- *
- * There are no fatal error macros at the moment. There are so few call
- * sites that the fatal error handler is called directly.
- */
-
-/*
- * Panic error
- *
- * Panic errors are not relative to either a heap or a thread, and cause
- * DUK_PANIC() macro to be invoked. Unless a user provides DUK_USE_PANIC_HANDLER,
- * DUK_PANIC() calls a helper which prints out the error and causes a process
- * exit.
- *
- * The user can override the macro to provide custom handling. A macro is
- * used to allow the user to have inline panic handling if desired (without
- * causing a potentially risky function call).
- *
- * Panics are only used in debug code such as assertions, and by the default
- * fatal error handler.
- */
-
-#if defined(DUK_USE_PANIC_HANDLER)
-/* already defined, good */
-#define DUK_PANIC(code,msg) DUK_USE_PANIC_HANDLER((code),(msg))
-#else
-#define DUK_PANIC(code,msg) duk_default_panic_handler((code),(msg))
-#endif /* DUK_USE_PANIC_HANDLER */
-
-/*
- * Assert macro: failure causes panic.
- */
-
-#if defined(DUK_USE_ASSERTIONS)
-
-/* the message should be a compile time constant without formatting (less risk);
- * we don't care about assertion text size because they're not used in production
- * builds.
- */
-#define DUK_ASSERT(x) do { \
- if (!(x)) { \
- DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
- "assertion failed: " #x \
- " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
- } \
- } while (0)
-
-/* Assertion compatible inside a comma expression, evaluates to void.
- * Currently not compatible with DUK_USE_PANIC_HANDLER() which may have
- * a statement block.
- */
-#if defined(DUK_USE_PANIC_HANDLER)
-/* XXX: resolve macro definition issue or call through a helper function? */
-#define DUK_ASSERT_EXPR(x) ((void) 0)
-#else
-#define DUK_ASSERT_EXPR(x) \
- ((void) ((x) ? 0 : (DUK_PANIC(DUK_ERR_ASSERTION_ERROR, \
- "assertion failed: " #x \
- " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
-#endif
-
-#else /* DUK_USE_ASSERTIONS */
-
-#define DUK_ASSERT(x) do { /* assertion omitted */ } while (0)
-
-#define DUK_ASSERT_EXPR(x) ((void) 0)
-
-#endif /* DUK_USE_ASSERTIONS */
-
-/* this variant is used when an assert would generate a compile warning by
- * being always true (e.g. >= 0 comparison for an unsigned value
- */
-#define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0)
-
-/*
- * Assertion helpers
- */
-
-#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
-#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \
- DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \
- } while (0)
-#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \
- if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \
- } \
- } while (0)
-#else
-#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */
-#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */
-#endif
-
-#define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n))
-
-#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL)
-#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \
- duk_double_union duk__assert_tmp_du; \
- duk__assert_tmp_du.d = (dval); \
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \
- } while (0)
-#else
-#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */
-#endif
-
-/*
- * Helper for valstack space
- *
- * Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
- * required for its own use, and any child calls which are not (a) Duktape API calls
- * or (b) Duktape calls which involve extending the valstack (e.g. getter call).
- */
-
-#define DUK_VALSTACK_ASSERT_EXTRA 5 /* this is added to checks to allow for Duktape
- * API calls in addition to function's own use
- */
-#if defined(DUK_USE_ASSERTIONS)
-#define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \
- DUK_ASSERT((thr) != NULL); \
- DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \
- } while (0)
-#else
-#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */
-#endif
-
-/*
- * Error throwing helpers
- *
- * The goal is to provide verbose and configurable error messages. Call
- * sites should be clean in source code and compile to a small footprint.
- * Small footprint is also useful for performance because small cold paths
- * reduce code cache pressure. Adding macros here only makes sense if there
- * are enough call sites to get concrete benefits.
- */
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-/* Verbose errors with key/value summaries (non-paranoid) or without key/value
- * summaries (paranoid, for some security sensitive environments), the paranoid
- * vs. non-paranoid distinction affects only a few specific errors.
- */
-#if defined(DUK_USE_PARANOID_ERRORS)
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
- } while (0)
-#else /* DUK_USE_PARANOID_ERRORS */
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index), (expectname)); \
- } while (0)
-#endif /* DUK_USE_PARANOID_ERRORS */
-
-#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_UNIMPLEMENTED_ERROR, (msg)); \
- } while (0)
-#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
- duk_err_unimplemented_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_UNSUPPORTED_ERROR, (msg)); \
- } while (0)
-#ifndef DUK_USE_BYTECODE_DUMP_SUPPORT
-#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
- duk_err_unsupported_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#endif
-#define DUK_ERROR_INTERNAL(thr,msg) do { \
- duk_err_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
- duk_err_internal_defmsg((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
- } while (0)
-#define DUK_ERROR_ALLOC(thr,msg) do { \
- duk_err_alloc((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
- DUK_ERROR_ALLOC((thr), DUK_STR_ALLOC_FAILED); \
- } while (0)
-/* DUK_ERR_ASSERTION_ERROR: no macros needed */
-#define DUK_ERROR_API_INDEX(thr,index) do { \
- duk_err_api_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (index)); \
- } while (0)
-#define DUK_ERROR_API(thr,msg) do { \
- duk_err_api((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-/* DUK_ERR_UNCAUGHT_ERROR: no macros needed */
-/* DUK_ERR_ERROR: no macros needed */
-/* DUK_ERR_EVAL: no macros needed */
-#define DUK_ERROR_RANGE(thr,msg) do { \
- duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
- } while (0)
-/* DUK_ERR_REFERENCE_ERROR: no macros needed */
-#define DUK_ERROR_SYNTAX(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
- } while (0)
-#define DUK_ERROR_TYPE(thr,msg) do { \
- DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
- } while (0)
-/* DUK_ERR_URI_ERROR: no macros needed */
-#else /* DUK_USE_VERBOSE_ERRORS */
-/* Non-verbose errors for low memory targets: no file, line, or message. */
-
-#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,index,expectname,lowmemstr) do { \
- duk_err_type((thr)); \
- } while (0)
-
-#define DUK_ERROR_UNIMPLEMENTED(thr,msg) do { \
- duk_err_unimplemented((thr)); \
- } while (0)
-#define DUK_ERROR_UNIMPLEMENTED_DEFMSG(thr) do { \
- duk_err_unimplemented((thr)); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED(thr,msg) do { \
- duk_err_unsupported((thr)); \
- } while (0)
-#define DUK_ERROR_UNSUPPORTED_DEFMSG(thr) do { \
- duk_err_unsupported((thr)); \
- } while (0)
-#define DUK_ERROR_INTERNAL(thr,msg) do { \
- duk_err_internal((thr)); \
- } while (0)
-#define DUK_ERROR_INTERNAL_DEFMSG(thr) do { \
- duk_err_internal((thr)); \
- } while (0)
-#define DUK_ERROR_ALLOC(thr,msg) do { \
- duk_err_alloc((thr)); \
- } while (0)
-#define DUK_ERROR_ALLOC_DEFMSG(thr) do { \
- duk_err_alloc((thr)); \
- } while (0)
-#define DUK_ERROR_API_INDEX(thr,index) do { \
- duk_err_api((thr)); \
- } while (0)
-#define DUK_ERROR_API(thr,msg) do { \
- duk_err_api((thr)); \
- } while (0)
-#define DUK_ERROR_RANGE(thr,msg) do { \
- duk_err_range((thr)); \
- } while (0)
-#define DUK_ERROR_SYNTAX(thr,msg) do { \
- duk_err_syntax((thr)); \
- } while (0)
-#define DUK_ERROR_TYPE(thr,msg) do { \
- duk_err_type((thr)); \
- } while (0)
-#endif /* DUK_USE_VERBOSE_ERRORS */
-
-/*
- * Prototypes
- */
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...));
-#else /* DUK_USE_VERBOSE_ERRORS */
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code));
-#endif /* DUK_USE_VERBOSE_ERRORS */
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line));
-#else
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code));
-#endif
-
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
-
-#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_bool_t noblame_fileline);
-#endif
-#if defined(DUK_USE_AUGMENT_ERROR_THROW)
-DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
-#endif
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-#if defined(DUK_USE_PARANOID_ERRORS)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name));
-#else
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name));
-#endif
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-#ifndef DUK_USE_BYTECODE_DUMP_SUPPORT
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-#endif
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
-#else /* DUK_VERBOSE_ERRORS */
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_api(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unimplemented(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_unsupported(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_internal(duk_hthread *thr));
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_alloc(duk_hthread *thr));
-#endif /* DUK_VERBOSE_ERRORS */
-
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
-
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg));
-
-#if !defined(DUK_USE_PANIC_HANDLER)
-DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_panic_handler(duk_errcode_t code, const char *msg));
-#endif
-
-DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type);
-
-DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
-
-#endif /* DUK_ERROR_H_INCLUDED */
-#line 1 "duk_unicode.h"
-/*
- * Unicode helpers
- */
-
-#ifndef DUK_UNICODE_H_INCLUDED
-#define DUK_UNICODE_H_INCLUDED
-
-/*
- * UTF-8 / XUTF-8 / CESU-8 constants
- */
-
-#define DUK_UNICODE_MAX_XUTF8_LENGTH 7 /* up to 36 bit codepoints */
-#define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
-#define DUK_UNICODE_MAX_CESU8_LENGTH 6 /* all codepoints up to U+10FFFF */
-#define DUK_UNICODE_MAX_CESU8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
-
-/*
- * Useful Unicode codepoints
- *
- * Integer constants must be signed to avoid unexpected coercions
- * in comparisons.
- */
-
-#define DUK_UNICODE_CP_ZWNJ 0x200cL /* zero-width non-joiner */
-#define DUK_UNICODE_CP_ZWJ 0x200dL /* zero-width joiner */
-#define DUK_UNICODE_CP_REPLACEMENT_CHARACTER 0xfffdL /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */
-
-/*
- * ASCII character constants
- *
- * C character literals like 'x' have a platform specific value and do
- * not match ASCII (UTF-8) values on e.g. EBCDIC platforms. So, use
- * these (admittedly awkward) constants instead. These constants must
- * also have signed values to avoid unexpected coercions in comparisons.
- *
- * http://en.wikipedia.org/wiki/ASCII
- */
-
-#define DUK_ASC_NUL 0x00
-#define DUK_ASC_SOH 0x01
-#define DUK_ASC_STX 0x02
-#define DUK_ASC_ETX 0x03
-#define DUK_ASC_EOT 0x04
-#define DUK_ASC_ENQ 0x05
-#define DUK_ASC_ACK 0x06
-#define DUK_ASC_BEL 0x07
-#define DUK_ASC_BS 0x08
-#define DUK_ASC_HT 0x09
-#define DUK_ASC_LF 0x0a
-#define DUK_ASC_VT 0x0b
-#define DUK_ASC_FF 0x0c
-#define DUK_ASC_CR 0x0d
-#define DUK_ASC_SO 0x0e
-#define DUK_ASC_SI 0x0f
-#define DUK_ASC_DLE 0x10
-#define DUK_ASC_DC1 0x11
-#define DUK_ASC_DC2 0x12
-#define DUK_ASC_DC3 0x13
-#define DUK_ASC_DC4 0x14
-#define DUK_ASC_NAK 0x15
-#define DUK_ASC_SYN 0x16
-#define DUK_ASC_ETB 0x17
-#define DUK_ASC_CAN 0x18
-#define DUK_ASC_EM 0x19
-#define DUK_ASC_SUB 0x1a
-#define DUK_ASC_ESC 0x1b
-#define DUK_ASC_FS 0x1c
-#define DUK_ASC_GS 0x1d
-#define DUK_ASC_RS 0x1e
-#define DUK_ASC_US 0x1f
-#define DUK_ASC_SPACE 0x20
-#define DUK_ASC_EXCLAMATION 0x21
-#define DUK_ASC_DOUBLEQUOTE 0x22
-#define DUK_ASC_HASH 0x23
-#define DUK_ASC_DOLLAR 0x24
-#define DUK_ASC_PERCENT 0x25
-#define DUK_ASC_AMP 0x26
-#define DUK_ASC_SINGLEQUOTE 0x27
-#define DUK_ASC_LPAREN 0x28
-#define DUK_ASC_RPAREN 0x29
-#define DUK_ASC_STAR 0x2a
-#define DUK_ASC_PLUS 0x2b
-#define DUK_ASC_COMMA 0x2c
-#define DUK_ASC_MINUS 0x2d
-#define DUK_ASC_PERIOD 0x2e
-#define DUK_ASC_SLASH 0x2f
-#define DUK_ASC_0 0x30
-#define DUK_ASC_1 0x31
-#define DUK_ASC_2 0x32
-#define DUK_ASC_3 0x33
-#define DUK_ASC_4 0x34
-#define DUK_ASC_5 0x35
-#define DUK_ASC_6 0x36
-#define DUK_ASC_7 0x37
-#define DUK_ASC_8 0x38
-#define DUK_ASC_9 0x39
-#define DUK_ASC_COLON 0x3a
-#define DUK_ASC_SEMICOLON 0x3b
-#define DUK_ASC_LANGLE 0x3c
-#define DUK_ASC_EQUALS 0x3d
-#define DUK_ASC_RANGLE 0x3e
-#define DUK_ASC_QUESTION 0x3f
-#define DUK_ASC_ATSIGN 0x40
-#define DUK_ASC_UC_A 0x41
-#define DUK_ASC_UC_B 0x42
-#define DUK_ASC_UC_C 0x43
-#define DUK_ASC_UC_D 0x44
-#define DUK_ASC_UC_E 0x45
-#define DUK_ASC_UC_F 0x46
-#define DUK_ASC_UC_G 0x47
-#define DUK_ASC_UC_H 0x48
-#define DUK_ASC_UC_I 0x49
-#define DUK_ASC_UC_J 0x4a
-#define DUK_ASC_UC_K 0x4b
-#define DUK_ASC_UC_L 0x4c
-#define DUK_ASC_UC_M 0x4d
-#define DUK_ASC_UC_N 0x4e
-#define DUK_ASC_UC_O 0x4f
-#define DUK_ASC_UC_P 0x50
-#define DUK_ASC_UC_Q 0x51
-#define DUK_ASC_UC_R 0x52
-#define DUK_ASC_UC_S 0x53
-#define DUK_ASC_UC_T 0x54
-#define DUK_ASC_UC_U 0x55
-#define DUK_ASC_UC_V 0x56
-#define DUK_ASC_UC_W 0x57
-#define DUK_ASC_UC_X 0x58
-#define DUK_ASC_UC_Y 0x59
-#define DUK_ASC_UC_Z 0x5a
-#define DUK_ASC_LBRACKET 0x5b
-#define DUK_ASC_BACKSLASH 0x5c
-#define DUK_ASC_RBRACKET 0x5d
-#define DUK_ASC_CARET 0x5e
-#define DUK_ASC_UNDERSCORE 0x5f
-#define DUK_ASC_GRAVE 0x60
-#define DUK_ASC_LC_A 0x61
-#define DUK_ASC_LC_B 0x62
-#define DUK_ASC_LC_C 0x63
-#define DUK_ASC_LC_D 0x64
-#define DUK_ASC_LC_E 0x65
-#define DUK_ASC_LC_F 0x66
-#define DUK_ASC_LC_G 0x67
-#define DUK_ASC_LC_H 0x68
-#define DUK_ASC_LC_I 0x69
-#define DUK_ASC_LC_J 0x6a
-#define DUK_ASC_LC_K 0x6b
-#define DUK_ASC_LC_L 0x6c
-#define DUK_ASC_LC_M 0x6d
-#define DUK_ASC_LC_N 0x6e
-#define DUK_ASC_LC_O 0x6f
-#define DUK_ASC_LC_P 0x70
-#define DUK_ASC_LC_Q 0x71
-#define DUK_ASC_LC_R 0x72
-#define DUK_ASC_LC_S 0x73
-#define DUK_ASC_LC_T 0x74
-#define DUK_ASC_LC_U 0x75
-#define DUK_ASC_LC_V 0x76
-#define DUK_ASC_LC_W 0x77
-#define DUK_ASC_LC_X 0x78
-#define DUK_ASC_LC_Y 0x79
-#define DUK_ASC_LC_Z 0x7a
-#define DUK_ASC_LCURLY 0x7b
-#define DUK_ASC_PIPE 0x7c
-#define DUK_ASC_RCURLY 0x7d
-#define DUK_ASC_TILDE 0x7e
-#define DUK_ASC_DEL 0x7f
-
-/*
- * Unicode tables
- */
-
-#ifdef DUK_USE_SOURCE_NONBMP
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-extern const duk_uint8_t duk_unicode_ids_noa[791];
-#else
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-extern const duk_uint8_t duk_unicode_ids_noabmp[611];
-#endif
-
-#ifdef DUK_USE_SOURCE_NONBMP
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
-#else
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
-#endif
-
-#ifdef DUK_USE_SOURCE_NONBMP
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-extern const duk_uint8_t duk_unicode_idp_m_ids_noa[397];
-#else
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348];
-#endif
-
-/*
- * Automatically generated by extract_caseconv.py, do not edit!
- */
-
-extern const duk_uint8_t duk_unicode_caseconv_uc[1288];
-extern const duk_uint8_t duk_unicode_caseconv_lc[616];
-
-#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
-/*
- * Automatically generated by extract_caseconv.py, do not edit!
- */
-
-extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
-#endif
-
-/*
- * Extern
- */
-
-/* duk_unicode_support.c */
-#if !defined(DUK_SINGLE_FILE)
-DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7];
-DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2];
-DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22];
-DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8];
-DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4];
-DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24];
-DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10];
-DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128];
-#endif /* !DUK_SINGLE_FILE */
-
-/*
- * Prototypes
- */
-
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp);
-#if defined(DUK_USE_ASSERTIONS)
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp);
-#endif
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out);
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out);
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp);
-DUK_INTERNAL_DECL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end);
-DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen);
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp);
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp);
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp);
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
-DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase);
-DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
-DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
-
-#endif /* DUK_UNICODE_H_INCLUDED */
-#line 1 "duk_json.h"
-/*
- * Defines for JSON, especially duk_bi_json.c.
- */
-
-#ifndef DUK_JSON_H_INCLUDED
-#define DUK_JSON_H_INCLUDED
-
-/* Encoding/decoding flags */
-#define DUK_JSON_FLAG_ASCII_ONLY (1 << 0) /* escape any non-ASCII characters */
-#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1 << 1) /* avoid key quotes when key is an ASCII Identifier */
-#define DUK_JSON_FLAG_EXT_CUSTOM (1 << 2) /* extended types: custom encoding */
-#define DUK_JSON_FLAG_EXT_COMPATIBLE (1 << 3) /* extended types: compatible encoding */
-
-/* How much stack to require on entry to object/array encode */
-#define DUK_JSON_ENC_REQSTACK 32
-
-/* How much stack to require on entry to object/array decode */
-#define DUK_JSON_DEC_REQSTACK 32
-
-/* How large a loop detection stack to use */
-#define DUK_JSON_ENC_LOOPARRAY 64
-
-/* Encoding state. Heap object references are all borrowed. */
-typedef struct {
- duk_hthread *thr;
- duk_bufwriter_ctx bw; /* output bufwriter */
- duk_hobject *h_replacer; /* replacer function */
- duk_hstring *h_gap; /* gap (if empty string, NULL) */
- duk_idx_t idx_proplist; /* explicit PropertyList */
- duk_idx_t idx_loop; /* valstack index of loop detection object */
- duk_small_uint_t flags;
- duk_small_uint_t flag_ascii_only;
- duk_small_uint_t flag_avoid_key_quotes;
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- duk_small_uint_t flag_ext_custom;
- duk_small_uint_t flag_ext_compatible;
- duk_small_uint_t flag_ext_custom_or_compatible;
-#endif
- duk_int_t recursion_depth;
- duk_int_t recursion_limit;
- duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- duk_small_uint_t stridx_custom_undefined;
- duk_small_uint_t stridx_custom_nan;
- duk_small_uint_t stridx_custom_neginf;
- duk_small_uint_t stridx_custom_posinf;
- duk_small_uint_t stridx_custom_function;
-#endif
- duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */
-} duk_json_enc_ctx;
-
-typedef struct {
- duk_hthread *thr;
- const duk_uint8_t *p;
- const duk_uint8_t *p_start;
- const duk_uint8_t *p_end;
- duk_idx_t idx_reviver;
- duk_small_uint_t flags;
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- duk_small_uint_t flag_ext_custom;
- duk_small_uint_t flag_ext_compatible;
- duk_small_uint_t flag_ext_custom_or_compatible;
-#endif
- duk_int_t recursion_depth;
- duk_int_t recursion_limit;
-} duk_json_dec_ctx;
-
-#endif /* DUK_JSON_H_INCLUDED */
-#line 1 "duk_js.h"
-/*
- * Ecmascript execution, support primitives.
- */
-
-#ifndef DUK_JS_H_INCLUDED
-#define DUK_JS_H_INCLUDED
-
-/* Flags for call handling. */
-#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 */
-#define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */
-
-/* Flags for duk_js_compare_helper(). */
-#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 0) /* eval left argument first */
-#define DUK_COMPARE_FLAG_NEGATE (1 << 1) /* negate result */
-
-/* conversions, coercions, comparison, etc */
-DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
-DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x);
-DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
-DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx);
-DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h);
-DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
-DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2);
-DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
-#if 0 /* unused */
-DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
-#endif
-DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
-DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
-DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
-DUK_INTERNAL_DECL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x);
-
-#define duk_js_equals(thr,tv_x,tv_y) \
- duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
-#define duk_js_strict_equals(tv_x,tv_y) \
- duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)
-#define duk_js_samevalue(tv_x,tv_y) \
- duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)
-
-/* E5 Sections 11.8.1, 11.8.5; x < y */
-#define duk_js_lessthan(thr,tv_x,tv_y) \
- duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
-
-/* E5 Sections 11.8.2, 11.8.5; x > y --> y < x */
-#define duk_js_greaterthan(thr,tv_x,tv_y) \
- duk_js_compare_helper((thr), (tv_y), (tv_x), 0)
-
-/* E5 Sections 11.8.3, 11.8.5; x <= y --> not (x > y) --> not (y < x) */
-#define duk_js_lessthanorequal(thr,tv_x,tv_y) \
- duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)
-
-/* E5 Sections 11.8.4, 11.8.5; x >= y --> not (x < y) */
-#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \
- duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
-
-/* identifiers and environment handling */
-#if 0 /*unused*/
-DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
-#endif
-DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag);
-DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag);
-DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict);
-DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict);
-#if 0 /*unused*/
-DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
-#endif
-DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
-DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl);
-DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
-DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase);
-DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom);
-DUK_INTERNAL_DECL
-void duk_js_push_closure(duk_hthread *thr,
- duk_hcompiledfunction *fun_temp,
- duk_hobject *outer_var_env,
- duk_hobject *outer_lex_env,
- duk_bool_t add_auto_proto);
-
-/* call handling */
-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);
-
-/* bytecode execution */
-DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
-
-#endif /* DUK_JS_H_INCLUDED */
-#line 1 "duk_numconv.h"
-#ifndef DUK_NUMCONV_H_INCLUDED
-#define DUK_NUMCONV_H_INCLUDED
-
-/*
- * Number-to-string conversion. The semantics of these is very tightly
- * bound with the Ecmascript semantics required for call sites.
- */
-
-/* Output a specified number of digits instead of using the shortest
- * form. Used for toPrecision() and toFixed().
- */
-#define DUK_N2S_FLAG_FIXED_FORMAT (1 << 0)
-
-/* Force exponential format. Used for toExponential(). */
-#define DUK_N2S_FLAG_FORCE_EXP (1 << 1)
-
-/* If number would need zero padding (for whole number part), use
- * exponential format instead. E.g. if input number is 12300, 3
- * digits are generated ("123"), output "1.23e+4" instead of "12300".
- * Used for toPrecision().
- */
-#define DUK_N2S_FLAG_NO_ZERO_PAD (1 << 2)
-
-/* Digit count indicates number of fractions (i.e. an absolute
- * digit index instead of a relative one). Used together with
- * DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
- */
-#define DUK_N2S_FLAG_FRACTION_DIGITS (1 << 3)
-
-/*
- * String-to-number conversion
- */
-
-/* Maximum exponent value when parsing numbers. This is not strictly
- * compliant as there should be no upper limit, but as we parse the
- * exponent without a bigint, impose some limit.
- */
-#define DUK_S2N_MAX_EXPONENT 1000000000
-
-/* Trim white space (= allow leading and trailing whitespace) */
-#define DUK_S2N_FLAG_TRIM_WHITE (1 << 0)
-
-/* Allow exponent */
-#define DUK_S2N_FLAG_ALLOW_EXP (1 << 1)
-
-/* Allow trailing garbage (e.g. treat "123foo" as "123) */
-#define DUK_S2N_FLAG_ALLOW_GARBAGE (1 << 2)
-
-/* Allow leading plus sign */
-#define DUK_S2N_FLAG_ALLOW_PLUS (1 << 3)
-
-/* Allow leading minus sign */
-#define DUK_S2N_FLAG_ALLOW_MINUS (1 << 4)
-
-/* Allow 'Infinity' */
-#define DUK_S2N_FLAG_ALLOW_INF (1 << 5)
-
-/* Allow fraction part */
-#define DUK_S2N_FLAG_ALLOW_FRAC (1 << 6)
-
-/* Allow naked fraction (e.g. ".123") */
-#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1 << 7)
-
-/* Allow empty fraction (e.g. "123.") */
-#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1 << 8)
-
-/* Allow empty string to be interpreted as 0 */
-#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1 << 9)
-
-/* Allow leading zeroes (e.g. "0123" -> "123") */
-#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1 << 10)
-
-/* Allow automatic detection of hex base ("0x" or "0X" prefix),
- * overrides radix argument and forces integer mode.
- */
-#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11)
-
-/* Allow automatic detection of octal base, overrides radix
- * argument and forces integer mode.
- */
-#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 12)
-
-/*
- * Prototypes
- */
-
-DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags);
-
-#endif /* DUK_NUMCONV_H_INCLUDED */
-#line 1 "duk_bi_protos.h"
-/*
- * Prototypes for built-in functions not automatically covered by the
- * header declarations emitted by genbuiltins.py.
- */
-
-#ifndef DUK_BUILTIN_PROTOS_H_INCLUDED
-#define DUK_BUILTIN_PROTOS_H_INCLUDED
-
-/* Buffer size needed for duk_bi_date_format_timeval().
- * Accurate value is 32 + 1 for NUL termination:
- * >>> len('+123456-01-23T12:34:56.123+12:34')
- * 32
- * Include additional space to be safe.
- */
-#define DUK_BI_DATE_ISO8601_BUFSIZE 48
-
-/* Maximum length of CommonJS module identifier to resolve. Length includes
- * both current module ID, requested (possibly relative) module ID, and a
- * slash in between.
- */
-#define DUK_BI_COMMONJS_MODULE_ID_LIMIT 256
-
-/* Helpers exposed for internal use */
-DUK_INTERNAL_DECL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags);
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
-DUK_INTERNAL_DECL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf);
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
-/* Built-in providers */
-#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx);
-#endif
-#if defined(DUK_USE_DATE_NOW_TIME)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx);
-#endif
-#if defined(DUK_USE_DATE_NOW_WINDOWS)
-DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx);
-#endif
-#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME)
-DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
-#endif
-#if defined(DUK_USE_DATE_TZO_WINDOWS)
-DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
-#endif
-#if defined(DUK_USE_DATE_PRS_STRPTIME)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str);
-#endif
-#if defined(DUK_USE_DATE_PRS_GETDATE)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str);
-#endif
-#if defined(DUK_USE_DATE_FMT_STRFTIME)
-DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
-#endif
-
-DUK_INTERNAL_DECL
-void duk_bi_json_parse_helper(duk_context *ctx,
- duk_idx_t idx_value,
- duk_idx_t idx_reviver,
- duk_small_uint_t flags);
-DUK_INTERNAL_DECL
-void duk_bi_json_stringify_helper(duk_context *ctx,
- duk_idx_t idx_value,
- duk_idx_t idx_replacer,
- duk_idx_t idx_space,
- duk_small_uint_t flags);
-
-#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
-#line 1 "duk_selftest.h"
-/*
- * Selftest code
- */
-
-#ifndef DUK_SELFTEST_H_INCLUDED
-#define DUK_SELFTEST_H_INCLUDED
-
-#if defined(DUK_USE_SELF_TESTS)
-DUK_INTERNAL_DECL void duk_selftest_run_tests(void);
-#endif
-
-#endif /* DUK_SELFTEST_H_INCLUDED */
-#line 78 "duk_internal.h"
-
-#endif /* DUK_INTERNAL_H_INCLUDED */
-#line 1 "duk_replacements.c"
-/*
- * Replacements for missing platform functions.
- *
- * Unlike the originals, fpclassify() and signbit() replacements don't
- * work on any floating point types, only doubles. The C typing here
- * mimics the standard prototypes.
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_COMPUTED_NAN)
-DUK_INTERNAL double duk_computed_nan;
-#endif
-
-#if defined(DUK_USE_COMPUTED_INFINITY)
-DUK_INTERNAL double duk_computed_infinity;
-#endif
-
-#if defined(DUK_USE_REPL_FPCLASSIFY)
-DUK_INTERNAL int duk_repl_fpclassify(double x) {
- duk_double_union u;
- duk_uint_fast16_t expt;
- duk_small_int_t mzero;
-
- u.d = x;
- expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL);
- if (expt > 0x0000UL && expt < 0x7ff0UL) {
- /* expt values [0x001,0x7fe] = normal */
- return DUK_FP_NORMAL;
- }
-
- mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0);
- if (expt == 0x0000UL) {
- /* expt 0x000 is zero/subnormal */
- if (mzero) {
- return DUK_FP_ZERO;
- } else {
- return DUK_FP_SUBNORMAL;
- }
- } else {
- /* expt 0xfff is infinite/nan */
- if (mzero) {
- return DUK_FP_INFINITE;
- } else {
- return DUK_FP_NAN;
- }
- }
-}
-#endif
-
-#if defined(DUK_USE_REPL_SIGNBIT)
-DUK_INTERNAL int duk_repl_signbit(double x) {
- duk_double_union u;
- u.d = x;
- return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL);
-}
-#endif
-
-#if defined(DUK_USE_REPL_ISFINITE)
-DUK_INTERNAL int duk_repl_isfinite(double x) {
- int c = DUK_FPCLASSIFY(x);
- if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
- return 0;
- } else {
- return 1;
- }
-}
-#endif
-
-#if defined(DUK_USE_REPL_ISNAN)
-DUK_INTERNAL int duk_repl_isnan(double x) {
- int c = DUK_FPCLASSIFY(x);
- return (c == DUK_FP_NAN);
-}
-#endif
-
-#if defined(DUK_USE_REPL_ISINF)
-DUK_INTERNAL int duk_repl_isinf(double x) {
- int c = DUK_FPCLASSIFY(x);
- return (c == DUK_FP_INFINITE);
-}
-#endif
-#line 1 "duk_strings.c"
-/*
- * Shared error message strings
- *
- * To minimize code footprint, try to share error messages inside Duktape
- * code. Modern compilers will do this automatically anyway, this is mostly
- * for older compilers.
- */
-
-/* include removed: duk_internal.h */
-
-/* Mostly API and built-in method related */
-DUK_INTERNAL const char *duk_str_internal_error = "internal error";
-DUK_INTERNAL const char *duk_str_invalid_count = "invalid count";
-DUK_INTERNAL const char *duk_str_invalid_call_args = "invalid call args";
-DUK_INTERNAL const char *duk_str_not_constructable = "not constructable";
-DUK_INTERNAL const char *duk_str_not_callable = "not callable";
-DUK_INTERNAL const char *duk_str_not_extensible = "not extensible";
-DUK_INTERNAL const char *duk_str_not_writable = "not writable";
-DUK_INTERNAL const char *duk_str_not_configurable = "not configurable";
-
-DUK_INTERNAL const char *duk_str_invalid_context = "invalid context";
-DUK_INTERNAL const char *duk_str_push_beyond_alloc_stack = "attempt to push beyond currently allocated stack";
-DUK_INTERNAL const char *duk_str_not_buffer = "not buffer"; /* still in use with verbose messages */
-DUK_INTERNAL const char *duk_str_unexpected_type = "unexpected type";
-DUK_INTERNAL const char *duk_str_defaultvalue_coerce_failed = "[[DefaultValue]] coerce failed";
-DUK_INTERNAL const char *duk_str_number_outside_range = "number outside range";
-DUK_INTERNAL const char *duk_str_not_object_coercible = "not object coercible";
-DUK_INTERNAL const char *duk_str_string_too_long = "string too long";
-DUK_INTERNAL const char *duk_str_buffer_too_long = "buffer too long";
-DUK_INTERNAL const char *duk_str_sprintf_too_long = "sprintf message too long";
-DUK_INTERNAL const char *duk_str_alloc_failed = "alloc failed";
-DUK_INTERNAL const char *duk_str_pop_too_many = "attempt to pop too many entries";
-DUK_INTERNAL const char *duk_str_wrong_buffer_type = "wrong buffer type";
-DUK_INTERNAL const char *duk_str_encode_failed = "encode failed";
-DUK_INTERNAL const char *duk_str_decode_failed = "decode failed";
-DUK_INTERNAL const char *duk_str_no_sourcecode = "no sourcecode";
-DUK_INTERNAL const char *duk_str_concat_result_too_long = "concat result too long";
-DUK_INTERNAL const char *duk_str_unimplemented = "unimplemented";
-DUK_INTERNAL const char *duk_str_unsupported = "unsupported";
-DUK_INTERNAL const char *duk_str_array_length_over_2g = "array length over 2G";
-
-/* JSON */
-DUK_INTERNAL const char *duk_str_fmt_ptr = "%p";
-DUK_INTERNAL const char *duk_str_fmt_invalid_json = "invalid json (at offset %ld)";
-DUK_INTERNAL const char *duk_str_jsondec_reclimit = "json decode recursion limit";
-DUK_INTERNAL const char *duk_str_jsonenc_reclimit = "json encode recursion limit";
-DUK_INTERNAL const char *duk_str_cyclic_input = "cyclic input";
-
-/* Object property access */
-DUK_INTERNAL const char *duk_str_proxy_revoked = "proxy revoked";
-DUK_INTERNAL const char *duk_str_invalid_base = "invalid base value";
-DUK_INTERNAL const char *duk_str_strict_caller_read = "attempt to read strict 'caller'";
-DUK_INTERNAL const char *duk_str_proxy_rejected = "proxy rejected";
-DUK_INTERNAL const char *duk_str_invalid_array_length = "invalid array length";
-DUK_INTERNAL const char *duk_str_array_length_write_failed = "array length write failed";
-DUK_INTERNAL const char *duk_str_array_length_not_writable = "array length non-writable";
-DUK_INTERNAL const char *duk_str_setter_undefined = "setter undefined";
-DUK_INTERNAL const char *duk_str_redefine_virt_prop = "attempt to redefine virtual property";
-DUK_INTERNAL const char *duk_str_invalid_descriptor = "invalid descriptor";
-DUK_INTERNAL const char *duk_str_property_is_virtual = "property is virtual";
-
-/* Compiler */
-DUK_INTERNAL const char *duk_str_parse_error = "parse error";
-DUK_INTERNAL const char *duk_str_duplicate_label = "duplicate label";
-DUK_INTERNAL const char *duk_str_invalid_label = "invalid label";
-DUK_INTERNAL const char *duk_str_invalid_array_literal = "invalid array literal";
-DUK_INTERNAL const char *duk_str_invalid_object_literal = "invalid object literal";
-DUK_INTERNAL const char *duk_str_invalid_var_declaration = "invalid variable declaration";
-DUK_INTERNAL const char *duk_str_cannot_delete_identifier = "cannot delete identifier";
-DUK_INTERNAL const char *duk_str_invalid_expression = "invalid expression";
-DUK_INTERNAL const char *duk_str_invalid_lvalue = "invalid lvalue";
-DUK_INTERNAL const char *duk_str_expected_identifier = "expected identifier";
-DUK_INTERNAL const char *duk_str_empty_expr_not_allowed = "empty expression not allowed";
-DUK_INTERNAL const char *duk_str_invalid_for = "invalid for statement";
-DUK_INTERNAL const char *duk_str_invalid_switch = "invalid switch statement";
-DUK_INTERNAL const char *duk_str_invalid_break_cont_label = "invalid break/continue label";
-DUK_INTERNAL const char *duk_str_invalid_return = "invalid return";
-DUK_INTERNAL const char *duk_str_invalid_try = "invalid try";
-DUK_INTERNAL const char *duk_str_invalid_throw = "invalid throw";
-DUK_INTERNAL const char *duk_str_with_in_strict_mode = "with in strict mode";
-DUK_INTERNAL const char *duk_str_func_stmt_not_allowed = "function statement not allowed";
-DUK_INTERNAL const char *duk_str_unterminated_stmt = "unterminated statement";
-DUK_INTERNAL const char *duk_str_invalid_arg_name = "invalid argument name";
-DUK_INTERNAL const char *duk_str_invalid_func_name = "invalid function name";
-DUK_INTERNAL const char *duk_str_invalid_getset_name = "invalid getter/setter name";
-DUK_INTERNAL const char *duk_str_func_name_required = "function name required";
-
-/* Regexp */
-DUK_INTERNAL const char *duk_str_invalid_quantifier_no_atom = "quantifier without preceding atom";
-DUK_INTERNAL const char *duk_str_invalid_quantifier_values = "quantifier values invalid (qmin > qmax)";
-DUK_INTERNAL const char *duk_str_quantifier_too_many_copies = "quantifier expansion requires too many atom copies";
-DUK_INTERNAL const char *duk_str_unexpected_closing_paren = "unexpected closing parenthesis";
-DUK_INTERNAL const char *duk_str_unexpected_end_of_pattern = "unexpected end of pattern";
-DUK_INTERNAL const char *duk_str_unexpected_regexp_token = "unexpected token in regexp";
-DUK_INTERNAL const char *duk_str_invalid_regexp_flags = "invalid regexp flags";
-DUK_INTERNAL const char *duk_str_invalid_backrefs = "invalid backreference(s)";
-
-/* Limits */
-DUK_INTERNAL const char *duk_str_valstack_limit = "valstack limit";
-DUK_INTERNAL const char *duk_str_callstack_limit = "callstack limit";
-DUK_INTERNAL const char *duk_str_catchstack_limit = "catchstack limit";
-DUK_INTERNAL const char *duk_str_prototype_chain_limit = "prototype chain limit";
-DUK_INTERNAL const char *duk_str_bound_chain_limit = "function call bound chain limit";
-DUK_INTERNAL const char *duk_str_c_callstack_limit = "C call stack depth limit";
-DUK_INTERNAL const char *duk_str_compiler_recursion_limit = "compiler recursion limit";
-DUK_INTERNAL const char *duk_str_bytecode_limit = "bytecode limit";
-DUK_INTERNAL const char *duk_str_reg_limit = "register limit";
-DUK_INTERNAL const char *duk_str_temp_limit = "temp limit";
-DUK_INTERNAL const char *duk_str_const_limit = "const limit";
-DUK_INTERNAL const char *duk_str_func_limit = "function limit";
-DUK_INTERNAL const char *duk_str_regexp_compiler_recursion_limit = "regexp compiler recursion limit";
-DUK_INTERNAL const char *duk_str_regexp_executor_recursion_limit = "regexp executor recursion limit";
-DUK_INTERNAL const char *duk_str_regexp_executor_step_limit = "regexp step limit";
-
-/* Misc */
-#line 1 "duk_debug_macros.c"
-/*
- * Debugging macro calls.
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_DEBUG
-
-/*
- * Debugging enabled
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
-DUK_LOCAL char duk__debug_buf[DUK__DEBUG_BUFSIZE];
-
-DUK_LOCAL const char *duk__get_level_string(duk_small_int_t level) {
- switch ((int) level) {
- case DUK_LEVEL_DEBUG:
- return "D";
- case DUK_LEVEL_DDEBUG:
- return "DD";
- case DUK_LEVEL_DDDEBUG:
- return "DDD";
- }
- return "???";
-}
-
-#ifdef DUK_USE_DPRINT_COLORS
-
-/* http://en.wikipedia.org/wiki/ANSI_escape_code */
-#define DUK__TERM_REVERSE "\x1b[7m"
-#define DUK__TERM_BRIGHT "\x1b[1m"
-#define DUK__TERM_RESET "\x1b[0m"
-#define DUK__TERM_BLUE "\x1b[34m"
-#define DUK__TERM_RED "\x1b[31m"
-
-DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) DUK__TERM_RED;
-}
-
-DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
- switch ((int) level) {
- case DUK_LEVEL_DEBUG:
- return (const char *) (DUK__TERM_RESET DUK__TERM_BRIGHT);
- case DUK_LEVEL_DDEBUG:
- return (const char *) (DUK__TERM_RESET);
- case DUK_LEVEL_DDDEBUG:
- return (const char *) (DUK__TERM_RESET DUK__TERM_BLUE);
- }
- return (const char *) DUK__TERM_RESET;
-}
-
-DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) DUK__TERM_RESET;
-}
-
-#else
-
-DUK_LOCAL const char *duk__get_term_1(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
-
-DUK_LOCAL const char *duk__get_term_2(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
-
-DUK_LOCAL const char *duk__get_term_3(duk_small_int_t level) {
- DUK_UNREF(level);
- return (const char *) "";
-}
-
-#endif /* DUK_USE_DPRINT_COLORS */
-
-#ifdef DUK_USE_VARIADIC_MACROS
-
-DUK_INTERNAL void duk_debug_log(duk_small_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
-
- DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
- duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
-
- DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%ld (%s):%s %s%s\n",
- (const char *) duk__get_term_1(level),
- (const char *) duk__get_level_string(level),
- (const char *) file,
- (long) line,
- (const char *) func,
- (const char *) duk__get_term_2(level),
- (const char *) duk__debug_buf,
- (const char *) duk__get_term_3(level));
- DUK_FFLUSH(DUK_STDERR);
-
- va_end(ap);
-}
-
-#else /* DUK_USE_VARIADIC_MACROS */
-
-DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL char duk_debug_line_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
-DUK_INTERNAL duk_small_int_t duk_debug_level_stash;
-
-DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
- va_list ap;
- duk_small_int_t level = duk_debug_level_stash;
-
- va_start(ap, fmt);
-
- DUK_MEMZERO((void *) duk__debug_buf, (size_t) DUK__DEBUG_BUFSIZE);
- duk_debug_vsnprintf(duk__debug_buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
-
- DUK_FPRINTF(DUK_STDERR, "%s[%s] %s:%s (%s):%s %s%s\n",
- (const char *) duk__get_term_1(level),
- (const char *) duk__get_level_string(duk_debug_level_stash),
- (const char *) duk_debug_file_stash,
- (const char *) duk_debug_line_stash,
- (const char *) duk_debug_func_stash,
- (const char *) duk__get_term_2(level),
- (const char *) duk__debug_buf,
- (const char *) duk__get_term_3(level));
- DUK_FFLUSH(DUK_STDERR);
-
- va_end(ap);
-}
-
-#endif /* DUK_USE_VARIADIC_MACROS */
-
-#else /* DUK_USE_DEBUG */
-
-/*
- * Debugging disabled
- */
-
-#endif /* DUK_USE_DEBUG */
-#line 1 "duk_builtins.c"
-/*
- * Automatically generated by genbuiltins.py, do not edit!
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_ROM_STRINGS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
-#else /* DUK_USE_ROM_STRINGS */
-DUK_INTERNAL const duk_uint8_t duk_strings_data[1049] = {
-79,104,209,144,168,105,6,78,182,139,90,122,8,154,140,35,103,35,117,193,73,
-5,52,116,180,104,166,135,52,189,4,98,12,27,178,156,80,211,31,161,115,150,
-64,52,221,109,24,18,68,157,24,38,67,118,36,55,73,119,151,164,140,93,18,117,
-128,153,201,228,201,205,2,250,8,196,24,232,104,82,146,40,232,193,48,118,
-168,37,147,212,54,127,113,208,70,32,194,187,68,54,127,113,208,70,32,196,
-123,68,54,127,113,209,44,12,121,7,208,70,32,194,186,134,207,236,126,219,
-160,140,65,133,246,136,108,254,199,237,186,8,196,24,87,80,217,253,159,217,
-116,17,136,48,190,209,13,159,217,253,151,65,24,131,12,233,86,224,79,236,
-254,203,160,140,65,134,116,171,112,39,246,223,105,208,70,32,193,140,183,4,
-11,55,92,20,244,141,169,186,50,11,164,109,77,208,208,165,36,79,215,185,13,
-153,34,110,204,241,32,6,66,84,11,112,200,84,52,157,124,92,242,70,120,45,64,
-186,17,22,138,38,0,172,140,19,154,84,26,145,0,86,69,17,180,97,34,0,172,132,
-75,144,215,77,221,91,132,5,147,178,156,80,211,30,160,93,9,215,21,115,119,
-169,49,75,211,138,26,101,205,222,68,157,47,78,40,105,151,55,120,204,156,
-189,56,161,166,52,157,72,136,138,65,154,232,147,162,4,136,150,81,115,66,
-208,210,37,96,148,250,134,140,151,39,212,125,255,221,125,73,80,209,146,233,
-124,93,55,79,15,34,196,230,202,113,160,166,232,157,132,148,128,98,28,46,
-114,200,6,153,180,96,73,19,74,113,67,76,103,5,36,20,211,70,140,133,67,72,
-49,245,160,235,81,212,52,168,106,39,132,253,111,80,210,161,168,158,5,245,
-191,96,31,172,15,208,23,226,190,131,232,62,131,232,11,251,127,93,245,223,
-93,251,172,234,27,80,45,3,250,14,140,19,34,65,19,81,132,108,228,97,1,107,
-33,12,32,45,100,136,206,9,12,196,155,134,69,146,100,235,226,231,146,51,194,
-72,218,48,145,4,200,119,89,189,81,49,39,72,147,235,226,233,186,120,121,58,
-226,167,90,124,93,55,107,71,137,33,68,68,130,64,206,75,189,209,156,144,84,
-44,141,3,8,137,187,178,156,80,211,26,110,242,100,230,146,120,121,8,48,76,6,
-89,26,105,157,65,196,201,213,145,166,153,212,28,76,157,113,75,34,78,62,14,
-38,73,105,228,142,136,178,48,141,152,228,73,150,83,0,148,39,137,75,67,73,
-214,209,129,36,85,190,206,32,17,6,9,128,141,3,8,130,161,100,235,64,194,24,
-52,41,73,19,189,200,108,201,19,111,181,2,232,66,239,173,37,230,157,244,56,
-153,4,225,145,27,233,93,22,1,114,62,251,80,69,128,121,247,213,146,228,109,
-79,190,212,17,35,106,125,246,78,164,68,68,111,175,23,217,45,13,33,119,208,
-68,210,38,250,192,61,91,233,80,208,45,25,36,81,190,156,13,26,201,19,239,
-162,2,214,66,31,125,153,226,64,13,27,236,72,96,130,68,62,251,48,68,196,153,
-119,217,157,18,56,156,199,161,100,42,26,250,77,36,140,122,40,144,19,34,9,
-24,246,103,139,172,150,56,125,145,1,17,29,44,112,250,183,0,100,24,200,218,
-140,228,185,130,9,19,237,190,208,73,184,146,35,68,146,163,8,50,178,99,136,
-44,89,196,2,33,70,64,208,196,67,74,226,88,17,105,73,24,186,37,40,38,5,133,
-161,89,4,183,25,115,119,86,227,118,83,138,26,103,255,223,209,106,141,25,11,
-244,95,117,56,208,159,250,223,251,250,45,52,13,250,47,186,156,104,79,253,
-111,253,253,22,144,210,253,23,221,78,52,39,254,187,254,254,139,77,67,75,
-244,95,117,56,208,159,250,239,251,250,45,22,141,23,209,125,212,227,66,127,
-235,63,239,69,163,69,247,83,141,9,255,165,12,72,5,16,64,145,10,32,76,71,64,
-156,217,161,180,34,6,64,208,198,36,78,50,20,20,92,204,50,44,147,32,134,226,
-17,114,33,202,134,129,107,192,202,232,160,180,104,166,135,52,72,40,144,213,
-33,178,152,26,34,56,163,105,44,104,146,116,139,77,43,34,98,57,38,116,72,
-179,60,93,97,206,56,52,240,242,56,163,168,34,81,57,178,153,42,228,12,182,
-58,22,66,89,19,57,68,176,74,68,35,104,195,18,239,116,102,114,94,100,104,
-228,100,49,238,140,203,42,60,145,35,104,181,146,113,161,10,80,46,68,82,24,
-245,145,132,108,228,148,54,100,137,64,34,13,100,153,222,1,40,6,33,223,20,
-84,19,34,95,23,76,130,153,6,103,208,43,64,141,41,130,104,17,112,130,44,96,
-};
-#endif /* DUK_USE_ROM_STRINGS */
-
-#if defined(DUK_USE_ROM_OBJECTS)
-#error ROM support not enabled, rerun make_dist.py with --rom-support
-#else /* DUK_USE_ROM_OBJECTS */
-/* native functions: 149 */
-DUK_INTERNAL const duk_c_function duk_bi_native_functions[149] = {
- duk_bi_array_constructor,
- duk_bi_array_constructor_is_array,
- duk_bi_array_prototype_concat,
- duk_bi_array_prototype_indexof_shared,
- duk_bi_array_prototype_iter_shared,
- duk_bi_array_prototype_join_shared,
- duk_bi_array_prototype_pop,
- duk_bi_array_prototype_push,
- duk_bi_array_prototype_reduce_shared,
- duk_bi_array_prototype_reverse,
- duk_bi_array_prototype_shift,
- duk_bi_array_prototype_slice,
- duk_bi_array_prototype_sort,
- duk_bi_array_prototype_splice,
- duk_bi_array_prototype_to_string,
- duk_bi_array_prototype_unshift,
- duk_bi_arraybuffer_constructor,
- duk_bi_arraybuffer_isview,
- duk_bi_boolean_constructor,
- duk_bi_boolean_prototype_tostring_shared,
- duk_bi_buffer_compare_shared,
- duk_bi_buffer_constructor,
- duk_bi_buffer_prototype_tostring_shared,
- duk_bi_buffer_readfield,
- duk_bi_buffer_slice_shared,
- duk_bi_buffer_writefield,
- duk_bi_dataview_constructor,
- duk_bi_date_constructor,
- duk_bi_date_constructor_now,
- duk_bi_date_constructor_parse,
- duk_bi_date_constructor_utc,
- duk_bi_date_prototype_get_shared,
- duk_bi_date_prototype_get_timezone_offset,
- duk_bi_date_prototype_set_shared,
- duk_bi_date_prototype_set_time,
- duk_bi_date_prototype_to_json,
- duk_bi_date_prototype_tostring_shared,
- duk_bi_date_prototype_value_of,
- duk_bi_duktape_object_act,
- duk_bi_duktape_object_compact,
- duk_bi_duktape_object_dec,
- duk_bi_duktape_object_enc,
- duk_bi_duktape_object_fin,
- duk_bi_duktape_object_gc,
- duk_bi_duktape_object_info,
- duk_bi_error_constructor_shared,
- duk_bi_error_prototype_filename_getter,
- duk_bi_error_prototype_filename_setter,
- duk_bi_error_prototype_linenumber_getter,
- duk_bi_error_prototype_linenumber_setter,
- duk_bi_error_prototype_stack_getter,
- duk_bi_error_prototype_stack_setter,
- duk_bi_error_prototype_to_string,
- duk_bi_function_constructor,
- duk_bi_function_prototype,
- duk_bi_function_prototype_apply,
- duk_bi_function_prototype_bind,
- duk_bi_function_prototype_call,
- duk_bi_function_prototype_to_string,
- duk_bi_global_object_decode_uri,
- duk_bi_global_object_decode_uri_component,
- duk_bi_global_object_encode_uri,
- duk_bi_global_object_encode_uri_component,
- duk_bi_global_object_escape,
- duk_bi_global_object_eval,
- duk_bi_global_object_is_finite,
- duk_bi_global_object_is_nan,
- duk_bi_global_object_parse_float,
- duk_bi_global_object_parse_int,
- duk_bi_global_object_print_helper,
- duk_bi_global_object_require,
- duk_bi_global_object_unescape,
- duk_bi_json_object_parse,
- duk_bi_json_object_stringify,
- duk_bi_logger_constructor,
- duk_bi_logger_prototype_fmt,
- duk_bi_logger_prototype_log_shared,
- duk_bi_logger_prototype_raw,
- duk_bi_math_object_max,
- duk_bi_math_object_min,
- duk_bi_math_object_onearg_shared,
- duk_bi_math_object_random,
- duk_bi_math_object_twoarg_shared,
- duk_bi_nodejs_buffer_byte_length,
- duk_bi_nodejs_buffer_concat,
- duk_bi_nodejs_buffer_constructor,
- duk_bi_nodejs_buffer_copy,
- duk_bi_nodejs_buffer_fill,
- duk_bi_nodejs_buffer_is_buffer,
- duk_bi_nodejs_buffer_is_encoding,
- duk_bi_nodejs_buffer_tojson,
- duk_bi_nodejs_buffer_tostring,
- duk_bi_nodejs_buffer_write,
- duk_bi_number_constructor,
- duk_bi_number_prototype_to_exponential,
- duk_bi_number_prototype_to_fixed,
- duk_bi_number_prototype_to_locale_string,
- duk_bi_number_prototype_to_precision,
- duk_bi_number_prototype_to_string,
- duk_bi_number_prototype_value_of,
- duk_bi_object_constructor,
- duk_bi_object_constructor_create,
- duk_bi_object_constructor_define_properties,
- duk_bi_object_constructor_define_property,
- duk_bi_object_constructor_get_own_property_descriptor,
- duk_bi_object_constructor_is_extensible,
- duk_bi_object_constructor_is_sealed_frozen_shared,
- duk_bi_object_constructor_keys_shared,
- duk_bi_object_constructor_prevent_extensions,
- duk_bi_object_constructor_seal_freeze_shared,
- duk_bi_object_getprototype_shared,
- duk_bi_object_prototype_has_own_property,
- duk_bi_object_prototype_is_prototype_of,
- duk_bi_object_prototype_property_is_enumerable,
- duk_bi_object_prototype_to_locale_string,
- duk_bi_object_prototype_to_string,
- duk_bi_object_prototype_value_of,
- duk_bi_object_setprototype_shared,
- duk_bi_pointer_constructor,
- duk_bi_pointer_prototype_tostring_shared,
- duk_bi_proxy_constructor,
- duk_bi_regexp_constructor,
- duk_bi_regexp_prototype_exec,
- duk_bi_regexp_prototype_test,
- duk_bi_regexp_prototype_to_string,
- duk_bi_string_constructor,
- duk_bi_string_constructor_from_char_code,
- duk_bi_string_prototype_caseconv_shared,
- duk_bi_string_prototype_char_at,
- duk_bi_string_prototype_char_code_at,
- duk_bi_string_prototype_concat,
- duk_bi_string_prototype_indexof_shared,
- duk_bi_string_prototype_locale_compare,
- duk_bi_string_prototype_match,
- duk_bi_string_prototype_replace,
- duk_bi_string_prototype_search,
- duk_bi_string_prototype_slice,
- duk_bi_string_prototype_split,
- duk_bi_string_prototype_substr,
- duk_bi_string_prototype_substring,
- duk_bi_string_prototype_to_string,
- duk_bi_string_prototype_trim,
- duk_bi_thread_constructor,
- duk_bi_thread_current,
- duk_bi_thread_resume,
- duk_bi_thread_yield,
- duk_bi_type_error_thrower,
- duk_bi_typedarray_constructor,
- duk_bi_typedarray_set,
-};
-#if defined(DUK_USE_BUILTIN_INITJS)
-DUK_INTERNAL const duk_uint8_t duk_initjs_data[187] = {
-40,102,117,110,99,116,105,111,110,40,100,44,97,41,123,102,117,110,99,116,
-105,111,110,32,98,40,97,44,98,44,99,41,123,79,98,106,101,99,116,46,100,101,
-102,105,110,101,80,114,111,112,101,114,116,121,40,97,44,98,44,123,118,97,
-108,117,101,58,99,44,119,114,105,116,97,98,108,101,58,33,48,44,101,110,117,
-109,101,114,97,98,108,101,58,33,49,44,99,111,110,102,105,103,117,114,97,98,
-108,101,58,33,48,125,41,125,98,40,97,46,76,111,103,103,101,114,44,34,99,
-108,111,103,34,44,110,101,119,32,97,46,76,111,103,103,101,114,40,34,67,34,
-41,41,59,98,40,97,44,34,109,111,100,76,111,97,100,101,100,34,44,123,125,41,
-125,41,40,116,104,105,115,44,68,117,107,116,97,112,101,41,59,10,0,
-};
-#endif /* DUK_USE_BUILTIN_INITJS */
-#if defined(DUK_USE_DOUBLE_LE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,0,0,0,0,0,0,7,195,248,119,0,0,0,0,0,0,3,193,252,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
-255,255,255,255,255,253,239,240,153,178,103,95,173,6,101,88,176,0,64,0,0,0,
-0,0,0,3,168,0,0,0,0,0,0,31,15,241,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,0,0,0,0,0,0,60,31,226,51,162,199,131,82,77,104,183,228,206,
-141,38,116,154,150,96,0,0,0,0,0,0,120,127,128,15,248,192,70,40,0,0,0,0,0,0,
-0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
-190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
-126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
-247,111,238,56,0,127,199,2,49,72,0,0,0,0,0,0,248,127,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,105,87,20,139,10,191,5,
-64,130,76,156,197,132,1,101,91,91,187,22,176,36,8,28,201,204,160,119,156,
-253,127,33,23,115,31,193,102,79,142,202,44,15,232,34,182,84,113,95,115,248,
-52,201,241,216,176,139,0,59,148,152,85,239,47,108,254,5,66,76,1,130,212,69,
-79,178,16,148,8,61,58,52,170,49,190,202,6,105,219,251,52,245,7,49,252,22,
-157,26,85,25,64,205,59,127,102,158,160,246,63,74,7,135,23,53,2,65,48,227,
-223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
-211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
-47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,0,0,0,0,65,98,
-32,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,
-60,56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,0,0,0,0,0,0,0,128,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,0,0,0,0,0,0,60,15,192,101,253,152,0,5,109,252,17,98,0,
-0,0,0,0,0,7,129,248,12,191,181,0,0,174,63,130,44,64,0,0,0,0,0,0,240,63,1,
-151,246,224,0,21,215,240,69,136,0,0,0,0,0,0,0,8,0,50,254,228,0,2,188,254,8,
-177,0,0,0,0,0,0,0,1,0,6,95,221,128,0,87,223,193,22,32,0,0,0,0,0,0,8,32,0,
-203,251,208,0,11,3,248,34,196,0,0,0,0,0,0,1,4,0,25,127,126,0,1,97,127,4,88,
-128,0,0,0,0,0,0,32,128,3,47,240,64,0,44,79,224,139,16,0,0,0,0,0,0,8,16,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
-};
-#elif defined(DUK_USE_DOUBLE_BE)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,3,255,192,0,0,0,0,0,0,119,1,255,192,0,0,0,0,0,0,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,15,
-253,255,255,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
-0,0,0,67,168,15,255,0,0,0,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,31,252,0,0,0,0,0,0,34,51,162,199,131,82,77,104,183,228,206,
-141,38,116,154,150,96,127,248,0,0,0,0,0,0,0,15,248,192,70,40,0,0,0,0,0,0,0,
-0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,248,
-190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,167,
-126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,64,
-247,111,238,56,0,127,199,2,49,72,127,248,0,0,0,0,0,0,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,64,5,191,10,139,20,87,
-105,130,76,156,197,132,4,0,38,187,27,187,85,81,104,28,201,204,160,31,243,
-23,33,127,125,28,247,193,102,79,142,202,44,3,255,113,84,118,82,184,47,232,
-52,201,241,216,176,139,0,255,111,45,236,84,155,148,58,5,66,76,4,0,146,31,
-181,68,66,209,136,61,58,52,170,49,190,202,1,255,53,4,243,51,249,222,108,22,
-157,26,85,25,64,63,246,160,158,102,127,59,205,74,7,135,23,53,2,65,48,227,
-223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,195,
-211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,15,
-47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,32,98,65,0,0,0,0,
-0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
-56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,128,0,0,0,0,0,0,0,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,15,252,0,0,0,0,0,0,0,101,253,152,0,5,109,252,17,98,1,
-255,128,0,0,0,0,0,0,12,191,181,0,0,174,63,130,44,64,63,240,0,0,0,0,0,0,1,
-151,246,224,0,21,215,240,69,136,8,0,0,0,0,0,0,0,0,50,254,228,0,2,188,254,8,
-177,1,0,0,0,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,32,8,0,0,0,0,0,0,0,
-203,251,208,0,11,3,248,34,196,4,1,0,0,0,0,0,0,0,25,127,126,0,1,97,127,4,88,
-128,128,32,0,0,0,0,0,0,3,47,240,64,0,44,79,224,139,16,16,8,0,0,0,0,0,0,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
-};
-#elif defined(DUK_USE_DOUBLE_ME)
-DUK_INTERNAL const duk_uint8_t duk_builtins_data[3833] = {
-105,195,75,32,3,148,52,154,248,9,26,13,128,112,105,0,240,22,20,26,95,124,6,
-152,52,137,0,120,99,74,239,129,18,70,241,191,2,98,13,79,32,42,88,210,90,2,
-240,1,50,141,37,168,76,94,216,118,69,229,203,127,44,0,84,163,73,106,21,75,
-14,236,249,98,242,229,191,150,0,46,81,164,181,14,165,151,54,94,89,119,99,
-203,23,151,45,252,176,1,146,141,37,168,93,63,59,186,97,241,23,151,45,252,
-176,1,178,141,37,168,77,79,60,50,197,229,203,127,44,0,116,163,73,106,17,86,
-148,152,188,185,111,229,128,15,148,129,198,137,36,58,166,142,91,251,212,
-243,195,44,94,92,183,242,13,79,8,45,14,91,252,121,148,52,199,120,63,72,105,
-21,240,118,128,210,237,224,245,17,165,43,224,211,55,231,207,151,148,161,70,
-145,0,31,40,107,26,2,18,138,26,228,192,142,0,16,161,174,76,9,74,26,228,192,
-158,0,8,161,174,76,10,96,2,42,26,228,192,174,0,26,161,174,76,11,96,3,74,26,
-228,192,190,0,44,161,174,76,12,96,3,202,26,228,192,206,0,70,161,169,84,14,
-202,3,255,254,32,234,0,0,7,195,248,0,0,0,0,119,0,0,3,193,252,0,0,0,0,57,
-136,1,152,32,16,194,0,166,24,6,49,0,57,138,2,12,96,18,99,128,163,32,5,153,
-40,76,94,216,118,69,229,203,127,35,41,10,165,135,118,124,177,121,114,223,
-200,203,67,169,101,205,151,150,93,216,242,197,229,203,127,35,49,11,167,231,
-119,76,62,34,242,229,191,145,154,132,212,243,195,44,94,92,183,242,51,144,
-138,180,164,197,229,203,127,35,60,6,26,0,52,208,193,226,117,215,211,15,12,
-166,146,11,67,150,255,30,77,24,58,113,64,243,92,8,27,0,68,217,130,70,212,
-19,54,224,161,185,5,77,216,44,111,65,115,126,12,28,16,100,225,156,16,32,18,
-17,195,15,46,121,100,238,232,136,136,87,12,60,185,229,141,179,126,30,136,
-100,130,233,231,59,12,228,34,66,52,243,141,167,118,158,153,80,73,9,201,151,
-30,252,153,106,210,146,118,72,150,76,184,247,228,203,86,148,152,123,246,
-240,223,187,46,238,135,132,132,229,221,143,126,76,181,105,73,61,36,75,46,
-236,123,242,101,171,74,76,61,251,120,111,221,151,119,67,226,65,178,243,199,
-135,134,83,242,66,58,238,203,207,30,30,25,81,201,5,225,203,78,238,136,163,
-208,92,59,50,242,232,138,62,0,2,38,163,19,255,255,224,142,80,192,0,20,31,
-240,14,135,103,203,210,135,45,253,55,244,243,195,44,252,205,197,0,1,18,221,
-82,0,3,24,207,151,164,254,251,168,114,223,195,47,46,158,98,101,231,143,150,
-158,29,55,242,104,68,79,62,94,147,251,238,161,203,127,12,188,186,121,157,
-135,110,94,109,100,131,99,229,151,15,76,172,168,8,89,217,16,201,151,54,157,
-217,104,114,223,195,47,46,154,114,243,102,68,19,158,92,59,27,73,6,205,203,
-46,95,89,91,74,0,3,17,225,203,47,108,187,186,69,241,211,46,238,122,119,238,
-230,216,72,70,158,116,242,225,217,151,35,81,33,26,121,198,229,191,214,93,
-205,69,0,1,134,105,231,23,199,76,187,185,233,197,179,43,73,32,154,242,249,
-230,214,80,0,31,255,193,2,38,103,110,117,24,81,115,0,78,228,0,161,208,16,
-237,24,121,207,239,186,135,45,252,50,242,233,229,188,144,221,60,232,114,
-223,211,127,79,60,50,207,204,224,72,167,14,91,248,101,229,211,204,158,113,
-119,117,219,151,150,28,91,50,184,144,40,95,224,0,15,248,64,4,20,78,129,5,
-195,195,134,207,38,232,130,99,195,179,97,201,244,19,22,157,217,14,15,130,
-135,254,0,48,125,60,224,242,229,135,200,9,1,255,12,2,162,136,112,2,112,80,
-128,0,193,177,239,221,143,15,64,35,224,152,20,144,62,27,248,3,2,9,195,175,
-61,0,231,208,126,89,123,101,229,207,40,72,32,188,244,105,205,208,40,16,94,
-123,52,227,202,22,136,39,61,252,186,6,18,13,207,134,205,56,242,134,175,65,
-250,238,231,163,78,110,129,231,208,125,59,178,101,241,63,48,25,248,0,12,47,
-102,30,125,36,238,201,151,196,252,192,103,255,255,240,92,189,178,242,242,8,
-105,4,231,191,110,80,67,80,0,24,62,109,252,162,225,199,160,16,212,0,10,7,
-183,15,0,67,80,0,56,54,109,59,58,101,228,8,106,0,9,6,229,151,39,92,121,66,
-15,192,0,97,124,178,228,235,143,45,45,57,244,116,8,63,255,255,10,39,248,0,
-195,51,114,223,182,30,140,60,161,239,201,149,248,248,31,241,0,140,80,129,
-202,10,49,128,10,35,1,6,199,163,15,40,61,32,9,10,199,163,15,40,123,242,101,
-131,210,4,144,108,123,247,99,195,210,8,250,15,167,118,76,190,39,230,131,52,
-133,236,195,207,164,157,217,50,248,159,154,12,212,0,6,27,179,126,60,59,50,
-195,223,183,134,30,89,97,9,5,219,135,166,61,16,164,131,242,203,195,102,28,
-121,97,145,6,231,151,15,44,122,33,201,5,231,179,78,60,177,8,130,243,225,
-179,79,72,148,66,121,245,197,207,167,45,59,179,197,162,23,211,124,205,253,
-242,242,135,135,158,87,240,68,122,111,153,191,30,29,153,102,111,239,151,
-148,60,60,242,191,130,23,211,125,94,28,50,242,135,135,158,87,240,128,0,196,
-122,111,153,191,30,29,153,106,240,225,151,148,60,60,242,191,132,0,6,9,211,
-150,157,177,160,131,115,235,139,159,78,81,72,10,47,248,0,3,254,40,17,138,
-48,66,136,152,64,0,66,129,48,5,27,252,88,76,216,54,47,214,131,50,172,88,31,
-255,253,239,255,255,255,255,240,153,178,103,95,173,6,101,88,176,0,0,0,0,0,
-64,0,0,3,168,0,0,31,15,224,0,0,0,17,26,19,233,201,169,38,180,91,242,103,70,
-147,58,77,75,48,0,0,60,31,192,0,0,0,34,51,162,199,131,82,77,104,183,228,
-206,141,38,116,154,150,96,0,0,120,127,128,0,0,0,0,15,248,192,70,40,0,0,0,0,
-0,0,0,0,3,10,44,68,9,216,8,20,49,130,15,211,124,109,62,50,228,95,36,55,166,
-248,190,56,111,221,151,119,77,56,118,47,18,23,211,125,14,89,113,233,231,
-167,126,230,18,5,31,252,0,224,188,48,242,231,148,116,144,58,181,33,143,127,
-64,247,111,238,56,0,127,199,2,49,72,0,0,248,127,0,0,0,0,180,81,36,4,51,166,
-248,152,122,101,167,211,150,157,217,201,2,0,3,12,233,190,166,157,185,105,
-244,229,167,118,114,64,128,1,4,228,129,0,3,137,116,223,51,126,60,59,50,196,
-195,211,45,62,156,180,238,206,72,16,0,72,151,77,243,55,227,195,179,45,77,
-59,114,211,233,203,78,236,228,129,0,5,10,73,2,0,12,21,18,4,0,28,82,35,32,
-80,74,8,62,124,189,42,105,219,148,148,16,188,249,122,70,235,179,101,156,
-184,121,15,132,0,34,29,159,47,74,181,33,198,235,179,101,156,184,121,15,132,
-0,38,17,159,47,73,187,247,116,208,62,16,0,168,94,124,189,42,212,135,55,126,
-238,154,7,194,0,23,7,207,151,164,76,61,50,143,132,0,50,21,159,47,74,181,33,
-196,195,211,40,248,64,3,96,217,242,244,137,135,200,248,64,3,161,57,242,244,
-171,82,28,76,62,71,194,0,31,8,207,151,164,141,253,121,115,31,8,0,132,47,62,
-94,149,106,67,145,191,175,46,99,225,0,17,133,103,203,210,110,157,221,122,
-101,230,62,16,1,40,110,124,189,42,212,135,55,78,238,189,50,243,31,8,0,156,
-43,62,94,148,242,227,223,187,39,49,240,128,10,67,115,229,233,86,164,58,121,
-113,239,221,147,152,248,64,5,97,249,242,244,155,167,102,205,60,242,227,223,
-187,39,49,240,128,11,68,179,229,233,86,164,57,186,118,108,211,207,46,61,
-251,178,115,31,8,0,188,71,62,94,149,52,237,203,235,126,236,179,243,102,231,
-151,161,0,32,252,242,244,169,167,110,82,34,67,249,229,233,55,78,205,154,
-121,229,199,191,118,78,100,37,0,24,137,115,203,210,173,72,115,116,236,217,
-167,158,92,123,247,100,230,66,80,1,152,87,60,189,41,229,199,191,118,78,100,
-43,224,3,80,222,121,122,85,169,14,158,92,123,247,100,230,66,190,0,55,10,
-231,151,164,221,59,186,244,203,204,133,252,0,114,27,207,47,74,181,33,205,
-211,187,175,76,188,200,95,192,7,97,28,242,244,145,191,175,46,100,51,224,3,
-208,190,121,122,85,169,14,70,254,188,185,144,207,128,15,193,249,229,233,19,
-15,76,164,37,0,32,133,115,203,210,173,72,113,48,244,202,66,80,2,24,71,60,
-189,38,239,221,211,65,10,248,1,20,47,158,94,149,106,67,155,191,119,77,4,43,
-224,4,112,190,121,122,70,235,179,101,156,184,121,16,191,128,18,67,185,229,
-233,86,164,56,221,118,108,179,151,15,34,23,240,2,88,62,124,189,44,229,195,
-200,124,32,4,208,126,121,122,89,203,135,145,9,64,9,194,145,254,0,0,255,144,
-24,100,130,14,0,16,176,2,192,129,11,33,12,1,168,193,108,96,186,48,95,32,0,
-0,0,0,0,0,0,0,56,38,95,25,113,189,18,9,211,47,62,143,100,20,95,0,20,159,
-240,0,7,252,144,162,241,2,195,66,7,11,89,204,140,197,252,229,197,226,230,
-115,3,16,69,19,64,5,43,252,0,9,255,40,16,188,33,49,123,97,217,23,151,45,
-252,131,66,7,0,20,191,240,0,39,252,176,66,240,133,82,195,187,62,88,188,185,
-111,228,26,16,56,0,166,127,128,1,63,230,2,23,132,58,150,92,217,121,101,221,
-143,44,94,92,183,242,13,8,28,0,83,127,192,0,159,243,65,11,194,23,79,206,
-238,152,124,69,229,203,127,32,208,129,192,5,59,252,0,9,255,56,16,188,33,53,
-60,240,203,23,151,45,252,131,66,7,0,20,255,240,0,39,252,240,66,240,132,85,
-165,38,47,46,91,249,6,132,14,0,31,255,228,64,98,192,10,191,5,64,105,87,20,
-139,130,76,156,197,132,11,22,176,36,1,101,91,91,184,28,201,204,160,33,23,
-115,31,247,156,253,127,65,102,79,142,202,44,4,113,95,115,255,232,34,182,88,
-52,201,241,216,176,139,1,239,47,108,252,59,148,152,86,5,66,76,15,178,16,
-148,1,130,212,69,72,61,58,52,170,49,190,202,4,245,7,49,254,105,219,251,52,
-22,157,26,85,25,64,158,160,246,63,205,59,127,102,74,7,135,23,53,2,65,48,
-227,223,205,64,160,0,48,76,60,244,238,80,40,0,20,19,15,76,59,148,10,0,7,5,
-195,211,14,230,74,72,130,99,203,167,98,129,64,1,32,120,247,243,80,40,0,44,
-15,47,142,10,5,0,6,130,230,217,191,127,37,2,128,3,192,246,111,206,160,80,0,
-136,30,220,62,19,151,160,123,116,238,79,94,129,240,223,221,73,32,0,48,110,
-88,119,100,223,181,68,16,94,91,250,238,200,160,80,0,152,31,61,59,148,10,0,
-21,4,231,199,151,69,2,128,5,192,250,97,220,160,80,0,192,127,255,128,20,23,
-134,30,92,242,164,34,19,207,167,45,59,179,233,205,229,37,129,127,255,0,0,
-191,255,128,0,63,255,197,131,246,203,203,158,157,251,160,0,65,98,32,0,0,0,
-0,3,166,156,30,53,32,249,165,131,76,223,159,62,94,70,172,114,16,176,144,60,
-56,250,19,18,5,159,25,89,32,121,180,238,42,30,129,229,221,140,164,122,7,
-147,46,50,129,232,62,61,251,120,97,199,208,156,129,83,127,0,50,250,69,3,
-252,131,32,248,250,242,229,151,119,72,240,3,254,148,0,2,168,254,0,0,255,
-167,0,33,68,88,32,0,33,64,176,2,170,254,0,0,255,169,0,33,69,220,32,0,33,67,
-184,2,172,254,0,0,255,171,8,137,144,0,0,0,128,0,0,0,0,68,73,4,195,187,126,
-226,8,4,178,16,41,164,32,147,7,136,52,193,240,0,18,17,48,124,0,8,133,76,31,
-0,3,33,147,7,192,1,8,116,193,240,0,82,127,255,132,47,65,11,137,191,174,45,
-153,98,242,229,191,144,105,4,95,47,46,91,249,32,211,185,6,94,92,183,242,65,
-163,14,236,155,52,238,206,0,85,255,192,6,13,167,157,109,57,123,136,144,31,
-245,192,3,5,231,179,78,60,163,9,0,2,10,199,248,0,3,254,192,4,32,249,242,
-244,147,187,163,129,116,128,24,66,51,229,233,87,78,238,142,5,210,0,65,8,
-207,151,164,157,221,24,182,23,72,1,140,39,62,94,149,116,238,232,197,176,
-186,64,8,97,25,242,244,147,187,163,54,66,233,0,50,132,231,203,210,174,157,
-221,25,178,23,72,1,20,43,62,94,145,182,111,195,209,155,33,116,128,17,194,
-179,229,233,27,102,252,61,27,52,23,72,1,36,31,158,94,146,119,116,112,50,
-208,3,8,71,60,189,42,233,221,209,192,203,64,8,33,28,242,244,147,187,163,22,
-195,45,0,49,132,243,203,210,174,157,221,24,182,25,104,1,12,35,158,94,146,
-119,116,102,200,101,160,6,80,158,121,122,85,211,187,163,54,67,45,0,34,133,
-115,203,210,54,205,248,122,51,100,50,208,2,56,87,60,189,35,108,223,135,163,
-102,131,45,0,36,7,255,248,1,11,50,136,132,115,235,139,15,46,88,124,140,36,
-0,4,43,79,224,139,16,0,0,60,15,192,0,0,0,0,101,253,152,0,5,109,252,17,98,0,
-0,7,129,248,0,0,0,0,12,191,181,0,0,174,63,130,44,64,0,0,240,63,0,0,0,0,1,
-151,246,224,0,21,215,240,69,136,0,0,0,8,0,0,0,0,0,50,254,228,0,2,188,254,8,
-177,0,0,0,1,0,0,0,0,0,6,95,221,128,0,87,223,193,22,32,0,0,8,32,0,0,0,0,0,
-203,251,208,0,11,3,248,34,196,0,0,1,4,0,0,0,0,0,25,127,126,0,1,97,127,4,88,
-128,0,0,32,128,0,0,0,0,3,47,240,64,0,44,79,224,139,16,0,0,8,16,0,0,0,0,0,
-101,254,24,0,5,141,252,1,96,216,247,238,199,135,162,162,33,90,121,197,221,
-143,126,77,59,179,172,146,17,167,156,46,185,179,101,228,176,65,89,77,16,
-124,123,246,240,195,203,40,162,64,0,193,255,138,5,144,158,89,112,228,171,
-39,119,71,2,232,132,114,203,135,36,157,221,28,11,164,0,66,25,203,46,28,149,
-100,238,232,197,180,200,162,233,0,1,134,114,203,135,37,89,59,186,49,109,10,
-40,186,64,2,97,124,178,225,201,39,119,70,45,166,69,23,72,0,140,47,150,92,
-57,36,238,232,197,180,40,162,233,0,25,134,114,203,135,37,89,59,186,51,101,
-50,40,186,64,0,161,156,178,225,201,86,78,238,140,217,66,138,46,144,0,168,
-95,44,184,114,73,221,209,155,41,145,69,210,0,37,11,229,151,14,73,59,186,51,
-101,10,40,186,64,6,161,124,178,225,201,27,102,252,61,38,69,23,72,0,28,47,
-150,92,57,35,108,223,135,164,40,162,233,0,11,134,114,203,135,36,77,253,113,
-108,203,50,40,186,64,1,33,156,178,225,201,19,127,92,91,50,194,138,46,144,0,
-200,87,44,184,114,85,147,187,164,200,162,237,0,5,133,114,203,135,37,89,59,
-186,66,138,46,208,0,216,79,44,184,114,73,221,210,100,81,118,128,10,194,121,
-101,195,146,78,238,144,162,139,180,0,118,21,223,150,158,153,106,201,221,
-209,192,203,33,61,249,105,233,150,78,238,142,6,90,0,33,13,239,203,79,76,
-181,100,238,232,197,180,200,163,45,0,1,134,247,229,167,166,90,178,119,116,
-98,218,20,81,150,128,4,195,59,242,211,211,44,157,221,24,182,153,20,101,160,
-2,48,206,252,180,244,203,39,119,70,45,161,69,25,104,0,204,55,191,45,61,50,
-213,147,187,163,54,83,34,140,180,0,10,27,223,150,158,153,106,201,221,209,
-155,40,81,70,90,0,21,12,239,203,79,76,178,119,116,102,202,100,81,150,128,9,
-67,59,242,211,211,44,157,221,25,178,133,20,101,160,3,80,206,252,180,244,
-203,27,102,252,61,38,69,25,104,0,28,51,191,45,61,50,198,217,191,15,72,81,
-70,90,0,23,13,239,203,79,76,177,55,245,197,179,44,200,163,45,0,4,134,247,
-229,167,166,88,155,250,226,217,150,20,81,150,128,6,66,251,242,211,211,45,
-89,59,186,76,138,51,16,0,88,95,126,90,122,101,171,39,119,72,81,70,98,0,27,
-10,239,203,79,76,178,119,116,153,20,102,32,2,176,174,252,180,244,203,39,
-119,72,81,70,98,0,58,40,173,176,82,90,4,19,54,157,155,21,217,6,203,199,174,
-29,156,197,9,7,199,191,111,12,60,178,138,20,0,6,9,143,127,15,42,208,130,
-243,217,167,30,81,132,65,123,242,211,211,42,228,0,
-};
-#else
-#error invalid endianness defines
-#endif
-#endif /* DUK_USE_ROM_OBJECTS */
-#line 1 "duk_error_macros.c"
-/*
- * Error, fatal, and panic handling.
- */
-
-/* include removed: duk_internal.h */
-
-#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-
-DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
- va_list ap;
- char msg[DUK__ERRFMT_BUFSIZE];
- va_start(ap, fmt);
- (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
- msg[sizeof(msg) - 1] = (char) 0;
- duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
- va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */
-}
-
-DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
- duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
-}
-
-#else /* DUK_USE_VERBOSE_ERRORS */
-
-DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
- duk_err_create_and_throw(thr, code);
-}
-
-#endif /* DUK_USE_VERBOSE_ERRORS */
-
-/*
- * Error throwing helpers
- */
-
-#if defined(DUK_USE_VERBOSE_ERRORS)
-#if defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) {
- DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
- expect_name, duk_get_type_name((duk_context *) thr, index), (long) index);
-}
-#else
-DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index, const char *expect_name) {
- DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
- expect_name, duk_push_string_readable((duk_context *) thr, index), (long) index);
-}
-#endif
-DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
-}
-DUK_INTERNAL void duk_err_api_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t index) {
- DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_API_ERROR, "invalid stack index %ld", (long) (index));
-}
-DUK_INTERNAL void duk_err_api(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_API_ERROR, message);
-}
-DUK_INTERNAL void duk_err_unimplemented_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNIMPLEMENTED_ERROR, DUK_STR_UNIMPLEMENTED);
-}
-#ifndef DUK_USE_BYTECODE_DUMP_SUPPORT
-DUK_INTERNAL void duk_err_unsupported_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_UNSUPPORTED_ERROR, DUK_STR_UNSUPPORTED);
-}
-#endif
-DUK_INTERNAL void duk_err_internal_defmsg(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, DUK_STR_INTERNAL_ERROR);
-}
-DUK_INTERNAL void duk_err_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_INTERNAL_ERROR, message);
-}
-DUK_INTERNAL void duk_err_alloc(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
- DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ALLOC_ERROR, message);
-}
-#else
-/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
- * when non-verbose errors are used.
- */
-DUK_INTERNAL void duk_err_type(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_TYPE_ERROR, NULL);
-}
-DUK_INTERNAL void duk_err_api(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_API_ERROR, NULL);
-}
-DUK_INTERNAL void duk_err_range(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_RANGE_ERROR, NULL);
-}
-DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_SYNTAX_ERROR, NULL);
-}
-DUK_INTERNAL void duk_err_unimplemented(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNIMPLEMENTED_ERROR, NULL);
-}
-DUK_INTERNAL void duk_err_unsupported(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_UNSUPPORTED_ERROR, NULL);
-}
-DUK_INTERNAL void duk_err_internal(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, 0, DUK_ERR_INTERNAL_ERROR, NULL);
-}
-DUK_INTERNAL void duk_err_alloc(duk_hthread *thr) {
- DUK_ERROR_RAW(thr, NULL, thr, DUK_ERR_ALLOC_ERROR, NULL);
-}
-#endif
-
-/*
- * Default fatal error handler
- */
-
-DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) {
- DUK_UNREF(ctx);
-#if defined(DUK_USE_FILE_IO)
- DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null"));
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* omit print */
-#endif
- DUK_D(DUK_DPRINT("default fatal handler called, code %ld -> calling DUK_PANIC()", (long) code));
- DUK_PANIC(code, msg);
- DUK_UNREACHABLE();
-}
-
-/*
- * Default panic handler
- */
-
-#if !defined(DUK_USE_PANIC_HANDLER)
-DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) {
-#if defined(DUK_USE_FILE_IO)
- DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s ("
-#if defined(DUK_USE_PANIC_ABORT)
- "calling abort"
-#elif defined(DUK_USE_PANIC_EXIT)
- "calling exit"
-#elif defined(DUK_USE_PANIC_SEGFAULT)
- "segfaulting on purpose"
-#else
-#error no DUK_USE_PANIC_xxx macro defined
-#endif
- ")\n", (long) code, (const char *) (msg ? msg : "null"));
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* omit print */
- DUK_UNREF(code);
- DUK_UNREF(msg);
-#endif
-
-#if defined(DUK_USE_PANIC_ABORT)
- DUK_ABORT();
-#elif defined(DUK_USE_PANIC_EXIT)
- DUK_EXIT(-1);
-#elif defined(DUK_USE_PANIC_SEGFAULT)
- /* exit() afterwards to satisfy "noreturn" */
- DUK_CAUSE_SEGFAULT(); /* SCANBUILD: "Dereference of null pointer", normal */
- DUK_EXIT(-1);
-#else
-#error no DUK_USE_PANIC_xxx macro defined
-#endif
-
- DUK_UNREACHABLE();
-}
-#endif /* !DUK_USE_PANIC_HANDLER */
-
-#undef DUK__ERRFMT_BUFSIZE
-#line 1 "duk_unicode_support.c"
-/*
- * Various Unicode help functions for character classification predicates,
- * case conversion, decoding, etc.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Fast path tables
- */
-
-#if defined(DUK_USE_IDCHAR_FASTPATH)
-DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = {
- /* 0: not IdentifierStart or IdentifierPart
- * 1: IdentifierStart and IdentifierPart
- * -1: IdentifierPart only
- */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00...0x0f */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10...0x1f */
- 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20...0x2f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, /* 0x30...0x3f */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40...0x4f */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50...0x5f */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60...0x6f */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70...0x7f */
-};
-#endif
-
-/*
- * XUTF-8 and CESU-8 encoding/decoding
- */
-
-DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) {
- duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
- if (x < 0x80UL) {
- /* 7 bits */
- return 1;
- } else if (x < 0x800UL) {
- /* 11 bits */
- return 2;
- } else if (x < 0x10000UL) {
- /* 16 bits */
- return 3;
- } else if (x < 0x200000UL) {
- /* 21 bits */
- return 4;
- } else if (x < 0x4000000UL) {
- /* 26 bits */
- return 5;
- } else if (x < (duk_ucodepoint_t) 0x80000000UL) {
- /* 31 bits */
- return 6;
- } else {
- /* 36 bits */
- return 7;
- }
-}
-
-#if defined(DUK_USE_ASSERTIONS)
-DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) {
- duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
- if (x < 0x80UL) {
- /* 7 bits */
- return 1;
- } else if (x < 0x800UL) {
- /* 11 bits */
- return 2;
- } else if (x < 0x10000UL) {
- /* 16 bits */
- return 3;
- } else {
- /* Encoded as surrogate pair, each encoding to 3 bytes for
- * 6 bytes total. Codepoints above U+10FFFF encode as 6 bytes
- * too, see duk_unicode_encode_cesu8().
- */
- return 3 + 3;
- }
-}
-#endif /* DUK_USE_ASSERTIONS */
-
-DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = {
- 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
-};
-
-/* Encode to extended UTF-8; 'out' must have space for at least
- * DUK_UNICODE_MAX_XUTF8_LENGTH bytes. Allows encoding of any
- * 32-bit (unsigned) codepoint.
- */
-DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) {
- duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
- duk_small_int_t len;
- duk_uint8_t marker;
- duk_small_int_t i;
-
- len = duk_unicode_get_xutf8_length(cp);
- DUK_ASSERT(len > 0);
-
- marker = duk_unicode_xutf8_markers[len - 1]; /* 64-bit OK because always >= 0 */
-
- i = len;
- DUK_ASSERT(i > 0);
- do {
- i--;
- if (i > 0) {
- out[i] = (duk_uint8_t) (0x80 + (x & 0x3f));
- x >>= 6;
- } else {
- /* Note: masking of 'x' is not necessary because of
- * range check and shifting -> no bits overlapping
- * the marker should be set.
- */
- out[0] = (duk_uint8_t) (marker + x);
- }
- } while (i > 0);
-
- return len;
-}
-
-/* Encode to CESU-8; 'out' must have space for at least
- * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF
- * will encode to garbage but won't overwrite the output buffer.
- */
-DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) {
- duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
- duk_small_int_t len;
-
- if (x < 0x80UL) {
- out[0] = (duk_uint8_t) x;
- len = 1;
- } else if (x < 0x800UL) {
- out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f));
- out[1] = (duk_uint8_t) (0x80 + (x & 0x3f));
- len = 2;
- } else if (x < 0x10000UL) {
- /* surrogate pairs get encoded here */
- out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f));
- out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f));
- out[2] = (duk_uint8_t) (0x80 + (x & 0x3f));
- len = 3;
- } else {
- /*
- * Unicode codepoints above U+FFFF are encoded as surrogate
- * pairs here. This ensures that all CESU-8 codepoints are
- * 16-bit values as expected in Ecmascript. The surrogate
- * pairs always get a 3-byte encoding (each) in CESU-8.
- * See: http://en.wikipedia.org/wiki/Surrogate_pair
- *
- * 20-bit codepoint, 10 bits (A and B) per surrogate pair:
- *
- * x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB
- * sp1 = 0b110110AA AAAAAAAA (0xd800 + ((x >> 10) & 0x3ff))
- * sp2 = 0b110111BB BBBBBBBB (0xdc00 + (x & 0x3ff))
- *
- * Encoded into CESU-8:
- *
- * sp1 -> 0b11101101 (0xe0 + ((sp1 >> 12) & 0x0f))
- * -> 0b1010AAAA (0x80 + ((sp1 >> 6) & 0x3f))
- * -> 0b10AAAAAA (0x80 + (sp1 & 0x3f))
- * sp2 -> 0b11101101 (0xe0 + ((sp2 >> 12) & 0x0f))
- * -> 0b1011BBBB (0x80 + ((sp2 >> 6) & 0x3f))
- * -> 0b10BBBBBB (0x80 + (sp2 & 0x3f))
- *
- * Note that 0x10000 must be subtracted first. The code below
- * avoids the sp1, sp2 temporaries which saves around 20 bytes
- * of code.
- */
-
- x -= 0x10000UL;
-
- out[0] = (duk_uint8_t) (0xed);
- out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f));
- out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f));
- out[3] = (duk_uint8_t) (0xed);
- out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f));
- out[5] = (duk_uint8_t) (0x80 + (x & 0x3f));
- len = 6;
- }
-
- return len;
-}
-
-/* Decode helper. Return zero on error. */
-DUK_INTERNAL duk_small_int_t duk_unicode_decode_xutf8(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_ucodepoint_t *out_cp) {
- const duk_uint8_t *p;
- duk_uint32_t res;
- duk_uint_fast8_t ch;
- duk_small_int_t n;
-
- DUK_UNREF(thr);
-
- p = *ptr;
- if (p < ptr_start || p >= ptr_end) {
- goto fail;
- }
-
- /*
- * UTF-8 decoder which accepts longer than standard byte sequences.
- * This allows full 32-bit code points to be used.
- */
-
- ch = (duk_uint_fast8_t) (*p++);
- if (ch < 0x80) {
- /* 0xxx xxxx [7 bits] */
- res = (duk_uint32_t) (ch & 0x7f);
- n = 0;
- } else if (ch < 0xc0) {
- /* 10xx xxxx -> invalid */
- goto fail;
- } else if (ch < 0xe0) {
- /* 110x xxxx 10xx xxxx [11 bits] */
- res = (duk_uint32_t) (ch & 0x1f);
- n = 1;
- } else if (ch < 0xf0) {
- /* 1110 xxxx 10xx xxxx 10xx xxxx [16 bits] */
- res = (duk_uint32_t) (ch & 0x0f);
- n = 2;
- } else if (ch < 0xf8) {
- /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx [21 bits] */
- res = (duk_uint32_t) (ch & 0x07);
- n = 3;
- } else if (ch < 0xfc) {
- /* 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [26 bits] */
- res = (duk_uint32_t) (ch & 0x03);
- n = 4;
- } else if (ch < 0xfe) {
- /* 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [31 bits] */
- res = (duk_uint32_t) (ch & 0x01);
- n = 5;
- } else if (ch < 0xff) {
- /* 1111 1110 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [36 bits] */
- res = (duk_uint32_t) (0);
- n = 6;
- } else {
- /* 8-byte format could be:
- * 1111 1111 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [41 bits]
- *
- * However, this format would not have a zero bit following the
- * leading one bits and would not allow 0xFF to be used as an
- * "invalid xutf-8" marker for internal keys. Further, 8-byte
- * encodings (up to 41 bit code points) are not currently needed.
- */
- goto fail;
- }
-
- DUK_ASSERT(p >= ptr_start); /* verified at beginning */
- if (p + n > ptr_end) {
- /* check pointer at end */
- goto fail;
- }
-
- while (n > 0) {
- DUK_ASSERT(p >= ptr_start && p < ptr_end);
- res = res << 6;
- res += (duk_uint32_t) ((*p++) & 0x3f);
- n--;
- }
-
- *ptr = p;
- *out_cp = res;
- return 1;
-
- fail:
- return 0;
-}
-
-/* used by e.g. duk_regexp_executor.c, string built-ins */
-DUK_INTERNAL duk_ucodepoint_t duk_unicode_decode_xutf8_checked(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end) {
- duk_ucodepoint_t cp;
-
- if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
- return cp;
- }
- DUK_ERROR_INTERNAL(thr, "utf-8 decode failed"); /* XXX: 'internal error' is a bit of a misnomer */
- DUK_UNREACHABLE();
- return 0;
-}
-
-/* Compute (extended) utf-8 length without codepoint encoding validation,
- * used for string interning.
- *
- * NOTE: This algorithm is performance critical, more so than string hashing
- * in some cases. It is needed when interning a string and needs to scan
- * every byte of the string with no skipping. Having an ASCII fast path
- * is useful if possible in the algorithm. The current algorithms were
- * chosen from several variants, based on x64 gcc -O2 testing. See:
- * https://github.com/svaarala/duktape/pull/422
- *
- * NOTE: must match src/dukutil.py:duk_unicode_unvalidated_utf8_length().
- */
-
-#if defined(DUK_USE_PREFER_SIZE)
-/* Small variant; roughly 150 bytes smaller than the fast variant. */
-DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
- const duk_uint8_t *p;
- const duk_uint8_t *p_end;
- duk_size_t ncont;
- duk_size_t clen;
-
- p = data;
- p_end = data + blen;
- ncont = 0;
- while (p != p_end) {
- duk_uint8_t x;
- x = *p++;
- if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
- ncont++;
- }
- }
-
- DUK_ASSERT(ncont <= blen);
- clen = blen - ncont;
- DUK_ASSERT(clen <= blen);
- return clen;
-}
-#else /* DUK_USE_PREFER_SIZE */
-/* This seems like a good overall approach. Fast path for ASCII in 4 byte
- * blocks.
- */
-DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
- const duk_uint8_t *p;
- const duk_uint8_t *p_end;
- const duk_uint32_t *p32_end;
- const duk_uint32_t *p32;
- duk_size_t ncont;
- duk_size_t clen;
-
- ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */
- p = data;
- p_end = data + blen;
- if (blen < 16) {
- goto skip_fastpath;
- }
-
- /* Align 'p' to 4; the input data may have arbitrary alignment.
- * End of string check not needed because blen >= 16.
- */
- while (((duk_size_t) (const void *) p) & 0x03U) {
- duk_uint8_t x;
- x = *p++;
- if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
- ncont++;
- }
- }
-
- /* Full, aligned 4-byte reads. */
- p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03)));
- p32 = (const duk_uint32_t *) (const void *) p;
- while (p32 != (const duk_uint32_t *) p32_end) {
- duk_uint32_t x;
- x = *p32++;
- if (DUK_LIKELY((x & 0x80808080UL) == 0)) {
- ; /* ASCII fast path */
- } else {
- /* Flip highest bit of each byte which changes
- * the bit pattern 10xxxxxx into 00xxxxxx which
- * allows an easy bit mask test.
- */
- x ^= 0x80808080UL;
- if (DUK_UNLIKELY(!(x & 0xc0000000UL))) {
- ncont++;
- }
- if (DUK_UNLIKELY(!(x & 0x00c00000UL))) {
- ncont++;
- }
- if (DUK_UNLIKELY(!(x & 0x0000c000UL))) {
- ncont++;
- }
- if (DUK_UNLIKELY(!(x & 0x000000c0UL))) {
- ncont++;
- }
- }
- }
- p = (const duk_uint8_t *) p32;
- /* Fall through to handle the rest. */
-
- skip_fastpath:
- while (p != p_end) {
- duk_uint8_t x;
- x = *p++;
- if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
- ncont++;
- }
- }
-
- DUK_ASSERT(ncont <= blen);
- clen = blen - ncont;
- DUK_ASSERT(clen <= blen);
- return clen;
-}
-#endif /* DUK_USE_PREFER_SIZE */
-
-/*
- * Unicode range matcher
- *
- * Matches a codepoint against a packed bitstream of character ranges.
- * Used for slow path Unicode matching.
- */
-
-/* Must match src/extract_chars.py, generate_match_table3(). */
-DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
- duk_uint32_t t;
-
- t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4);
- if (t <= 0x0eU) {
- return t;
- }
- t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8);
- if (t <= 0xfdU) {
- return t + 0x0f;
- }
- if (t == 0xfeU) {
- t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12);
- return t + 0x0fU + 0xfeU;
- } else {
- t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24);
- return t + 0x0fU + 0xfeU + 0x1000UL;
- }
-}
-
-DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) {
- duk_bitdecoder_ctx bd_ctx;
- duk_codepoint_t prev_re;
-
- DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
- bd_ctx.data = (const duk_uint8_t *) unitab;
- bd_ctx.length = (duk_size_t) unilen;
-
- prev_re = 0;
- for (;;) {
- duk_codepoint_t r1, r2;
- r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
- if (r1 == 0) {
- break;
- }
- r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
-
- r1 = prev_re + r1;
- r2 = r1 + r2;
- prev_re = r2;
-
- /* [r1,r2] is the range */
-
- DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]",
- (unsigned long) cp, (unsigned long) r1, (unsigned long) r2));
- if (cp >= r1 && cp <= r2) {
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
- * "WhiteSpace" production check.
- */
-
-DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
- /*
- * E5 Section 7.2 specifies six characters specifically as
- * white space:
- *
- * 0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
- * 000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
- * 000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
- * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
- * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
- * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
- *
- * It also specifies any Unicode category 'Zs' characters as white
- * space. These can be extracted with the "src/extract_chars.py" script.
- * Current result:
- *
- * RAW OUTPUT:
- * ===========
- * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
- * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
- * 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
- * 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
- * 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
- * 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
- * 2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
- * 2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
- * 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
- * 3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
- *
- * RANGES:
- * =======
- * 0x0020
- * 0x00a0
- * 0x1680
- * 0x180e
- * 0x2000 ... 0x200a
- * 0x202f
- * 0x205f
- * 0x3000
- *
- * A manual decoder (below) is probably most compact for this.
- */
-
- duk_uint_fast8_t lo;
- duk_uint_fast32_t hi;
-
- /* cp == -1 (EOF) never matches and causes return value 0 */
-
- lo = (duk_uint_fast8_t) (cp & 0xff);
- hi = (duk_uint_fast32_t) (cp >> 8); /* does not fit into an uchar */
-
- if (hi == 0x0000UL) {
- if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU ||
- lo == 0x20U || lo == 0xa0U) {
- return 1;
- }
- } else if (hi == 0x0020UL) {
- if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) {
- return 1;
- }
- } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L ||
- cp == 0xfeffL) {
- return 1;
- }
-
- return 0;
-}
-
-/*
- * "LineTerminator" production check.
- */
-
-DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) {
- /*
- * E5 Section 7.3
- *
- * A LineTerminatorSequence essentially merges <CR> <LF> sequences
- * into a single line terminator. This must be handled by the caller.
- */
-
- if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L ||
- cp == 0x2029L) {
- return 1;
- }
-
- return 0;
-}
-
-/*
- * "IdentifierStart" production check.
- */
-
-DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) {
- /*
- * E5 Section 7.6:
- *
- * IdentifierStart:
- * UnicodeLetter
- * $
- * _
- * \ UnicodeEscapeSequence
- *
- * IdentifierStart production has one multi-character production:
- *
- * \ UnicodeEscapeSequence
- *
- * The '\' character is -not- matched by this function. Rather, the caller
- * should decode the escape and then call this function to check whether the
- * decoded character is acceptable (see discussion in E5 Section 7.6).
- *
- * The "UnicodeLetter" alternative of the production allows letters
- * from various Unicode categories. These can be extracted with the
- * "src/extract_chars.py" script.
- *
- * Because the result has hundreds of Unicode codepoint ranges, matching
- * for any values >= 0x80 are done using a very slow range-by-range scan
- * and a packed range format.
- *
- * The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because
- * it matters the most. The ASCII related ranges of IdentifierStart are:
- *
- * 0x0041 ... 0x005a ['A' ... 'Z']
- * 0x0061 ... 0x007a ['a' ... 'z']
- * 0x0024 ['$']
- * 0x005f ['_']
- */
-
- /* ASCII (and EOF) fast path -- quick accept and reject */
- if (cp <= 0x7fL) {
-#if defined(DUK_USE_IDCHAR_FASTPATH)
- return (cp >= 0) && (duk_is_idchar_tab[cp] > 0);
-#else
- if ((cp >= 'a' && cp <= 'z') ||
- (cp >= 'A' && cp <= 'Z') ||
- cp == '_' || cp == '$') {
- return 1;
- }
- return 0;
-#endif
- }
-
- /* Non-ASCII slow path (range-by-range linear comparison), very slow */
-
-#ifdef DUK_USE_SOURCE_NONBMP
- if (duk__uni_range_match(duk_unicode_ids_noa,
- (duk_size_t) sizeof(duk_unicode_ids_noa),
- (duk_codepoint_t) cp)) {
- return 1;
- }
- return 0;
-#else
- if (cp < 0x10000L) {
- if (duk__uni_range_match(duk_unicode_ids_noabmp,
- sizeof(duk_unicode_ids_noabmp),
- (duk_codepoint_t) cp)) {
- return 1;
- }
- return 0;
- } else {
- /* without explicit non-BMP support, assume non-BMP characters
- * are always accepted as identifier characters.
- */
- return 1;
- }
-#endif
-}
-
-/*
- * "IdentifierPart" production check.
- */
-
-DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) {
- /*
- * E5 Section 7.6:
- *
- * IdentifierPart:
- * IdentifierStart
- * UnicodeCombiningMark
- * UnicodeDigit
- * UnicodeConnectorPunctuation
- * <ZWNJ> [U+200C]
- * <ZWJ> [U+200D]
- *
- * IdentifierPart production has one multi-character production
- * as part of its IdentifierStart alternative. The '\' character
- * of an escape sequence is not matched here, see discussion in
- * duk_unicode_is_identifier_start().
- *
- * To match non-ASCII characters (codepoints >= 0x80), a very slow
- * linear range-by-range scan is used. The codepoint is first compared
- * to the IdentifierStart ranges, and if it doesn't match, then to a
- * set consisting of code points in IdentifierPart but not in
- * IdentifierStart. This is done to keep the unicode range data small,
- * at the expense of speed.
- *
- * The ASCII fast path consists of:
- *
- * 0x0030 ... 0x0039 ['0' ... '9', UnicodeDigit]
- * 0x0041 ... 0x005a ['A' ... 'Z', IdentifierStart]
- * 0x0061 ... 0x007a ['a' ... 'z', IdentifierStart]
- * 0x0024 ['$', IdentifierStart]
- * 0x005f ['_', IdentifierStart and
- * UnicodeConnectorPunctuation]
- *
- * UnicodeCombiningMark has no code points <= 0x7f.
- *
- * The matching code reuses the "identifier start" tables, and then
- * consults a separate range set for characters in "identifier part"
- * but not in "identifier start". These can be extracted with the
- * "src/extract_chars.py" script.
- *
- * UnicodeCombiningMark -> categories Mn, Mc
- * UnicodeDigit -> categories Nd
- * UnicodeConnectorPunctuation -> categories Pc
- */
-
- /* ASCII (and EOF) fast path -- quick accept and reject */
- if (cp <= 0x7fL) {
-#if defined(DUK_USE_IDCHAR_FASTPATH)
- return (cp >= 0) && (duk_is_idchar_tab[cp] != 0);
-#else
- if ((cp >= 'a' && cp <= 'z') ||
- (cp >= 'A' && cp <= 'Z') ||
- (cp >= '0' && cp <= '9') ||
- cp == '_' || cp == '$') {
- return 1;
- }
- return 0;
-#endif
- }
-
- /* Non-ASCII slow path (range-by-range linear comparison), very slow */
-
-#ifdef DUK_USE_SOURCE_NONBMP
- if (duk__uni_range_match(duk_unicode_ids_noa,
- sizeof(duk_unicode_ids_noa),
- (duk_codepoint_t) cp) ||
- duk__uni_range_match(duk_unicode_idp_m_ids_noa,
- sizeof(duk_unicode_idp_m_ids_noa),
- (duk_codepoint_t) cp)) {
- return 1;
- }
- return 0;
-#else
- if (cp < 0x10000L) {
- if (duk__uni_range_match(duk_unicode_ids_noabmp,
- sizeof(duk_unicode_ids_noabmp),
- (duk_codepoint_t) cp) ||
- duk__uni_range_match(duk_unicode_idp_m_ids_noabmp,
- sizeof(duk_unicode_idp_m_ids_noabmp),
- (duk_codepoint_t) cp)) {
- return 1;
- }
- return 0;
- } else {
- /* without explicit non-BMP support, assume non-BMP characters
- * are always accepted as identifier characters.
- */
- return 1;
- }
-#endif
-}
-
-/*
- * Unicode letter check.
- */
-
-DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
- /*
- * Unicode letter is now taken to be the categories:
- *
- * Lu, Ll, Lt, Lm, Lo
- *
- * (Not sure if this is exactly correct.)
- *
- * The ASCII fast path consists of:
- *
- * 0x0041 ... 0x005a ['A' ... 'Z']
- * 0x0061 ... 0x007a ['a' ... 'z']
- */
-
- /* ASCII (and EOF) fast path -- quick accept and reject */
- if (cp <= 0x7fL) {
- if ((cp >= 'a' && cp <= 'z') ||
- (cp >= 'A' && cp <= 'Z')) {
- return 1;
- }
- return 0;
- }
-
- /* Non-ASCII slow path (range-by-range linear comparison), very slow */
-
-#ifdef DUK_USE_SOURCE_NONBMP
- if (duk__uni_range_match(duk_unicode_ids_noa,
- sizeof(duk_unicode_ids_noa),
- (duk_codepoint_t) cp) &&
- !duk__uni_range_match(duk_unicode_ids_m_let_noa,
- sizeof(duk_unicode_ids_m_let_noa),
- (duk_codepoint_t) cp)) {
- return 1;
- }
- return 0;
-#else
- if (cp < 0x10000L) {
- if (duk__uni_range_match(duk_unicode_ids_noabmp,
- sizeof(duk_unicode_ids_noabmp),
- (duk_codepoint_t) cp) &&
- !duk__uni_range_match(duk_unicode_ids_m_let_noabmp,
- sizeof(duk_unicode_ids_m_let_noabmp),
- (duk_codepoint_t) cp)) {
- return 1;
- }
- return 0;
- } else {
- /* without explicit non-BMP support, assume non-BMP characters
- * are always accepted as letters.
- */
- return 1;
- }
-#endif
-}
-
-/*
- * Complex case conversion helper which decodes a bit-packed conversion
- * control stream generated by unicode/extract_caseconv.py. The conversion
- * is very slow because it runs through the conversion data in a linear
- * fashion to save space (which is why ASCII characters have a special
- * fast path before arriving here).
- *
- * The particular bit counts etc have been determined experimentally to
- * be small but still sufficient, and must match the Python script
- * (src/extract_caseconv.py).
- *
- * The return value is the case converted codepoint or -1 if the conversion
- * results in multiple characters (this is useful for regexp Canonicalization
- * operation). If 'buf' is not NULL, the result codepoint(s) are also
- * appended to the hbuffer.
- *
- * Context and locale specific rules must be checked before consulting
- * this function.
- */
-
-DUK_LOCAL
-duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
- duk_bufwriter_ctx *bw,
- duk_codepoint_t cp,
- duk_bitdecoder_ctx *bd_ctx) {
- duk_small_int_t skip = 0;
- duk_small_int_t n;
- duk_small_int_t t;
- duk_small_int_t count;
- duk_codepoint_t tmp_cp;
- duk_codepoint_t start_i;
- duk_codepoint_t start_o;
-
- DUK_UNREF(thr);
- DUK_ASSERT(bd_ctx != NULL);
-
- DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
-
- /* range conversion with a "skip" */
- DUK_DDD(DUK_DDDPRINT("checking ranges"));
- for (;;) {
- skip++;
- n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
- if (n == 0x3f) {
- /* end marker */
- break;
- }
- DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld", (long) skip, (long) n));
-
- while (n--) {
- start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
- start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
- count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
- DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld",
- (long) start_i, (long) start_o, (long) count, (long) skip));
-
- if (cp >= start_i) {
- tmp_cp = cp - start_i; /* always >= 0 */
- if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip &&
- (tmp_cp % (duk_codepoint_t) skip) == 0) {
- DUK_DDD(DUK_DDDPRINT("range matches input codepoint"));
- cp = start_o + tmp_cp;
- goto single;
- }
- }
- }
- }
-
- /* 1:1 conversion */
- n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
- DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n));
- while (n--) {
- start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
- start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
- DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld", (long) start_i, (long) start_o));
- if (cp == start_i) {
- DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint"));
- cp = start_o;
- goto single;
- }
- }
-
- /* complex, multicharacter conversion */
- n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
- DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)", (long) n));
- while (n--) {
- start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
- t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2);
- DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars", (long) start_i, (long) t));
- if (cp == start_i) {
- DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint"));
- if (bw != NULL) {
- while (t--) {
- tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
- DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp);
- }
- }
- return -1;
- } else {
- while (t--) {
- (void) duk_bd_decode(bd_ctx, 16);
- }
- }
- }
-
- /* default: no change */
- DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input"));
- /* fall through */
-
- single:
- if (bw != NULL) {
- DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
- }
- return cp;
-}
-
-/*
- * Case conversion helper, with context/local sensitivity.
- * For proper case conversion, one needs to know the character
- * and the preceding and following characters, as well as
- * locale/language.
- */
-
-/* XXX: add 'language' argument when locale/language sensitive rule
- * support added.
- */
-DUK_LOCAL
-duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
- duk_bufwriter_ctx *bw,
- duk_codepoint_t cp,
- duk_codepoint_t prev,
- duk_codepoint_t next,
- duk_bool_t uppercase) {
- duk_bitdecoder_ctx bd_ctx;
-
- /* fast path for ASCII */
- if (cp < 0x80L) {
- /* XXX: there are language sensitive rules for the ASCII range.
- * If/when language/locale support is implemented, they need to
- * be implemented here for the fast path. There are no context
- * sensitive rules for ASCII range.
- */
-
- if (uppercase) {
- if (cp >= 'a' && cp <= 'z') {
- cp = cp - 'a' + 'A';
- }
- } else {
- if (cp >= 'A' && cp <= 'Z') {
- cp = cp - 'A' + 'a';
- }
- }
-
- if (bw != NULL) {
- DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp);
- }
- return cp;
- }
-
- /* context and locale specific rules which cannot currently be represented
- * in the caseconv bitstream: hardcoded rules in C
- */
- if (uppercase) {
- /* XXX: turkish / azeri */
- } else {
- /*
- * Final sigma context specific rule. This is a rather tricky
- * rule and this handling is probably not 100% correct now.
- * The rule is not locale/language specific so it is supported.
- */
-
- if (cp == 0x03a3L && /* U+03A3 = GREEK CAPITAL LETTER SIGMA */
- duk_unicode_is_letter(prev) && /* prev exists and is not a letter */
- !duk_unicode_is_letter(next)) { /* next does not exist or next is not a letter */
- /* Capital sigma occurred at "end of word", lowercase to
- * U+03C2 = GREEK SMALL LETTER FINAL SIGMA. Otherwise
- * fall through and let the normal rules lowercase it to
- * U+03C3 = GREEK SMALL LETTER SIGMA.
- */
- cp = 0x03c2L;
- goto singlechar;
- }
-
- /* XXX: lithuanian not implemented */
- /* XXX: lithuanian, explicit dot rules */
- /* XXX: turkish / azeri, lowercase rules */
- }
-
- /* 1:1 or special conversions, but not locale/context specific: script generated rules */
- DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
- if (uppercase) {
- bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc;
- bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
- } else {
- bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc;
- bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc);
- }
- return duk__slow_case_conversion(thr, bw, cp, &bd_ctx);
-
- singlechar:
- if (bw != NULL) {
- DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
- }
- return cp;
-
- /* unused now, not needed until Turkish/Azeri */
-#if 0
- nochar:
- return -1;
-#endif
-}
-
-/*
- * Replace valstack top with case converted version.
- */
-
-DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) {
- duk_context *ctx = (duk_context *) thr;
- duk_hstring *h_input;
- duk_bufwriter_ctx bw_alloc;
- duk_bufwriter_ctx *bw;
- const duk_uint8_t *p, *p_start, *p_end;
- duk_codepoint_t prev, curr, next;
-
- h_input = duk_require_hstring(ctx, -1);
- DUK_ASSERT(h_input != NULL);
-
- bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));
-
- /* [ ... input buffer ] */
-
- p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
- p = p_start;
-
- prev = -1; DUK_UNREF(prev);
- curr = -1;
- next = -1;
- for (;;) {
- prev = curr;
- curr = next;
- next = -1;
- if (p < p_end) {
- next = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
- } else {
- /* end of input and last char has been processed */
- if (curr < 0) {
- break;
- }
- }
-
- /* on first round, skip */
- if (curr >= 0) {
- /* XXX: could add a fast path to process chunks of input codepoints,
- * but relative benefit would be quite small.
- */
-
- /* Ensure space for maximum multi-character result; estimate is overkill. */
- DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH);
-
- duk__case_transform_helper(thr,
- bw,
- (duk_codepoint_t) curr,
- prev,
- next,
- uppercase);
- }
- }
-
- DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1); /* invalidates h_buf pointer */
- duk_remove(ctx, -2);
-}
-
-#ifdef DUK_USE_REGEXP_SUPPORT
-
-/*
- * Canonicalize() abstract operation needed for canonicalization of individual
- * codepoints during regexp compilation and execution, see E5 Section 15.10.2.8.
- * Note that codepoints are canonicalized one character at a time, so no context
- * specific rules can apply. Locale specific rules can apply, though.
- */
-
-DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) {
-#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
- /* Fast canonicalization lookup at the cost of 128kB footprint. */
- DUK_ASSERT(cp >= 0);
- DUK_UNREF(thr);
- if (DUK_LIKELY(cp < 0x10000L)) {
- return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp];
- }
- return cp;
-#else /* DUK_USE_REGEXP_CANON_WORKAROUND */
- duk_codepoint_t y;
-
- y = duk__case_transform_helper(thr,
- NULL, /* NULL is allowed, no output */
- cp, /* curr char */
- -1, /* prev char */
- -1, /* next char */
- 1); /* uppercase */
-
- if ((y < 0) || (cp >= 0x80 && y < 0x80)) {
- /* multiple codepoint conversion or non-ASCII mapped to ASCII
- * --> leave as is.
- */
- return cp;
- }
-
- return y;
-#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */
-}
-
-/*
- * E5 Section 15.10.2.6 "IsWordChar" abstract operation. Assume
- * x < 0 for characters read outside the string.
- */
-
-DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) {
- /*
- * Note: the description in E5 Section 15.10.2.6 has a typo, it
- * contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_].
- */
- if ((x >= '0' && x <= '9') ||
- (x >= 'a' && x <= 'z') ||
- (x >= 'A' && x <= 'Z') ||
- (x == '_')) {
- return 1;
- }
- return 0;
-}
-
-/*
- * Regexp range tables
- */
-
-/* exposed because lexer needs these too */
-DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = {
- (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
-};
-DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = {
- (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL,
- (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL,
- (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL,
- (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL,
- (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL,
- (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL,
- (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL,
- (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL,
- (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL,
- (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL,
- (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL,
-};
-DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = {
- (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
- (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL,
- (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL,
- (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL,
-};
-DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = {
- (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
- (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL,
-};
-DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = {
- (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL,
- (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL,
- (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL,
- (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL,
- (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL,
- (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL,
- (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL,
- (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL,
- (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL,
- (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL,
- (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL,
- (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL,
-};
-DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
- (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
- (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL,
- (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL,
- (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL,
- (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL,
-};
-
-#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_util_misc.c"
-/*
- * Misc util stuff
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Lowercase digits for radix values 2 to 36. Also doubles as lowercase
- * hex nybble table.
- */
-
-DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = {
- DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
- DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
- DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B,
- DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F,
- DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J,
- DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N,
- DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R,
- DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V,
- DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z
-};
-
-DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = {
- DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
- DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
- DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B,
- DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F
-};
-
-/*
- * Table for hex decoding ASCII hex digits
- */
-
-DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = {
- /* -1 if invalid */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
-};
-
-#if defined(DUK_USE_HEX_FASTPATH)
-/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */
-DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
- 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
- -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
- -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
-};
-#endif
-
-/*
- * Table for hex encoding bytes
- */
-
-#if defined(DUK_USE_HEX_FASTPATH)
-/* Lookup to encode one byte directly into 2 characters:
- *
- * def genhextab(bswap):
- * for i in xrange(256):
- * t = chr(i).encode('hex')
- * if bswap:
- * t = t[1] + t[0]
- * print('0x' + t.encode('hex') + 'U')
- * print('big endian'); genhextab(False)
- * print('little endian'); genhextab(True)
-*/
-DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = {
-#if defined(DUK_USE_INTEGER_BE)
- 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U,
- 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U,
- 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U,
- 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U,
- 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U,
- 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U,
- 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U,
- 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U,
- 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U,
- 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U,
- 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U,
- 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U,
- 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U,
- 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U,
- 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U,
- 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U,
- 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U,
- 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U,
- 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U,
- 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U,
- 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U,
- 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U,
- 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U,
- 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U,
- 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U,
- 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U,
- 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U,
- 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U,
- 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U,
- 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U,
- 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U,
- 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U
-#else /* DUK_USE_INTEGER_BE */
- 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U,
- 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U,
- 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U,
- 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U,
- 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U,
- 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U,
- 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U,
- 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U,
- 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U,
- 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U,
- 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U,
- 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U,
- 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U,
- 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U,
- 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U,
- 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U,
- 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U,
- 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U,
- 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U,
- 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U,
- 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U,
- 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U,
- 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U,
- 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U,
- 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U,
- 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U,
- 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U,
- 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U,
- 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U,
- 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U,
- 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U,
- 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U
-#endif /* DUK_USE_INTEGER_BE */
-};
-#endif /* DUK_USE_HEX_FASTPATH */
-
-/*
- * Table for base-64 encoding
- */
-
-#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = {
- 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */
- 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */
- 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */
- 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */
-};
-#endif /* DUK_USE_BASE64_FASTPATH */
-
-/*
- * Table for base-64 decoding
- */
-
-#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = {
- /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */
- -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */
-};
-#endif /* DUK_USE_BASE64_FASTPATH */
-
-/*
- * Arbitrary byteswap for potentially unaligned values
- *
- * Used to byteswap pointers e.g. in debugger code.
- */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
-DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
- duk_uint8_t tmp;
- duk_uint8_t *q = p + len - 1;
-
- while (p - q < 0) {
- tmp = *p;
- *p = *q;
- *q = tmp;
- p++;
- q--;
- }
-}
-#endif
-#line 1 "duk_util_hashprime.c"
-/*
- * Round a number upwards to a prime (not usually the nearest one).
- *
- * Uses a table of successive 32-bit primes whose ratio is roughly
- * constant. This keeps the relative upwards 'rounding error' bounded
- * and the data size small. A simple 'predict-correct' compression is
- * used to compress primes to one byte per prime. See genhashsizes.py
- * for details.
- *
- * The minimum prime returned here must be coordinated with the possible
- * probe sequence steps in duk_hobject and duk_heap stringtable.
- */
-
-/* include removed: duk_internal.h */
-
-/* Awkward inclusion condition: drop out of compilation if not needed by any
- * call site: object hash part or probing stringtable.
- */
-#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
-
-/* hash size ratio goal, must match genhashsizes.py */
-#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */
-
-/* prediction corrections for prime list (see genhashsizes.py) */
-DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = {
- 17, /* minimum prime */
- 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3,
- 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5,
- 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29,
- 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12,
- 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30,
- 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41,
- 10, 23, 16, 9, 2,
- -1
-};
-
-/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long
- * (DUK_UTIL_GET_HASH_PROBE_STEP macro).
- */
-DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = {
- 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107,
- 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199
-};
-
-DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
- const duk_int8_t *p = duk__hash_size_corrections;
- duk_uint32_t curr;
-
- curr = (duk_uint32_t) *p++;
- for (;;) {
- duk_small_int_t t = (duk_small_int_t) *p++;
- if (t < 0) {
- /* may happen if size is very close to 2^32-1 */
- break;
- }
-
- /* prediction: portable variant using doubles if 64-bit values not available */
-#ifdef DUK_USE_64BIT_OPS
- curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10);
-#else
- /* 32-bit x 11-bit = 43-bit, fits accurately into a double */
- curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0);
-#endif
-
- /* correction */
- curr += t;
-
- DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr));
-
- if (curr >= size) {
- return curr;
- }
- }
- return 0;
-}
-
-#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */
-#line 1 "duk_hobject_class.c"
-/*
- * Hobject Ecmascript [[Class]].
- */
-
-/* include removed: duk_internal.h */
-
-#if (DUK_STRIDX_UC_ARGUMENTS > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_BOOLEAN > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_DATE > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_ERROR > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_FUNCTION > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_JSON > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_MATH > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_NUMBER > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_OBJECT > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_REG_EXP > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_STRING > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_GLOBAL > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_OBJ_ENV > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_DEC_ENV > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_BUFFER > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_POINTER > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UC_THREAD > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_ARRAY_BUFFER > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_DATA_VIEW > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_INT8_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UINT8_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_INT16_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UINT16_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_INT32_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_UINT32_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_FLOAT32_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_FLOAT64_ARRAY > 255)
-#error constant too large
-#endif
-#if (DUK_STRIDX_EMPTY_STRING > 255)
-#error constant too large
-#endif
-
-/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
-DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
- DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
- DUK_STRIDX_UC_ARGUMENTS,
- DUK_STRIDX_ARRAY,
- DUK_STRIDX_UC_BOOLEAN,
- DUK_STRIDX_DATE,
- DUK_STRIDX_UC_ERROR,
- DUK_STRIDX_UC_FUNCTION,
- DUK_STRIDX_JSON,
- DUK_STRIDX_MATH,
- DUK_STRIDX_UC_NUMBER,
- DUK_STRIDX_UC_OBJECT,
- DUK_STRIDX_REG_EXP,
- DUK_STRIDX_UC_STRING,
- DUK_STRIDX_GLOBAL,
- DUK_STRIDX_OBJ_ENV,
- DUK_STRIDX_DEC_ENV,
- DUK_STRIDX_UC_BUFFER,
- DUK_STRIDX_UC_POINTER,
- DUK_STRIDX_UC_THREAD,
- DUK_STRIDX_ARRAY_BUFFER,
- DUK_STRIDX_DATA_VIEW,
- DUK_STRIDX_INT8_ARRAY,
- DUK_STRIDX_UINT8_ARRAY,
- DUK_STRIDX_UINT8_CLAMPED_ARRAY,
- DUK_STRIDX_INT16_ARRAY,
- DUK_STRIDX_UINT16_ARRAY,
- DUK_STRIDX_INT32_ARRAY,
- DUK_STRIDX_UINT32_ARRAY,
- DUK_STRIDX_FLOAT32_ARRAY,
- DUK_STRIDX_FLOAT64_ARRAY,
- DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
- DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
-};
-#line 1 "duk_alloc_default.c"
-/*
- * Default allocation functions.
- *
- * Assumes behavior such as malloc allowing zero size, yielding
- * a NULL or a unique pointer which is a no-op for free.
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
-DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
- void *res;
- DUK_UNREF(udata);
- res = DUK_ANSI_MALLOC(size);
- DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p",
- (unsigned long) size, (void *) res));
- return res;
-}
-
-DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) {
- void *res;
- DUK_UNREF(udata);
- res = DUK_ANSI_REALLOC(ptr, newsize);
- DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p",
- (void *) ptr, (unsigned long) newsize, (void *) res));
- return res;
-}
-
-DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
- DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr));
- DUK_UNREF(udata);
- DUK_ANSI_FREE(ptr);
-}
-#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */
-#line 1 "duk_api_buffer.c"
-/*
- * Buffer
- */
-
-/* include removed: duk_internal.h */
-
-DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hbuffer_dynamic *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
- DUK_ASSERT(h != NULL);
-
- if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
- DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
- }
-
- /* maximum size check is handled by callee */
- duk_hbuffer_resize(thr, h, new_size);
-
- return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
-}
-
-DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hbuffer_dynamic *h;
- void *ptr;
- duk_size_t sz;
-
- DUK_ASSERT(ctx != NULL);
-
- h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, index);
- DUK_ASSERT(h != NULL);
-
- if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
- DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
- }
-
- /* Forget the previous allocation, setting size to 0 and alloc to
- * NULL. Caller is responsible for freeing the previous allocation.
- * Getting the allocation and clearing it is done in the same API
- * call to avoid any chance of a realloc.
- */
- ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
- sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h);
- if (out_size) {
- *out_size = sz;
- }
- DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h);
- DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0);
-
- return ptr;
-}
-
-DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hbuffer_external *h;
-
- DUK_ASSERT(ctx != NULL);
-
- h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, index);
- DUK_ASSERT(h != NULL);
-
- if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
- DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
- }
- DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
-
- DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr);
- DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len);
-}
-#line 1 "duk_api_bytecode.c"
-/*
- * Bytecode dump/load
- *
- * The bytecode load primitive is more important performance-wise than the
- * dump primitive.
- *
- * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be
- * memory safe for invalid arguments - caller beware! There's little point
- * in trying to achieve memory safety unless bytecode instructions are also
- * validated which is not easy to do with indirect register references etc.
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
-
-#define DUK__SER_MARKER 0xff
-#define DUK__SER_VERSION 0x00
-#define DUK__SER_STRING 0x00
-#define DUK__SER_NUMBER 0x01
-#define DUK__BYTECODE_INITIAL_ALLOC 256
-
-/*
- * Dump/load helpers, xxx_raw() helpers do no buffer checks
- */
-
-DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) {
- duk_uint32_t len;
-
- len = DUK_RAW_READ_U32_BE(p);
- duk_push_lstring(ctx, (const char *) p, len);
- p += len;
- return p;
-}
-
-DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) {
- duk_uint32_t len;
- duk_uint8_t *buf;
-
- len = DUK_RAW_READ_U32_BE(p);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- DUK_ASSERT(buf != NULL);
- DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len);
- p += len;
- return p;
-}
-
-DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) {
- duk_size_t len;
- duk_uint32_t tmp32;
-
- DUK_ASSERT(h != NULL);
-
- len = DUK_HSTRING_GET_BYTELEN(h);
- DUK_ASSERT(len <= 0xffffffffUL); /* string limits */
- tmp32 = (duk_uint32_t) len;
- DUK_RAW_WRITE_U32_BE(p, tmp32);
- DUK_MEMCPY((void *) p,
- (const void *) DUK_HSTRING_GET_DATA(h),
- len);
- p += len;
- return p;
-}
-
-DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) {
- duk_size_t len;
- duk_uint32_t tmp32;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(h != NULL);
- DUK_UNREF(thr);
-
- len = DUK_HBUFFER_GET_SIZE(h);
- DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */
- tmp32 = (duk_uint32_t) len;
- DUK_RAW_WRITE_U32_BE(p, tmp32);
- DUK_MEMCPY((void *) p,
- (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
- len);
- p += len;
- return p;
-}
-
-DUK_LOCAL duk_uint8_t *duk__dump_string_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) {
- duk_hstring *h_str;
- duk_tval *tv;
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
- if (tv != NULL && DUK_TVAL_IS_STRING(tv)) {
- h_str = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h_str != NULL);
- } else {
- h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
- DUK_ASSERT(h_str != NULL);
- }
- DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p);
- p = duk__dump_hstring_raw(p, h_str);
- return p;
-}
-
-DUK_LOCAL duk_uint8_t *duk__dump_buffer_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx) {
- duk_tval *tv;
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
- if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h_buf;
- h_buf = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h_buf != NULL);
- DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p);
- p = duk__dump_hbuffer_raw(thr, p, h_buf);
- } else {
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
- DUK_RAW_WRITE_U32_BE(p, 0);
- }
- return p;
-}
-
-DUK_LOCAL duk_uint8_t *duk__dump_uint32_prop(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func, duk_small_uint_t stridx, duk_uint32_t def_value) {
- duk_tval *tv;
- duk_uint32_t val;
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
- if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) {
- val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
- } else {
- val = def_value;
- }
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
- DUK_RAW_WRITE_U32_BE(p, val);
- return p;
-}
-
-DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
- duk_tval *tv;
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
- if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h;
- duk_uint_fast32_t i;
-
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- /* We know _Varmap only has own properties so walk property
- * table directly. We also know _Varmap is dense and all
- * values are numbers; assert for these. GC and finalizers
- * shouldn't affect _Varmap so side effects should be fine.
- */
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
- duk_hstring *key;
- duk_tval *tv_val;
- duk_uint32_t val;
-
- key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
- DUK_ASSERT(key != NULL); /* _Varmap is dense */
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i));
- tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i);
- DUK_ASSERT(tv_val != NULL);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */
-#if defined(DUK_USE_FASTINT)
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val));
- DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */
- val = DUK_TVAL_GET_FASTINT_U32(tv_val);
-#else
- val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val);
-#endif
-
- DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p);
- p = duk__dump_hstring_raw(p, key);
- DUK_RAW_WRITE_U32_BE(p, val);
- }
- }
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
- DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */
- return p;
-}
-
-DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
- duk_tval *tv;
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
- if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h;
- duk_uint_fast32_t i;
-
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- /* We know _Formals is dense and all entries will be in the
- * array part. GC and finalizers shouldn't affect _Formals
- * so side effects should be fine.
- */
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
- duk_tval *tv_val;
- duk_hstring *varname;
-
- tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i);
- DUK_ASSERT(tv_val != NULL);
- if (DUK_TVAL_IS_STRING(tv_val)) {
- /* Array is dense and contains only strings, but ASIZE may
- * be larger than used part and there are UNUSED entries.
- */
- varname = DUK_TVAL_GET_STRING(tv_val);
- DUK_ASSERT(varname != NULL);
-
- DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
- p = duk__dump_hstring_raw(p, varname);
- }
- }
- }
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
- DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */
- return p;
-}
-
-static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompiledfunction *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
- duk_hthread *thr;
- duk_tval *tv, *tv_end;
- duk_instr_t *ins, *ins_end;
- duk_hobject **fn, **fn_end;
- duk_hstring *h_str;
- duk_uint32_t count_instr;
- duk_uint32_t tmp32;
- duk_uint16_t tmp16;
- duk_double_t d;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(ctx);
- DUK_UNREF(thr);
-
- DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
- "consts=[%p,%p[ (%ld bytes, %ld items), "
- "funcs=[%p,%p[ (%ld bytes, %ld items), "
- "code=[%p,%p[ (%ld bytes, %ld items)",
- (void *) func,
- (void *) p,
- (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(thr->heap, func),
- (long) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func)));
-
- DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
- count_instr = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(thr->heap, func);
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p);
-
- /* Fixed header info. */
- tmp32 = count_instr;
- DUK_RAW_WRITE_U32_BE(p, tmp32);
- tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(thr->heap, func);
- DUK_RAW_WRITE_U32_BE(p, tmp32);
- tmp32 = (duk_uint32_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, func);
- DUK_RAW_WRITE_U32_BE(p, tmp32);
- tmp16 = func->nregs;
- DUK_RAW_WRITE_U16_BE(p, tmp16);
- tmp16 = func->nargs;
- DUK_RAW_WRITE_U16_BE(p, tmp16);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- tmp32 = func->start_line;
- DUK_RAW_WRITE_U32_BE(p, tmp32);
- tmp32 = func->end_line;
- DUK_RAW_WRITE_U32_BE(p, tmp32);
-#else
- DUK_RAW_WRITE_U32_BE(p, 0);
- DUK_RAW_WRITE_U32_BE(p, 0);
-#endif
- tmp32 = ((duk_heaphdr *) func)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK;
- DUK_RAW_WRITE_U32_BE(p, tmp32);
-
- /* Bytecode instructions: endian conversion needed unless
- * platform is big endian.
- */
- ins = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, func);
- ins_end = DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, func);
- DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
-#if defined(DUK_USE_INTEGER_BE)
- DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins));
- p += (size_t) (ins_end - ins);
-#else
- while (ins != ins_end) {
- tmp32 = (duk_uint32_t) (*ins);
- DUK_RAW_WRITE_U32_BE(p, tmp32);
- ins++;
- }
-#endif
-
- /* Constants: variable size encoding. */
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, func);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, func);
- while (tv != tv_end) {
- /* constants are strings or numbers now */
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
- DUK_TVAL_IS_NUMBER(tv));
-
- if (DUK_TVAL_IS_STRING(tv)) {
- h_str = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h_str != NULL);
- DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p),
- *p++ = DUK__SER_STRING;
- p = duk__dump_hstring_raw(p, h_str);
- } else {
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p);
- *p++ = DUK__SER_NUMBER;
- d = DUK_TVAL_GET_NUMBER(tv);
- DUK_RAW_WRITE_DOUBLE_BE(p, d);
- }
- tv++;
- }
-
- /* Inner functions recursively. */
- fn = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, func);
- fn_end = (duk_hobject **) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, func);
- while (fn != fn_end) {
- /* XXX: This causes recursion up to inner function depth
- * which is normally not an issue, e.g. mark-and-sweep uses
- * a recursion limiter to avoid C stack issues. Avoiding
- * this would mean some sort of a work list or just refusing
- * to serialize deep functions.
- */
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(*fn));
- p = duk__dump_func(ctx, (duk_hcompiledfunction *) *fn, bw_ctx, p);
- fn++;
- }
-
- /* Object extra properties.
- *
- * There are some difference between function templates and functions.
- * For example, function templates don't have .length and nargs is
- * normally used to instantiate the functions.
- */
-
- p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
- p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
- p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
- p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
- p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
- p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
-
- DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p));
-
- return p;
-}
-
-/* Load a function from bytecode. The function object returned here must
- * match what is created by duk_js_push_closure() with respect to its flags,
- * properties, etc.
- *
- * NOTE: there are intentionally no input buffer length / bound checks.
- * Adding them would be easy but wouldn't ensure memory safety as untrusted
- * or broken bytecode is unsafe during execution unless the opcodes themselves
- * are validated (which is quite complex, especially for indirect opcodes).
- */
-
-#define DUK__ASSERT_LEFT(n) do { \
- DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
- } while (0)
-
-static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) {
- duk_hthread *thr;
- duk_hcompiledfunction *h_fun;
- duk_hbuffer *h_data;
- duk_size_t data_size;
- duk_uint32_t count_instr, count_const, count_funcs;
- duk_uint32_t n;
- duk_uint32_t tmp32;
- duk_small_uint_t const_type;
- duk_uint8_t *fun_data;
- duk_uint8_t *q;
- duk_idx_t idx_base;
- duk_tval *tv1;
- duk_uarridx_t arr_idx;
-
- /* XXX: There's some overlap with duk_js_closure() here, but
- * seems difficult to share code. Ensure that the final function
- * looks the same as created by duk_js_closure().
- */
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
-
- DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
-
- DUK__ASSERT_LEFT(3 * 4);
- count_instr = DUK_RAW_READ_U32_BE(p);
- count_const = DUK_RAW_READ_U32_BE(p);
- count_funcs = DUK_RAW_READ_U32_BE(p);
-
- data_size = sizeof(duk_tval) * count_const +
- sizeof(duk_hobject *) * count_funcs +
- sizeof(duk_instr_t) * count_instr;
-
- DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld",
- (long) count_instr, (long) count_const,
- (long) count_const, (long) data_size));
-
- /* Value stack is used to ensure reachability of constants and
- * inner functions being loaded. Require enough space to handle
- * large functions correctly.
- */
- duk_require_stack(ctx, 2 + count_const + count_funcs);
- idx_base = duk_get_top(ctx);
-
- /* Push function object, init flags etc. This must match
- * duk_js_push_closure() quite carefully.
- */
- duk_push_compiledfunction(ctx);
- h_fun = duk_get_hcompiledfunction(ctx, -1);
- DUK_ASSERT(h_fun != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) h_fun));
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, h_fun) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, h_fun) == NULL);
-
- h_fun->nregs = DUK_RAW_READ_U16_BE(p);
- h_fun->nargs = DUK_RAW_READ_U16_BE(p);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- h_fun->start_line = DUK_RAW_READ_U32_BE(p);
- h_fun->end_line = DUK_RAW_READ_U32_BE(p);
-#else
- p += 8; /* skip line info */
-#endif
-
- /* duk_hcompiledfunction flags; quite version specific */
- tmp32 = DUK_RAW_READ_U32_BE(p);
- DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32);
-
- /* standard prototype */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
-
- /* assert just a few critical flags */
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&h_fun->obj));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
-
- /* Create function 'data' buffer but don't attach it yet. */
- fun_data = (duk_uint8_t *) duk_push_fixed_buffer(ctx, data_size);
- DUK_ASSERT(fun_data != NULL);
-
- /* Load bytecode instructions. */
- DUK_ASSERT(sizeof(duk_instr_t) == 4);
- DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t));
-#if defined(DUK_USE_INTEGER_BE)
- q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
- DUK_MEMCPY((void *) q,
- (const void *) p,
- sizeof(duk_instr_t) * count_instr);
- p += sizeof(duk_instr_t) * count_instr;
-#else
- q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
- for (n = count_instr; n > 0; n--) {
- *((duk_instr_t *) (void *) q) = DUK_RAW_READ_U32_BE(p);
- q += sizeof(duk_instr_t);
- }
-#endif
-
- /* Load constants onto value stack but don't yet copy to buffer. */
- for (n = count_const; n > 0; n--) {
- DUK__ASSERT_LEFT(1);
- const_type = DUK_RAW_READ_U8(p);
- switch (const_type) {
- case DUK__SER_STRING: {
- p = duk__load_string_raw(ctx, p);
- break;
- }
- case DUK__SER_NUMBER: {
- /* Important to do a fastint check so that constants are
- * properly read back as fastints.
- */
- duk_tval tv_tmp;
- duk_double_t val;
- DUK__ASSERT_LEFT(8);
- val = DUK_RAW_READ_DOUBLE_BE(p);
- DUK_TVAL_SET_NUMBER_CHKFAST(&tv_tmp, val);
- duk_push_tval(ctx, &tv_tmp);
- break;
- }
- default: {
- goto format_error;
- }
- }
- }
-
- /* Load inner functions to value stack, but don't yet copy to buffer. */
- for (n = count_funcs; n > 0; n--) {
- p = duk__load_func(ctx, p, p_end);
- if (p == NULL) {
- goto format_error;
- }
- }
-
- /* With constants and inner functions on value stack, we can now
- * atomically finish the function 'data' buffer, bump refcounts,
- * etc.
- *
- * Here we take advantage of the value stack being just a duk_tval
- * array: we can just memcpy() the constants as long as we incref
- * them afterwards.
- */
-
- h_data = (duk_hbuffer *) duk_get_hbuffer(ctx, idx_base + 1);
- DUK_ASSERT(h_data != NULL);
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
- DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_fun, h_data);
- DUK_HBUFFER_INCREF(thr, h_data);
-
- tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */
- DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
-
- q = fun_data;
- if (count_const > 0) {
- /* Explicit zero size check to avoid NULL 'tv1'. */
- DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
- for (n = count_const; n > 0; n--) {
- DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */
- q += sizeof(duk_tval);
- }
- tv1 += count_const;
- }
-
- DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
- for (n = count_funcs; n > 0; n--) {
- duk_hobject *h_obj;
-
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
- h_obj = DUK_TVAL_GET_OBJECT(tv1);
- DUK_ASSERT(h_obj != NULL);
- tv1++;
- DUK_HOBJECT_INCREF(thr, h_obj);
-
- *((duk_hobject **) (void *) q) = h_obj;
- q += sizeof(duk_hobject *);
- }
-
- DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
-
- /* The function object is now reachable and refcounts are fine,
- * so we can pop off all the temporaries.
- */
- DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base)));
- duk_set_top(ctx, idx_base + 1);
-
- /* Setup function properties. */
- tmp32 = DUK_RAW_READ_U32_BE(p);
- duk_push_u32(ctx, tmp32);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
-
- p = duk__load_string_raw(ctx, p);
- if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
- /* Original function instance/template had NAMEBINDING.
- * Must create a lexical environment on loading to allow
- * recursive functions like 'function foo() { foo(); }'.
- */
- duk_hobject *proto;
-
- proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- proto);
- duk_dup(ctx, -2); /* -> [ func funcname env funcname ] */
- duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
- duk_xdef_prop_stridx(ctx, idx_base, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
- /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
- * will be ignored anyway
- */
- }
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
-
- p = duk__load_string_raw(ctx, p);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
-
- duk_push_object(ctx);
- duk_dup(ctx, -2);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
-
- p = duk__load_buffer_raw(ctx, p);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
-
- duk_push_object(ctx); /* _Varmap */
- for (;;) {
- /* XXX: awkward */
- p = duk__load_string_raw(ctx, p);
- if (duk_get_length(ctx, -1) == 0) {
- duk_pop(ctx);
- break;
- }
- tmp32 = DUK_RAW_READ_U32_BE(p);
- duk_push_u32(ctx, tmp32);
- duk_put_prop(ctx, -3);
- }
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
-
- duk_push_array(ctx); /* _Formals */
- for (arr_idx = 0; ; arr_idx++) {
- /* XXX: awkward */
- p = duk__load_string_raw(ctx, p);
- if (duk_get_length(ctx, -1) == 0) {
- duk_pop(ctx);
- break;
- }
- duk_put_prop_index(ctx, -2, arr_idx);
- }
- duk_compact(ctx, -1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
-
- /* Return with final function pushed on stack top. */
- DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1)));
- DUK_ASSERT_TOP(ctx, idx_base + 1);
- return p;
-
- format_error:
- return NULL;
-}
-
-DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
- duk_hthread *thr;
- duk_hcompiledfunction *func;
- duk_bufwriter_ctx bw_ctx_alloc;
- duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
- duk_uint8_t *p;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
-
- /* Bound functions don't have all properties so we'd either need to
- * lookup the non-bound target function or reject bound functions.
- * For now, bound functions are rejected.
- */
- func = duk_require_hcompiledfunction(ctx, -1);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&func->obj));
-
- /* Estimating the result size beforehand would be costly, so
- * start with a reasonable size and extend as needed.
- */
- DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
- p = DUK_BW_GET_PTR(thr, bw_ctx);
- *p++ = DUK__SER_MARKER;
- *p++ = DUK__SER_VERSION;
- p = duk__dump_func(ctx, func, bw_ctx, p);
- DUK_BW_SET_PTR(thr, bw_ctx, p);
- DUK_BW_COMPACT(thr, bw_ctx);
-
- DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1)));
-
- duk_remove(ctx, -2); /* [ ... func buf ] -> [ ... buf ] */
-}
-
-DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
- duk_hthread *thr;
- duk_uint8_t *p_buf, *p, *p_end;
- duk_size_t sz;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(ctx);
-
- p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz);
- DUK_ASSERT(p_buf != NULL);
-
- /* The caller is responsible for being sure that bytecode being loaded
- * is valid and trusted. Invalid bytecode can cause memory unsafe
- * behavior directly during loading or later during bytecode execution
- * (instruction validation would be quite complex to implement).
- *
- * This signature check is the only sanity check for detecting
- * accidental invalid inputs. The initial 0xFF byte ensures no
- * ordinary string will be accepted by accident.
- */
- p = p_buf;
- p_end = p_buf + sz;
- if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) {
- goto format_error;
- }
- p += 2;
-
- p = duk__load_func(ctx, p, p_end);
- if (p == NULL) {
- goto format_error;
- }
-
- duk_remove(ctx, -2); /* [ ... buf func ] -> [ ... func ] */
- return;
-
- format_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
-}
-
-#undef DUK__SER_MARKER
-#undef DUK__SER_VERSION
-#undef DUK__SER_STRING
-#undef DUK__SER_NUMBER
-#undef DUK__BYTECODE_INITIAL_ALLOC
-
-#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
-
-DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
-}
-
-DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
- DUK_ERROR_UNSUPPORTED_DEFMSG((duk_hthread *) ctx);
-}
-
-#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
-#line 1 "duk_api_call.c"
-/*
- * Calls.
- *
- * Protected variants should avoid ever throwing an error.
- */
-
-/* include removed: duk_internal.h */
-
-/* Prepare value stack for a method call through an object property.
- * May currently throw an error e.g. when getting the property.
- */
-DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_index, duk_idx_t nargs) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_index=%ld, nargs=%ld, stacktop=%ld",
- (long) normalized_obj_index, (long) nargs, (long) duk_get_top(ctx)));
-
- /* [... key arg1 ... argN] */
-
- /* duplicate key */
- duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
- duk_get_prop(ctx, normalized_obj_index);
-
- DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* [... key arg1 ... argN func] */
-
- duk_replace(ctx, -nargs - 2);
-
- /* [... func arg1 ... argN] */
-
- duk_dup(ctx, normalized_obj_index);
- duk_insert(ctx, -nargs - 1);
-
- /* [... func this arg1 ... argN] */
-}
-
-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_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- idx_func = duk_get_top(ctx) - nargs - 1;
- if (idx_func < 0 || nargs < 0) {
- /* note that we can't reliably pop anything here */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
-
- /* XXX: awkward; we assume there is space for this, overwrite
- * directly instead?
- */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_func + 1);
-
- call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- 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_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* note that we can't reliably pop anything here */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
-
- call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- 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) {
- /*
- * XXX: if duk_handle_call() took values through indices, this could be
- * made much more sensible. However, duk_handle_call() needs to fudge
- * the 'this' and 'func' values to handle bound function chains, which
- * is now done "in-place", so this is not a trivial change.
- */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
-
- duk__call_prop_prep_stack(ctx, obj_index, nargs);
-
- duk_call_method(ctx, nargs);
-}
-
-DUK_EXTERNAL duk_int_t duk_pcall(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);
-
- idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* We can't reliably pop anything here because the stack input
- * shape is incorrect. So we throw an error; if the caller has
- * no catch point for this, a fatal error will occur. Another
- * alternative would be to just return an error. But then the
- * stack would be in an unknown state which might cause some
- * very hard to diagnose problems later on. Also note that even
- * if we did not throw an error here, the underlying call handler
- * might STILL throw an out-of-memory error or some other internal
- * fatal error.
- */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return DUK_EXEC_ERROR; /* unreachable */
- }
-
- /* awkward; we assume there is space for this */
- duk_push_undefined(ctx);
- duk_insert(ctx, idx_func + 1);
-
- call_flags = 0; /* respect reclimit, not constructor */
-
- rc = duk_handle_call_protected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- return rc;
-}
-
-DUK_EXTERNAL duk_int_t duk_pcall_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);
-
- idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
- if (idx_func < 0 || nargs < 0) {
- /* See comments in duk_pcall(). */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return DUK_EXEC_ERROR; /* unreachable */
- }
-
- call_flags = 0; /* respect reclimit, not constructor */
-
- rc = duk_handle_call_protected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- return rc;
-}
-
-DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx) {
- duk_idx_t obj_index;
- duk_idx_t nargs;
-
- /* Get the original arguments. Note that obj_index may be a relative
- * index so the stack must have the same top when we use it.
- */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = (duk_idx_t) duk_get_int(ctx, -2);
- nargs = (duk_idx_t) duk_get_int(ctx, -1);
- duk_pop_2(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index); /* make absolute */
- duk__call_prop_prep_stack(ctx, obj_index, nargs);
- duk_call_method(ctx, nargs);
- return 1;
-}
-
-DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs) {
- /*
- * Must be careful to catch errors related to value stack manipulation
- * and property lookup, not just the call itself.
- */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_push_idx(ctx, obj_index);
- duk_push_idx(ctx, nargs);
-
- /* Inputs: explicit arguments (nargs), +1 for key, +2 for obj_index/nargs passing.
- * If the value stack does not contain enough args, an error is thrown; this matches
- * behavior of the other protected call API functions.
- */
- return duk_safe_call(ctx, duk__pcall_prop_raw, nargs + 1 + 2 /*nargs*/, 1 /*nrets*/);
-}
-
-DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_int_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- if (duk_get_top(ctx) < nargs || nrets < 0) {
- /* See comments in duk_pcall(). */
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return DUK_EXEC_ERROR; /* unreachable */
- }
-
- rc = duk_handle_safe_call(thr, /* thread */
- func, /* func */
- nargs, /* num_stack_args */
- nrets); /* num_stack_res */
-
- return rc;
-}
-
-DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
- /*
- * There are two [[Construct]] operations in the specification:
- *
- * - E5 Section 13.2.2: for Function objects
- * - E5 Section 15.3.4.5.2: for "bound" Function objects
- *
- * The chain of bound functions is resolved in Section 15.3.4.5.2,
- * with arguments "piling up" until the [[Construct]] internal
- * method is called on the final, actual Function object. Note
- * that the "prototype" property is looked up *only* from the
- * final object, *before* calling the constructor.
- *
- * Currently we follow the bound function chain here to get the
- * "prototype" property value from the final, non-bound function.
- * However, we let duk_handle_call() handle the argument "piling"
- * when the constructor is called. The bound function chain is
- * thus now processed twice.
- *
- * When constructing new Array instances, an unnecessary object is
- * created and discarded now: the standard [[Construct]] creates an
- * object, and calls the Array constructor. The Array constructor
- * returns an Array instance, which is used as the result value for
- * the "new" operation; the object created before the Array constructor
- * call is discarded.
- *
- * This would be easy to fix, e.g. by knowing that the Array constructor
- * will always create a replacement object and skip creating the fallback
- * object in that case.
- *
- * Note: functions called via "new" need to know they are called as a
- * constructor. For instance, built-in constructors behave differently
- * depending on how they are called.
- */
-
- /* XXX: merge this with duk_js_call.c, as this function implements
- * core semantics (or perhaps merge the two files altogether).
- */
-
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *proto;
- duk_hobject *cons;
- duk_hobject *fallback;
- duk_idx_t idx_cons;
- duk_small_uint_t call_flags;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* [... constructor arg1 ... argN] */
-
- idx_cons = duk_require_normalize_index(ctx, -nargs - 1);
-
- DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
- (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));
-
- /* XXX: code duplication */
-
- /*
- * Figure out the final, non-bound constructor, to get "prototype"
- * property.
- */
-
- duk_dup(ctx, idx_cons);
- for (;;) {
- cons = duk_get_hobject(ctx, -1);
- if (cons == NULL || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
- /* Checking constructability from anything else than the
- * initial constructor is not strictly necessary, but a
- * nice sanity check.
- */
- goto not_constructable;
- }
- if (!DUK_HOBJECT_HAS_BOUND(cons)) {
- break;
- }
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */
- duk_remove(ctx, -2); /* -> [... target] */
- }
- DUK_ASSERT(cons != NULL && !DUK_HOBJECT_HAS_BOUND(cons));
-
- /* [... constructor arg1 ... argN final_cons] */
-
- /*
- * Create "fallback" object to be used as the object instance,
- * unless the constructor returns a replacement value.
- * Its internal prototype needs to be set based on "prototype"
- * property of the constructor.
- */
-
- duk_push_object(ctx); /* class Object, extensible */
-
- /* [... constructor arg1 ... argN final_cons fallback] */
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE);
- proto = duk_get_hobject(ctx, -1);
- if (!proto) {
- DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
- "-> leave standard Object prototype as fallback prototype"));
- } else {
- DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
- "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
- fallback = duk_get_hobject(ctx, -2);
- DUK_ASSERT(fallback != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
- }
- duk_pop(ctx);
-
- /* [... constructor arg1 ... argN final_cons fallback] */
-
- /*
- * Manipulate callstack for the call.
- */
-
- duk_dup_top(ctx);
- duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */
- duk_insert(ctx, idx_cons); /* also stash it before constructor,
- * in case we need it (as the fallback value)
- */
- duk_pop(ctx); /* pop final_cons */
-
-
- /* [... fallback constructor fallback(this) arg1 ... argN];
- * Note: idx_cons points to first 'fallback', not 'constructor'.
- */
-
- DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
- "nargs=%ld, top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
- (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
- (long) nargs,
- (long) duk_get_top(ctx)));
-
- /*
- * Call the constructor function (called in "constructor mode").
- */
-
- call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
-
- duk_handle_call_unprotected(thr, /* thread */
- nargs, /* num_stack_args */
- call_flags); /* call_flags */
-
- /* [... fallback retval] */
-
- 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)));
-
- /*
- * Determine whether to use the constructor return value as the created
- * object instance or not.
- */
-
- if (duk_is_object(ctx, -1)) {
- duk_remove(ctx, -2);
- } else {
- duk_pop(ctx);
- }
-
- /*
- * Augment created errors upon creation (not when they are thrown or
- * rethrown). __FILE__ and __LINE__ are not desirable here; the call
- * stack reflects the caller which is correct.
- */
-
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- duk_hthread_sync_currpc(thr);
- duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
-#endif
-
- /* [... retval] */
-
- return;
-
- not_constructable:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONSTRUCTABLE);
-}
-
-DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx) {
- duk_uint_t nargs;
-
- nargs = duk_to_uint(ctx, -1);
- duk_pop(ctx);
-
- duk_new(ctx, nargs);
- return 1;
-}
-
-DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) {
- duk_int_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* For now, just use duk_safe_call() to wrap duk_new(). We can't
- * simply use a protected duk_handle_call() because there's post
- * processing which might throw. It should be possible to ensure
- * the post processing never throws (except in internal errors and
- * out of memory etc which are always allowed) and then remove this
- * wrapper.
- */
-
- duk_push_uint(ctx, nargs);
- rc = duk_safe_call(ctx, duk__pnew_helper, nargs + 2 /*nargs*/, 1 /*nrets*/);
- return rc;
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
-
- act = duk_hthread_get_current_activation(thr);
- DUK_ASSERT(act != NULL); /* because callstack_top > 0 */
- return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
-
- /* For user code this could just return 1 (strict) always
- * because all Duktape/C functions are considered strict,
- * and strict is also the default when nothing is running.
- * However, Duktape may call this function internally when
- * the current activation is an Ecmascript function, so
- * this cannot be replaced by a 'return 1' without fixing
- * the internal call sites.
- */
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
-
- act = duk_hthread_get_current_activation(thr);
- if (act == NULL) {
- /* Strict by default. */
- return 1;
- }
- return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
-}
-
-/*
- * Duktape/C function magic
- */
-
-DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_hobject *func;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
-
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- func = DUK_ACT_GET_FUNC(act);
- if (!func) {
- duk_tval *tv = &act->tv_func;
- duk_small_uint_t lf_flags;
- lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
- return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
- }
- DUK_ASSERT(func != NULL);
-
- if (DUK_HOBJECT_IS_NATIVEFUNCTION(func)) {
- duk_hnativefunction *nf = (duk_hnativefunction *) func;
- return (duk_int_t) nf->magic;
- }
- }
- return 0;
-}
-
-DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_hobject *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
- goto type_error;
- }
- return (duk_int_t) ((duk_hnativefunction *) h)->magic;
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
- return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
- }
-
- /* fall through */
- type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
- return 0;
-}
-
-DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic) {
- duk_hnativefunction *nf;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- nf = duk_require_hnativefunction(ctx, index);
- DUK_ASSERT(nf != NULL);
- nf->magic = (duk_int16_t) magic;
-}
-#line 1 "duk_api_codec.c"
-/*
- * Encoding and decoding basic formats: hex, base64.
- *
- * These are in-place operations which may allow an optimized implementation.
- *
- * Base-64: https://tools.ietf.org/html/rfc4648#section-4
- */
-
-/* include removed: duk_internal.h */
-
-/* Shared handling for encode/decode argument. Fast path handling for
- * buffer and string values because they're the most common. In particular,
- * avoid creating a temporary string or buffer when possible.
- */
-DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT(duk_is_valid_index(ctx, index)); /* checked by caller */
- if (duk_is_buffer(ctx, index)) {
- return (const duk_uint8_t *) duk_get_buffer(ctx, index, out_len);
- } else {
- return (const duk_uint8_t *) duk_to_lstring(ctx, index, out_len);
- }
-}
-
-#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
- duk_uint_t t;
- duk_size_t n_full, n_full3, n_final;
- const duk_uint8_t *src_end_fast;
-
- n_full = srclen / 3; /* full 3-byte -> 4-char conversions */
- n_full3 = n_full * 3;
- n_final = srclen - n_full3;
- DUK_ASSERT_DISABLE(n_final >= 0);
- DUK_ASSERT(n_final <= 2);
-
- src_end_fast = src + n_full3;
- while (DUK_UNLIKELY(src != src_end_fast)) {
- t = (duk_uint_t) (*src++);
- t = (t << 8) + (duk_uint_t) (*src++);
- t = (t << 8) + (duk_uint_t) (*src++);
-
- *dst++ = duk_base64_enctab[t >> 18];
- *dst++ = duk_base64_enctab[(t >> 12) & 0x3f];
- *dst++ = duk_base64_enctab[(t >> 6) & 0x3f];
- *dst++ = duk_base64_enctab[t & 0x3f];
-
-#if 0 /* Tested: not faster on x64 */
- /* aaaaaabb bbbbcccc ccdddddd */
- dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f];
- dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)];
- dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)];
- dst[3] = duk_base64_enctab[src[2] & 0x3f];
- src += 3; dst += 4;
-#endif
- }
-
- switch (n_final) {
- /* case 0: nop */
- case 1: {
- /* XX== */
- t = (duk_uint_t) (*src++);
- *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */
- *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */
- *dst++ = DUK_ASC_EQUALS;
- *dst++ = DUK_ASC_EQUALS;
- break;
- }
- case 2: {
- /* XXX= */
- t = (duk_uint_t) (*src++);
- t = (t << 8) + (duk_uint_t) (*src++);
- *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */
- *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */
- *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */
- *dst++ = DUK_ASC_EQUALS;
- break;
- }
- }
-}
-#else /* DUK_USE_BASE64_FASTPATH */
-DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
- duk_small_uint_t i, snip;
- duk_uint_t t;
- duk_uint_fast8_t x, y;
- const duk_uint8_t *src_end;
-
- src_end = src + srclen;
-
- while (src < src_end) {
- /* read 3 bytes into 't', padded by zero */
- snip = 4;
- t = 0;
- for (i = 0; i < 3; i++) {
- t = t << 8;
- if (src >= src_end) {
- snip--;
- } else {
- t += (duk_uint_t) (*src++);
- }
- }
-
- /*
- * Missing bytes snip base64 example
- * 0 4 XXXX
- * 1 3 XXX=
- * 2 2 XX==
- */
-
- DUK_ASSERT(snip >= 2 && snip <= 4);
-
- for (i = 0; i < 4; i++) {
- x = (duk_uint_fast8_t) ((t >> 18) & 0x3f);
- t = t << 6;
-
- /* A straightforward 64-byte lookup would be faster
- * and cleaner, but this is shorter.
- */
- if (i >= snip) {
- y = '=';
- } else if (x <= 25) {
- y = x + 'A';
- } else if (x <= 51) {
- y = x - 26 + 'a';
- } else if (x <= 61) {
- y = x - 52 + '0';
- } else if (x == 62) {
- y = '+';
- } else {
- y = '/';
- }
-
- *dst++ = (duk_uint8_t) y;
- }
- }
-}
-#endif /* DUK_USE_BASE64_FASTPATH */
-
-#if defined(DUK_USE_BASE64_FASTPATH)
-DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) {
- duk_int_t x;
- duk_int_t t;
- duk_small_uint_t n_equal;
- duk_small_uint_t n_chars;
- const duk_uint8_t *src_end;
- const duk_uint8_t *src_end_safe;
-
- src_end = src + srclen;
- src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */
-
- /* Innermost fast path processes 4 valid base-64 characters at a time
- * but bails out on whitespace, padding chars ('=') and invalid chars.
- * Once the slow path segment has been processed, we return to the
- * inner fast path again. This handles e.g. base64 with newlines
- * reasonably well because the majority of a line is in the fast path.
- */
- for (;;) {
- /* Fast path, handle units with just actual encoding characters. */
-
- while (src <= src_end_safe) {
- /* The lookup byte is intentionally sign extended to (at least)
- * 32 bits and then ORed. This ensures that is at least 1 byte
- * is negative, the highest bit of 't' will be set at the end
- * and we don't need to check every byte.
- */
- DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p",
- (const void *) src, (const void *) src_end_safe, (const void *) src_end));
-
- t = (duk_int_t) duk_base64_dectab[*src++];
- t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
- t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
- t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
-
- if (DUK_UNLIKELY(t < 0)) {
- DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit"));
- src -= 4;
- break;
- }
-
- DUK_ASSERT(t <= 0xffffffL);
- DUK_ASSERT((t >> 24) == 0);
- *dst++ = (duk_uint8_t) (t >> 16);
- *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
- *dst++ = (duk_uint8_t) (t & 0xff);
- }
-
- /* Handle one slow path unit (or finish if we're done). */
-
- n_equal = 0;
- n_chars = 0;
- t = 0;
- for (;;) {
- DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld",
- (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t));
-
- if (DUK_UNLIKELY(src >= src_end)) {
- goto done; /* two level break */
- }
-
- x = duk_base64_dectab[*src++];
- if (DUK_UNLIKELY(x < 0)) {
- if (x == -2) {
- continue; /* allowed ascii whitespace */
- } else if (x == -3) {
- n_equal++;
- t <<= 6;
- } else {
- DUK_ASSERT(x == -1);
- goto error;
- }
- } else {
- DUK_ASSERT(x >= 0 && x <= 63);
- if (n_equal > 0) {
- /* Don't allow actual chars after equal sign. */
- goto error;
- }
- t = (t << 6) + x;
- }
-
- if (DUK_UNLIKELY(n_chars == 3)) {
- /* Emit 3 bytes and backtrack if there was padding. There's
- * always space for the whole 3 bytes so no check needed.
- */
- DUK_ASSERT(t <= 0xffffffL);
- DUK_ASSERT((t >> 24) == 0);
- *dst++ = (duk_uint8_t) (t >> 16);
- *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
- *dst++ = (duk_uint8_t) (t & 0xff);
-
- if (DUK_UNLIKELY(n_equal > 0)) {
- DUK_ASSERT(n_equal <= 4);
-
- /* There may be whitespace between the equal signs. */
- if (n_equal == 1) {
- /* XXX= */
- dst -= 1;
- } else if (n_equal == 2) {
- /* XX== */
- dst -= 2;
- } else {
- goto error; /* invalid padding */
- }
-
- /* Continue parsing after padding, allows concatenated,
- * padded base64.
- */
- }
- break; /* back to fast loop */
- } else {
- n_chars++;
- }
- }
- }
- done:
- DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld",
- (const void *) src, (const void *) src_end, (long) n_chars));
-
- DUK_ASSERT(src == src_end);
-
- if (n_chars != 0) {
- /* Here we'd have the option of decoding unpadded base64
- * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
- * accepted.
- */
- goto error;
- }
-
- *out_dst_final = dst;
- return 1;
-
- error:
- return 0;
-}
-#else /* DUK_USE_BASE64_FASTPATH */
-DUK_LOCAL duk_bool_t duk__base64_decode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst, duk_uint8_t **out_dst_final) {
- duk_uint_t t;
- duk_uint_fast8_t x, y;
- duk_small_uint_t group_idx;
- duk_small_uint_t n_equal;
- const duk_uint8_t *src_end;
-
- src_end = src + srclen;
- t = 0;
- group_idx = 0;
- n_equal = 0;
-
- while (src < src_end) {
- x = *src++;
-
- if (x >= 'A' && x <= 'Z') {
- y = x - 'A' + 0;
- } else if (x >= 'a' && x <= 'z') {
- y = x - 'a' + 26;
- } else if (x >= '0' && x <= '9') {
- y = x - '0' + 52;
- } else if (x == '+') {
- y = 62;
- } else if (x == '/') {
- y = 63;
- } else if (x == '=') {
- /* We don't check the zero padding bytes here right now
- * (that they're actually zero). This seems to be common
- * behavior for base-64 decoders.
- */
-
- n_equal++;
- t <<= 6; /* shift in zeroes */
- goto skip_add;
- } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) {
- /* allow basic ASCII whitespace */
- continue;
- } else {
- goto error;
- }
-
- if (n_equal > 0) {
- /* Don't allow mixed padding and actual chars. */
- goto error;
- }
- t = (t << 6) + y;
- skip_add:
-
- if (group_idx == 3) {
- /* output 3 bytes from 't' */
- *dst++ = (duk_uint8_t) ((t >> 16) & 0xff);
- *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
- *dst++ = (duk_uint8_t) (t & 0xff);
-
- if (DUK_UNLIKELY(n_equal > 0)) {
- /* Backtrack. */
- DUK_ASSERT(n_equal <= 4);
- if (n_equal == 1) {
- dst -= 1;
- } else if (n_equal == 2) {
- dst -= 2;
- } else {
- goto error; /* invalid padding */
- }
-
- /* Here we can choose either to end parsing and ignore
- * whatever follows, or to continue parsing in case
- * multiple (possibly padded) base64 strings have been
- * concatenated. Currently, keep on parsing.
- */
- n_equal = 0;
- }
-
- t = 0;
- group_idx = 0;
- } else {
- group_idx++;
- }
- }
-
- if (group_idx != 0) {
- /* Here we'd have the option of decoding unpadded base64
- * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
- * accepted.
- */
- goto error;
- }
-
- *out_dst_final = dst;
- return 1;
-
- error:
- return 0;
-}
-#endif /* DUK_USE_BASE64_FASTPATH */
-
-DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- const duk_uint8_t *src;
- duk_size_t srclen;
- duk_size_t dstlen;
- duk_uint8_t *dst;
- const char *ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* XXX: optimize for string inputs: no need to coerce to a buffer
- * which makes a copy of the input.
- */
-
- index = duk_require_normalize_index(ctx, index);
- src = duk__prep_codec_arg(ctx, index, &srclen);
- /* Note: for srclen=0, src may be NULL */
-
- /* Computation must not wrap; this limit works for 32-bit size_t:
- * >>> srclen = 3221225469
- * >>> '%x' % ((srclen + 2) / 3 * 4)
- * 'fffffffc'
- */
- if (srclen > 3221225469UL) {
- goto type_error;
- }
- dstlen = (srclen + 2) / 3 * 4;
- dst = (duk_uint8_t *) duk_push_fixed_buffer(ctx, dstlen);
-
- duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
-
- ret = duk_to_string(ctx, -1);
- duk_replace(ctx, index);
- return ret;
-
- type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED);
- return NULL; /* never here */
-}
-
-DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- const duk_uint8_t *src;
- duk_size_t srclen;
- duk_size_t dstlen;
- duk_uint8_t *dst;
- duk_uint8_t *dst_final;
- duk_bool_t retval;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* XXX: optimize for buffer inputs: no need to coerce to a string
- * which causes an unnecessary interning.
- */
-
- index = duk_require_normalize_index(ctx, index);
- src = duk__prep_codec_arg(ctx, index, &srclen);
-
- /* Computation must not wrap, only srclen + 3 is at risk of
- * wrapping because after that the number gets smaller.
- * This limit works for 32-bit size_t:
- * 0x100000000 - 3 - 1 = 4294967292
- */
- if (srclen > 4294967292UL) {
- goto type_error;
- }
- dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
- dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen);
- /* Note: for dstlen=0, dst may be NULL */
-
- retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
- if (!retval) {
- goto type_error;
- }
-
- /* XXX: convert to fixed buffer? */
- (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst));
- duk_replace(ctx, index);
- return;
-
- type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
-}
-
-DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index) {
- const duk_uint8_t *inp;
- duk_size_t len;
- duk_size_t i;
- duk_uint8_t *buf;
- const char *ret;
-#if defined(DUK_USE_HEX_FASTPATH)
- duk_size_t len_safe;
- duk_uint16_t *p16;
-#endif
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_require_normalize_index(ctx, index);
- inp = duk__prep_codec_arg(ctx, index, &len);
- DUK_ASSERT(inp != NULL || len == 0);
-
- /* Fixed buffer, no zeroing because we'll fill all the data. */
- buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len * 2, DUK_BUF_FLAG_NOZERO /*flags*/);
- DUK_ASSERT(buf != NULL);
-
-#if defined(DUK_USE_HEX_FASTPATH)
- DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */
- p16 = (duk_uint16_t *) (void *) buf;
- len_safe = len & ~0x03U;
- for (i = 0; i < len_safe; i += 4) {
- p16[0] = duk_hex_enctab[inp[i]];
- p16[1] = duk_hex_enctab[inp[i + 1]];
- p16[2] = duk_hex_enctab[inp[i + 2]];
- p16[3] = duk_hex_enctab[inp[i + 3]];
- p16 += 4;
- }
- for (; i < len; i++) {
- *p16++ = duk_hex_enctab[inp[i]];
- }
-#else /* DUK_USE_HEX_FASTPATH */
- for (i = 0; i < len; i++) {
- duk_small_uint_t t;
- t = (duk_small_uint_t) inp[i];
- buf[i*2 + 0] = duk_lc_digits[t >> 4];
- buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
- }
-#endif /* DUK_USE_HEX_FASTPATH */
-
- /* XXX: Using a string return value forces a string intern which is
- * not always necessary. As a rough performance measure, hex encode
- * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s
- * without string coercion. Change to returning a buffer and let the
- * caller coerce to string if necessary?
- */
-
- ret = duk_to_string(ctx, -1);
- duk_replace(ctx, index);
- return ret;
-}
-
-DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- const duk_uint8_t *inp;
- duk_size_t len;
- duk_size_t i;
- duk_int_t t;
- duk_uint8_t *buf;
-#if defined(DUK_USE_HEX_FASTPATH)
- duk_int_t chk;
- duk_uint8_t *p;
- duk_size_t len_safe;
-#endif
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_require_normalize_index(ctx, index);
- inp = duk__prep_codec_arg(ctx, index, &len);
- DUK_ASSERT(inp != NULL || len == 0);
-
- if (len & 0x01) {
- goto type_error;
- }
-
- /* Fixed buffer, no zeroing because we'll fill all the data. */
- buf = (duk_uint8_t *) duk_push_buffer_raw(ctx, len / 2, DUK_BUF_FLAG_NOZERO /*flags*/);
- DUK_ASSERT(buf != NULL);
-
-#if defined(DUK_USE_HEX_FASTPATH)
- p = buf;
- len_safe = len & ~0x07U;
- for (i = 0; i < len_safe; i += 8) {
- t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) |
- ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
- chk = t;
- p[0] = (duk_uint8_t) t;
- t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) |
- ((duk_int_t) duk_hex_dectab[inp[i + 3]]);
- chk |= t;
- p[1] = (duk_uint8_t) t;
- t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) |
- ((duk_int_t) duk_hex_dectab[inp[i + 5]]);
- chk |= t;
- p[2] = (duk_uint8_t) t;
- t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) |
- ((duk_int_t) duk_hex_dectab[inp[i + 7]]);
- chk |= t;
- p[3] = (duk_uint8_t) t;
- p += 4;
-
- /* Check if any lookup above had a negative result. */
- if (DUK_UNLIKELY(chk < 0)) {
- goto type_error;
- }
- }
- for (; i < len; i += 2) {
- t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
- ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
- if (DUK_UNLIKELY(t < 0)) {
- goto type_error;
- }
- *p++ = (duk_uint8_t) t;
- }
-#else /* DUK_USE_HEX_FASTPATH */
- for (i = 0; i < len; i += 2) {
- /* For invalid characters the value -1 gets extended to
- * at least 16 bits. If either nybble is invalid, the
- * resulting 't' will be < 0.
- */
- t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
- ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
- if (DUK_UNLIKELY(t < 0)) {
- goto type_error;
- }
- buf[i >> 1] = (duk_uint8_t) t;
- }
-#endif /* DUK_USE_HEX_FASTPATH */
-
- duk_replace(ctx, index);
- return;
-
- type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
-}
-
-DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t index) {
-#ifdef DUK_USE_ASSERTIONS
- duk_idx_t top_at_entry;
-#endif
- const char *ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-#ifdef DUK_USE_ASSERTIONS
- top_at_entry = duk_get_top(ctx);
-#endif
-
- index = duk_require_normalize_index(ctx, index);
- duk_bi_json_stringify_helper(ctx,
- index /*idx_value*/,
- DUK_INVALID_INDEX /*idx_replacer*/,
- DUK_INVALID_INDEX /*idx_space*/,
- 0 /*flags*/);
- DUK_ASSERT(duk_is_string(ctx, -1));
- duk_replace(ctx, index);
- ret = duk_get_string(ctx, index);
-
- DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
-
- return ret;
-}
-
-DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t index) {
-#ifdef DUK_USE_ASSERTIONS
- duk_idx_t top_at_entry;
-#endif
-
- DUK_ASSERT_CTX_VALID(ctx);
-#ifdef DUK_USE_ASSERTIONS
- top_at_entry = duk_get_top(ctx);
-#endif
-
- index = duk_require_normalize_index(ctx, index);
- duk_bi_json_parse_helper(ctx,
- index /*idx_value*/,
- DUK_INVALID_INDEX /*idx_reviver*/,
- 0 /*flags*/);
- duk_replace(ctx, index);
-
- DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
-}
-#line 1 "duk_api_compile.c"
-/*
- * Compilation and evaluation
- */
-
-/* include removed: duk_internal.h */
-
-typedef struct duk__compile_raw_args duk__compile_raw_args;
-struct duk__compile_raw_args {
- duk_size_t src_length; /* should be first on 64-bit platforms */
- const duk_uint8_t *src_buffer;
- duk_uint_t flags;
-};
-
-/* Eval is just a wrapper now. */
-DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
- duk_uint_t comp_flags;
- duk_int_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Note: strictness is *not* inherited from the current Duktape/C.
- * This would be confusing because the current strictness state
- * depends on whether we're running inside a Duktape/C activation
- * (= strict mode) or outside of any activation (= non-strict mode).
- * See tests/api/test-eval-strictness.c for more discussion.
- */
-
- /* [ ... source? filename? ] (depends on flags) */
-
- comp_flags = flags;
- comp_flags |= DUK_COMPILE_EVAL;
- rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */
-
- /* [ ... closure/error ] */
-
- if (rc != DUK_EXEC_SUCCESS) {
- rc = DUK_EXEC_ERROR;
- goto got_rc;
- }
-
- duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */
-
- if (flags & DUK_COMPILE_SAFE) {
- rc = duk_pcall_method(ctx, 0);
- } else {
- duk_call_method(ctx, 0);
- rc = DUK_EXEC_SUCCESS;
- }
-
- /* [ ... result/error ] */
-
- got_rc:
- if (flags & DUK_COMPILE_NORESULT) {
- duk_pop(ctx);
- }
-
- return rc;
-}
-
-/* Helper which can be called both directly and with duk_safe_call(). */
-DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk__compile_raw_args *comp_args;
- duk_uint_t flags;
- duk_small_uint_t comp_flags;
- duk_hcompiledfunction *h_templ;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Note: strictness is not inherited from the current Duktape/C
- * context. Otherwise it would not be possible to compile
- * non-strict code inside a Duktape/C activation (which is
- * always strict now). See tests/api/test-eval-strictness.c
- * for discussion.
- */
-
- /* [ ... source? filename? &comp_args ] (depends on flags) */
-
- comp_args = (duk__compile_raw_args *) duk_require_pointer(ctx, -1);
- flags = comp_args->flags;
- duk_pop(ctx);
-
- /* [ ... source? filename? ] */
-
- if (flags & DUK_COMPILE_NOFILENAME) {
- /* Automatic filename: 'eval' or 'input'. */
- duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
- }
-
- /* [ ... source? filename ] */
-
- if (!comp_args->src_buffer) {
- duk_hstring *h_sourcecode;
-
- h_sourcecode = duk_get_hstring(ctx, -2);
- if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
- (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
- /* XXX: when this error is caused by a nonexistent
- * file given to duk_peval_file() or similar, the
- * error message is not the best possible.
- */
- DUK_ERROR_API(thr, DUK_STR_NO_SOURCECODE);
- }
- DUK_ASSERT(h_sourcecode != NULL);
- comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
- comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
- }
- DUK_ASSERT(comp_args->src_buffer != NULL);
-
- /* XXX: unnecessary translation of flags */
- comp_flags = 0;
- if (flags & DUK_COMPILE_EVAL) {
- comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
- }
- if (flags & DUK_COMPILE_FUNCTION) {
- comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
- DUK_JS_COMPILE_FLAG_FUNCEXPR;
- }
- if (flags & DUK_COMPILE_STRICT) {
- comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
- }
-
- /* [ ... source? filename ] */
-
- duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);
-
- /* [ ... source? func_template ] */
-
- if (flags & DUK_COMPILE_NOSOURCE) {
- ;
- } else {
- duk_remove(ctx, -2);
- }
-
- /* [ ... func_template ] */
-
- h_templ = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_templ != NULL);
- duk_js_push_closure(thr,
- h_templ,
- thr->builtins[DUK_BIDX_GLOBAL_ENV],
- thr->builtins[DUK_BIDX_GLOBAL_ENV],
- 1 /*add_auto_proto*/);
- duk_remove(ctx, -2); /* -> [ ... closure ] */
-
- /* [ ... closure ] */
-
- return 1;
-}
-
-DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
- duk__compile_raw_args comp_args_alloc;
- duk__compile_raw_args *comp_args = &comp_args_alloc;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
- /* String length is computed here to avoid multiple evaluation
- * of a macro argument in the calling side.
- */
- src_length = DUK_STRLEN(src_buffer);
- }
-
- comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
- comp_args->src_length = src_length;
- comp_args->flags = flags;
- duk_push_pointer(ctx, (void *) comp_args);
-
- /* [ ... source? filename? &comp_args ] (depends on flags) */
-
- if (flags & DUK_COMPILE_SAFE) {
- duk_int_t rc;
- duk_int_t nargs;
- duk_int_t nrets = 1;
-
- /* Arguments can be: [ source? filename? &comp_args] so that
- * nargs is 1 to 3. Call site encodes the correct nargs count
- * directly into flags.
- */
- nargs = flags & 0x07;
- DUK_ASSERT(nargs == (1 +
- ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
- ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1)));
- rc = duk_safe_call(ctx, duk__do_compile, nargs, nrets);
-
- /* [ ... closure ] */
- return rc;
- }
-
- (void) duk__do_compile(ctx);
-
- /* [ ... closure ] */
- return DUK_EXEC_SUCCESS;
-}
-#line 1 "duk_api_debug.c"
-/*
- * Debugging related API calls
- */
-
-/* include removed: duk_internal.h */
-
-DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
- duk_idx_t idx;
- duk_idx_t top;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* We don't duk_require_stack() here now, but rely on the caller having
- * enough space.
- */
-
- top = duk_get_top(ctx);
- duk_push_array(ctx);
- for (idx = 0; idx < top; idx++) {
- duk_dup(ctx, idx);
- duk_put_prop_index(ctx, -2, idx);
- }
-
- /* XXX: conversion errors should not propagate outwards.
- * Perhaps values need to be coerced individually?
- */
- duk_bi_json_stringify_helper(ctx,
- duk_get_top_index(ctx), /*idx_value*/
- DUK_INVALID_INDEX, /*idx_replacer*/
- DUK_INVALID_INDEX, /*idx_space*/
- DUK_JSON_FLAG_EXT_CUSTOM |
- DUK_JSON_FLAG_ASCII_ONLY |
- DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
-
- duk_push_sprintf(ctx, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(ctx, -1));
- duk_replace(ctx, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
- duk_pop(ctx);
- DUK_ASSERT(duk_is_string(ctx, -1));
-}
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-
-DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
- duk_debug_read_function read_cb,
- duk_debug_write_function write_cb,
- duk_debug_peek_function peek_cb,
- duk_debug_read_flush_function read_flush_cb,
- duk_debug_write_flush_function write_flush_cb,
- duk_debug_request_function request_cb,
- duk_debug_detached_function detached_cb,
- void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_heap *heap;
- const char *str;
- duk_size_t len;
-
- /* XXX: should there be an error or an automatic detach if
- * already attached?
- */
-
- DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(read_cb != NULL);
- DUK_ASSERT(write_cb != NULL);
- /* Other callbacks are optional. */
-
- heap = thr->heap;
- heap->dbg_read_cb = read_cb;
- heap->dbg_write_cb = write_cb;
- heap->dbg_peek_cb = peek_cb;
- heap->dbg_read_flush_cb = read_flush_cb;
- heap->dbg_write_flush_cb = write_flush_cb;
- heap->dbg_request_cb = request_cb;
- heap->dbg_detached_cb = detached_cb;
- heap->dbg_udata = udata;
- heap->dbg_have_next_byte = 0;
-
- /* Start in paused state. */
- heap->dbg_processing = 0;
- heap->dbg_paused = 1;
- heap->dbg_state_dirty = 1;
- heap->dbg_force_restart = 0;
- heap->dbg_step_type = 0;
- heap->dbg_step_thread = NULL;
- heap->dbg_step_csindex = 0;
- heap->dbg_step_startline = 0;
- heap->dbg_exec_counter = 0;
- heap->dbg_last_counter = 0;
- heap->dbg_last_time = 0.0;
-
- /* Send version identification and flush right afterwards. Note that
- * we must write raw, unframed bytes here.
- */
- duk_push_sprintf(ctx, "%ld %ld %s %s\n",
- (long) DUK_DEBUG_PROTOCOL_VERSION,
- (long) DUK_VERSION,
- (const char *) DUK_GIT_DESCRIBE,
- (const char *) DUK_USE_TARGET_INFO);
- str = duk_get_lstring(ctx, -1, &len);
- DUK_ASSERT(str != NULL);
- duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
- duk_debug_write_flush(thr);
- duk_pop(ctx);
-}
-
-DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
-
- /* Can be called multiple times with no harm. */
- duk_debug_do_detach(thr->heap);
-}
-
-DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
- duk_hthread *thr;
- duk_bool_t processed_messages;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
-
- if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- return;
- }
- if (thr->callstack_top > 0 || thr->heap->dbg_processing) {
- /* Calling duk_debugger_cooperate() while Duktape is being
- * called into is not supported. This is not a 100% check
- * but prevents any damage in most cases.
- */
- return;
- }
-
- processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/);
- DUK_UNREF(processed_messages);
-}
-
-DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
- duk_hthread *thr;
- duk_idx_t top;
- duk_idx_t idx;
- duk_bool_t ret = 0;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
-
- DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
-
- top = duk_get_top(ctx);
- if (top < nvalues) {
- DUK_ERROR_API(thr, "not enough stack values for notify");
- return ret; /* unreachable */
- }
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
- for (idx = top - nvalues; idx < top; idx++) {
- duk_tval *tv = DUK_GET_TVAL_POSIDX(ctx, idx);
- duk_debug_write_tval(thr, tv);
- }
- duk_debug_write_eom(thr);
-
- /* Return non-zero (true) if we have a good reason to believe
- * the notify was delivered; if we're still attached at least
- * a transport error was not indicated by the transport write
- * callback. This is not a 100% guarantee of course.
- */
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- ret = 1;
- }
- }
- duk_pop_n(ctx, nvalues);
- return ret;
-}
-
-DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
-
- DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
-
- /* Treat like a debugger statement: ignore when not attached. */
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_HEAP_SET_PAUSED(thr->heap);
-
- /* Pause on the next opcode executed. This is always safe to do even
- * inside the debugger message loop: the interrupt counter will be reset
- * to its proper value when the message loop exits.
- */
- thr->interrupt_init = 1;
- thr->interrupt_counter = 0;
- }
-}
-
-#else /* DUK_USE_DEBUGGER_SUPPORT */
-
-DUK_EXTERNAL void duk_debugger_attach_custom(duk_context *ctx,
- duk_debug_read_function read_cb,
- duk_debug_write_function write_cb,
- duk_debug_peek_function peek_cb,
- duk_debug_read_flush_function read_flush_cb,
- duk_debug_write_flush_function write_flush_cb,
- duk_debug_request_function request_cb,
- duk_debug_detached_function detached_cb,
- void *udata) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(read_cb);
- DUK_UNREF(write_cb);
- DUK_UNREF(peek_cb);
- DUK_UNREF(read_flush_cb);
- DUK_UNREF(write_flush_cb);
- DUK_UNREF(request_cb);
- DUK_UNREF(detached_cb);
- DUK_UNREF(udata);
- DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
-}
-
-DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ERROR_API((duk_hthread *) ctx, "no debugger support");
-}
-
-DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
- /* nop */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
-}
-
-DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
- duk_idx_t top;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- top = duk_get_top(ctx);
- if (top < nvalues) {
- DUK_ERROR_API((duk_hthread *) ctx, "not enough stack values for notify");
- return 0; /* unreachable */
- }
-
- /* No debugger support, just pop values. */
- duk_pop_n(ctx, nvalues);
- return 0;
-}
-
-DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
- /* Treat like debugger statement: nop */
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
-}
-
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-#line 1 "duk_api_heap.c"
-/*
- * Heap creation and destruction
- */
-
-/* include removed: duk_internal.h */
-
-DUK_EXTERNAL
-duk_context *duk_create_heap(duk_alloc_function alloc_func,
- duk_realloc_function realloc_func,
- duk_free_function free_func,
- void *heap_udata,
- duk_fatal_function fatal_handler) {
- duk_heap *heap = NULL;
- duk_context *ctx;
-
- /* Assume that either all memory funcs are NULL or non-NULL, mixed
- * cases will now be unsafe.
- */
-
- /* XXX: just assert non-NULL values here and make caller arguments
- * do the defaulting to the default implementations (smaller code)?
- */
-
- if (!alloc_func) {
- DUK_ASSERT(realloc_func == NULL);
- DUK_ASSERT(free_func == NULL);
-#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
- alloc_func = duk_default_alloc_function;
- realloc_func = duk_default_realloc_function;
- free_func = duk_default_free_function;
-#else
- DUK_D(DUK_DPRINT("no allocation functions given and no default providers"));
- return NULL;
-#endif
- } else {
- DUK_ASSERT(realloc_func != NULL);
- DUK_ASSERT(free_func != NULL);
- }
-
- if (!fatal_handler) {
- fatal_handler = duk_default_fatal_handler;
- }
-
- DUK_ASSERT(alloc_func != NULL);
- DUK_ASSERT(realloc_func != NULL);
- DUK_ASSERT(free_func != NULL);
- DUK_ASSERT(fatal_handler != NULL);
-
- heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler);
- if (!heap) {
- return NULL;
- }
- ctx = (duk_context *) heap->heap_thread;
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
- return ctx;
-}
-
-DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_heap *heap;
-
- if (!ctx) {
- return;
- }
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- duk_heap_free(heap);
-}
-
-/* XXX: better place for this */
-DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_glob;
- duk_hobject *h_prev_glob;
- duk_hobject *h_env;
- duk_hobject *h_prev_env;
-
- DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1)));
-
- h_glob = duk_require_hobject(ctx, -1);
- DUK_ASSERT(h_glob != NULL);
-
- /*
- * Replace global object.
- */
-
- h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
- DUK_UNREF(h_prev_glob);
- thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
- DUK_HOBJECT_INCREF(thr, h_glob);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
-
- /*
- * Replace lexical environment for global scope
- *
- * Create a new object environment for the global lexical scope.
- * We can't just reset the _Target property of the current one,
- * because the lexical scope is shared by other threads with the
- * same (initial) built-ins.
- */
-
- (void) duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
- -1); /* no prototype, updated below */
-
- duk_dup(ctx, -2);
- duk_dup(ctx, -3);
-
- /* [ ... new_glob new_env new_glob new_glob ] */
-
- duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
-
- /* [ ... new_glob new_env ] */
-
- h_env = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_env != NULL);
-
- h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env;
- DUK_HOBJECT_INCREF(thr, h_env);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
- DUK_UNREF(h_env); /* without refcounts */
- DUK_UNREF(h_prev_env);
-
- /* [ ... new_glob new_env ] */
-
- duk_pop_2(ctx);
-
- /* [ ... ] */
-}
-#line 1 "duk_api_logging.c"
-/*
- * Logging
- *
- * Current logging primitive is a sprintf-style log which is convenient
- * for most C code. Another useful primitive would be to log N arguments
- * from value stack (like the Ecmascript binding does).
- */
-
-/* include removed: duk_internal.h */
-
-DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) {
- /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */
- static const duk_uint16_t stridx_logfunc[6] = {
- DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO,
- DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL
- };
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (level < 0) {
- level = 0;
- } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) {
- level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1;
- }
-
- duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG);
- duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]);
- duk_dup(ctx, -2);
-
- /* [ ... Logger clog logfunc clog ] */
-
- duk_push_vsprintf(ctx, fmt, ap);
-
- /* [ ... Logger clog logfunc clog(=this) msg ] */
-
- duk_call_method(ctx, 1 /*nargs*/);
-
- /* [ ... Logger clog res ] */
-
- duk_pop_3(ctx);
-}
-
-DUK_EXTERNAL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) {
- va_list ap;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- va_start(ap, fmt);
- duk_log_va(ctx, level, fmt, ap);
- va_end(ap);
-}
-#line 1 "duk_api_memory.c"
-/*
- * Memory calls.
- */
-
-/* include removed: duk_internal.h */
-
-DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- return DUK_ALLOC_RAW(thr->heap, size);
-}
-
-DUK_EXTERNAL void duk_free_raw(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- DUK_FREE_RAW(thr->heap, ptr);
-}
-
-DUK_EXTERNAL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- return DUK_REALLOC_RAW(thr->heap, ptr, size);
-}
-
-DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- return DUK_ALLOC(thr->heap, size);
-}
-
-DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- DUK_FREE(thr->heap, ptr);
-}
-
-DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /*
- * Note: since this is an exposed API call, there should be
- * no way a mark-and-sweep could have a side effect on the
- * memory allocation behind 'ptr'; the pointer should never
- * be something that Duktape wants to change.
- *
- * Thus, no need to use DUK_REALLOC_INDIRECT (and we don't
- * have the storage location here anyway).
- */
-
- return DUK_REALLOC(thr->heap, ptr, size);
-}
-
-DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_heap *heap;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(out_funcs != NULL);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
-
- heap = thr->heap;
- out_funcs->alloc_func = heap->alloc_func;
- out_funcs->realloc_func = heap->realloc_func;
- out_funcs->free_func = heap->free_func;
- out_funcs->udata = heap->heap_udata;
-}
-
-DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_heap *heap;
-
- DUK_UNREF(flags);
-
- /* NULL accepted */
- if (!ctx) {
- return;
- }
- DUK_ASSERT_CTX_VALID(ctx);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
- duk_heap_mark_and_sweep(heap, 0);
-#else
- DUK_D(DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring"));
- DUK_UNREF(ctx);
- DUK_UNREF(flags);
-#endif
-}
-#line 1 "duk_api_object.c"
-/*
- * Object handling: property access and other support functions.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Property handling
- *
- * The API exposes only the most common property handling functions.
- * The caller can invoke Ecmascript built-ins for full control (e.g.
- * defineProperty, getOwnPropertyDescriptor).
- */
-
-DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_bool_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Note: copying tv_obj and tv_key to locals to shield against a valstack
- * resize is not necessary for a property get right now.
- */
-
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
-
- rc = duk_hobject_getprop(thr, tv_obj, tv_key);
- DUK_ASSERT(rc == 0 || rc == 1);
- /* a value is left on stack regardless of rc */
-
- duk_remove(ctx, -2); /* remove key */
- return rc; /* 1 if property found, 0 otherwise */
-}
-
-DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(key != NULL);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_get_prop(ctx, obj_index);
-}
-
-DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_get_prop(ctx, obj_index);
-}
-
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_get_prop(ctx, obj_index);
-}
-
-DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop) {
- duk_bool_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
-
- rc = duk_get_prop_stridx(ctx, obj_index, stridx);
- if (out_has_prop) {
- *out_has_prop = rc;
- }
- rc = duk_to_boolean(ctx, -1);
- DUK_ASSERT(rc == 0 || rc == 1);
- duk_pop(ctx);
- return rc;
-}
-
-DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_tval *tv_val;
- duk_small_int_t throw_flag;
- duk_bool_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Note: copying tv_obj and tv_key to locals to shield against a valstack
- * resize is not necessary for a property put right now (putprop protects
- * against it internally).
- */
-
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -2);
- tv_val = duk_require_tval(ctx, -1);
- throw_flag = duk_is_strict_call(ctx);
-
- rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
- DUK_ASSERT(rc == 0 || rc == 1);
-
- duk_pop_2(ctx); /* remove key and value */
- return rc; /* 1 if property found, 0 otherwise */
-}
-
-DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(key != NULL);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- duk_swap_top(ctx, -2); /* [val key] -> [key val] */
- return duk_put_prop(ctx, obj_index);
-}
-
-DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- duk_swap_top(ctx, -2); /* [val key] -> [key val] */
- return duk_put_prop(ctx, obj_index);
-}
-
-DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- duk_swap_top(ctx, -2); /* [val key] -> [key val] */
- return duk_put_prop(ctx, obj_index);
-}
-
-DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_small_int_t throw_flag;
- duk_bool_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Note: copying tv_obj and tv_key to locals to shield against a valstack
- * resize is not necessary for a property delete right now.
- */
-
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
- throw_flag = duk_is_strict_call(ctx);
-
- rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
- DUK_ASSERT(rc == 0 || rc == 1);
-
- duk_pop(ctx); /* remove key */
- return rc;
-}
-
-DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(key != NULL);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_del_prop(ctx, obj_index);
-}
-
-DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_del_prop(ctx, obj_index);
-}
-
-DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_del_prop(ctx, obj_index);
-}
-
-DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_bool_t rc;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Note: copying tv_obj and tv_key to locals to shield against a valstack
- * resize is not necessary for a property existence check right now.
- */
-
- tv_obj = duk_require_tval(ctx, obj_index);
- tv_key = duk_require_tval(ctx, -1);
-
- rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
- DUK_ASSERT(rc == 0 || rc == 1);
-
- duk_pop(ctx); /* remove key */
- return rc; /* 1 if property found, 0 otherwise */
-}
-
-DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(key != NULL);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_string(ctx, key);
- return duk_has_prop(ctx, obj_index);
-}
-
-DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_uarridx(ctx, arr_index);
- return duk_has_prop(ctx, obj_index);
-}
-
-DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_UNREF(thr);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
- return duk_has_prop(ctx, obj_index);
-}
-
-/* Define own property without inheritance looks and such. This differs from
- * [[DefineOwnProperty]] because special behaviors (like Array 'length') are
- * not invoked by this method. The caller must be careful to invoke any such
- * behaviors if necessary.
- */
-DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- duk_hstring *key;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj = duk_require_hobject(ctx, obj_index);
- DUK_ASSERT(obj != NULL);
- key = duk_to_hstring(ctx, -2);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
-
- duk_hobject_define_property_internal(thr, obj, key, desc_flags);
-
- duk_pop(ctx); /* pop key */
-}
-
-DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj = duk_require_hobject(ctx, obj_index);
- DUK_ASSERT(obj != NULL);
-
- duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags);
- /* value popped by call */
-}
-
-DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- duk_hstring *key;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
-
- obj = duk_require_hobject(ctx, obj_index);
- DUK_ASSERT(obj != NULL);
- key = DUK_HTHREAD_GET_STRING(thr, stridx);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
-
- duk_hobject_define_property_internal(thr, obj, key, desc_flags);
- /* value popped by call */
-}
-
-DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- duk_hstring *key;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(stridx >= 0);
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- DUK_ASSERT_DISABLE(builtin_idx >= 0);
- DUK_ASSERT(builtin_idx < DUK_NUM_BUILTINS);
-
- obj = duk_require_hobject(ctx, obj_index);
- DUK_ASSERT(obj != NULL);
- key = DUK_HTHREAD_GET_STRING(thr, stridx);
- DUK_ASSERT(key != NULL);
-
- duk_push_hobject(ctx, thr->builtins[builtin_idx]);
- duk_hobject_define_property_internal(thr, obj, key, desc_flags);
- /* value popped by call */
-}
-
-/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
- * setter/getter into an object property. This is needed by the 'arguments'
- * object creation code, function instance creation code, and Function.prototype.bind().
- */
-
-DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj = duk_require_hobject(ctx, obj_index);
- duk_hobject *thrower = thr->builtins[DUK_BIDX_TYPE_ERROR_THROWER];
- duk_hobject_define_accessor_internal(thr, obj, DUK_HTHREAD_GET_STRING(thr, stridx), thrower, thrower, desc_flags);
-}
-
-/* Object.defineProperty() equivalent C binding. */
-DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t idx_base;
- duk_hobject *obj;
- duk_hstring *key;
- duk_idx_t idx_value;
- duk_hobject *get;
- duk_hobject *set;
- duk_uint_t is_data_desc;
- duk_uint_t is_acc_desc;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj = duk_require_hobject(ctx, obj_index);
-
- is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
- is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
- if (is_data_desc && is_acc_desc) {
- /* "Have" flags must not be conflicting so that they would
- * apply to both a plain property and an accessor at the same
- * time.
- */
- goto fail_invalid_desc;
- }
-
- idx_base = duk_get_top_index(ctx);
- if (flags & DUK_DEFPROP_HAVE_SETTER) {
- duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
- DUK_TYPE_MASK_OBJECT |
- DUK_TYPE_MASK_LIGHTFUNC);
- set = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
- if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
- goto fail_not_callable;
- }
- idx_base--;
- } else {
- set = NULL;
- }
- if (flags & DUK_DEFPROP_HAVE_GETTER) {
- duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
- DUK_TYPE_MASK_OBJECT |
- DUK_TYPE_MASK_LIGHTFUNC);
- get = duk_get_hobject_or_lfunc_coerce(ctx, idx_base);
- if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
- goto fail_not_callable;
- }
- idx_base--;
- } else {
- get = NULL;
- }
- if (flags & DUK_DEFPROP_HAVE_VALUE) {
- idx_value = idx_base;
- idx_base--;
- } else {
- idx_value = (duk_idx_t) -1;
- }
- key = duk_require_hstring(ctx, idx_base);
-
- duk_require_valid_index(ctx, idx_base);
-
- duk_hobject_define_property_helper(ctx,
- flags /*defprop_flags*/,
- obj,
- key,
- idx_value,
- get,
- set);
-
- /* Clean up stack */
-
- duk_set_top(ctx, idx_base);
-
- /* [ ... obj ... ] */
-
- return;
-
- fail_invalid_desc:
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
- return;
-
- fail_not_callable:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
- return;
-}
-
-/*
- * Object related
- *
- * Note: seal() and freeze() are accessible through Ecmascript bindings,
- * and are not exposed through the API.
- */
-
-DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj = duk_get_hobject(ctx, obj_index);
- if (obj) {
- /* Note: this may fail, caller should protect the call if necessary */
- duk_hobject_compact_props(thr, obj);
- }
-}
-
-/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
-
-DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_dup(ctx, obj_index);
- duk_require_hobject_or_lfunc_coerce(ctx, -1);
- duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */
-}
-
-DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_require_hobject(ctx, enum_index);
- duk_dup(ctx, enum_index);
- return duk_hobject_enumerator_next(ctx, get_value);
-}
-
-/*
- * Helpers for writing multiple properties
- */
-
-DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs) {
- const duk_function_list_entry *ent = funcs;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- if (ent != NULL) {
- while (ent->key != NULL) {
- duk_push_c_function(ctx, ent->value, ent->nargs);
- duk_put_prop_string(ctx, obj_index, ent->key);
- ent++;
- }
- }
-}
-
-DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers) {
- const duk_number_list_entry *ent = numbers;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj_index = duk_require_normalize_index(ctx, obj_index);
- if (ent != NULL) {
- while (ent->key != NULL) {
- duk_push_number(ctx, ent->value);
- duk_put_prop_string(ctx, obj_index, ent->key);
- ent++;
- }
- }
-}
-
-/*
- * Shortcut for accessing global object properties
- */
-
-DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_bool_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
-
- /* XXX: direct implementation */
-
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- ret = duk_get_prop_string(ctx, -1, key);
- duk_remove(ctx, -2);
- return ret;
-}
-
-DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_bool_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
-
- /* XXX: direct implementation */
-
- duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
- duk_insert(ctx, -2);
- ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */
- duk_pop(ctx);
- return ret;
-}
-
-/*
- * Object prototype
- */
-
-DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- duk_hobject *proto;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- obj = duk_require_hobject(ctx, index);
- DUK_ASSERT(obj != NULL);
-
- /* XXX: shared helper for duk_push_hobject_or_undefined()? */
- proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
- if (proto) {
- duk_push_hobject(ctx, proto);
- } else {
- duk_push_undefined(ctx);
- }
-}
-
-DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- duk_hobject *proto;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj = duk_require_hobject(ctx, index);
- DUK_ASSERT(obj != NULL);
- duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED |
- DUK_TYPE_MASK_OBJECT);
- proto = duk_get_hobject(ctx, -1);
- /* proto can also be NULL here (allowed explicitly) */
-
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */
- return;
- }
-#endif
-
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
-
- duk_pop(ctx);
-}
-
-/*
- * Object finalizer
- */
-
-/* XXX: these could be implemented as macros calling an internal function
- * directly.
- * XXX: same issue as with Duktape.fin: there's no way to delete the property
- * now (just set it to undefined).
- */
-DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_get_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
-}
-
-DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_put_prop_stridx(ctx, index, DUK_STRIDX_INT_FINALIZER);
-}
-#line 1 "duk_api_stack.c"
-/*
- * API calls related to general value stack manipulation: resizing the value
- * stack, pushing and popping values, type checking and reading values,
- * coercing values, etc.
- *
- * Also contains internal functions (such as duk_get_tval()), defined
- * in duk_api_internal.h, with semantics similar to the public API.
- */
-
-/* XXX: repetition of stack pre-checks -> helper or macro or inline */
-/* XXX: shared api error strings, and perhaps even throw code for rare cases? */
-
-/* include removed: duk_internal.h */
-
-/*
- * Forward declarations
- */
-
-DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags);
-
-/*
- * Global state for working around missing variadic macros
- */
-
-#ifndef DUK_USE_VARIADIC_MACROS
-DUK_EXTERNAL const char *duk_api_global_filename = NULL;
-DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
-#endif
-
-/*
- * Misc helpers
- */
-
-/* Check that there's room to push one value. */
-#if defined(DUK_USE_VALSTACK_UNSAFE)
-/* Faster but value stack overruns are memory unsafe. */
-#define DUK__CHECK_SPACE() do { \
- DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
- } while (0)
-#else
-#define DUK__CHECK_SPACE() do { \
- if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK); \
- } \
- } while (0)
-#endif
-
-DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag);
-
-DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_small_int_t c;
- duk_double_t d;
-
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto error_notnumber;
- }
-
- /*
- * Special cases like NaN and +/- Infinity are handled explicitly
- * because a plain C coercion from double to int handles these cases
- * in undesirable ways. For instance, NaN may coerce to INT_MIN
- * (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX).
- *
- * This double-to-int coercion differs from ToInteger() because it
- * has a finite range (ToInteger() allows e.g. +/- Infinity). It
- * also differs from ToInt32() because the INT_MIN/INT_MAX clamping
- * depends on the size of the int type on the platform. In particular,
- * on platforms with a 64-bit int type, the full range is allowed.
- */
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv)) {
- duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
-#if (DUK_INT_MAX <= 0x7fffffffL)
- /* Clamping only necessary for 32-bit ints. */
- if (t < DUK_INT_MIN) {
- t = DUK_INT_MIN;
- } else if (t > DUK_INT_MAX) {
- t = DUK_INT_MAX;
- }
-#endif
- return (duk_int_t) t;
- }
-#endif
-
- if (DUK_TVAL_IS_NUMBER(tv)) {
- d = DUK_TVAL_GET_NUMBER(tv);
- c = (duk_small_int_t) DUK_FPCLASSIFY(d);
- if (c == DUK_FP_NAN) {
- return 0;
- } else if (d < (duk_double_t) DUK_INT_MIN) {
- /* covers -Infinity */
- return DUK_INT_MIN;
- } else if (d > (duk_double_t) DUK_INT_MAX) {
- /* covers +Infinity */
- return DUK_INT_MAX;
- } else {
- /* coerce towards zero */
- return (duk_int_t) d;
- }
- }
-
- error_notnumber:
-
- if (require) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
- /* not reachable */
- }
- return 0;
-}
-
-DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t index, duk_bool_t require) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_small_int_t c;
- duk_double_t d;
-
- /* Same as above but for unsigned int range. */
-
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto error_notnumber;
- }
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv)) {
- duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
- if (t < 0) {
- t = 0;
- }
-#if (DUK_UINT_MAX <= 0xffffffffUL)
- /* Clamping only necessary for 32-bit ints. */
- else if (t > DUK_UINT_MAX) {
- t = DUK_UINT_MAX;
- }
-#endif
- return (duk_uint_t) t;
- }
-#endif
-
- if (DUK_TVAL_IS_NUMBER(tv)) {
- d = DUK_TVAL_GET_NUMBER(tv);
- c = (duk_small_int_t) DUK_FPCLASSIFY(d);
- if (c == DUK_FP_NAN) {
- return 0;
- } else if (d < 0.0) {
- /* covers -Infinity */
- return (duk_uint_t) 0;
- } else if (d > (duk_double_t) DUK_UINT_MAX) {
- /* covers +Infinity */
- return (duk_uint_t) DUK_UINT_MAX;
- } else {
- /* coerce towards zero */
- return (duk_uint_t) d;
- }
- }
-
- error_notnumber:
-
- if (require) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
- /* not reachable */
- }
- return 0;
-}
-
-/*
- * Stack index validation/normalization and getting a stack duk_tval ptr.
- *
- * These are called by many API entrypoints so the implementations must be
- * fast and "inlined".
- *
- * There's some repetition because of this; keep the functions in sync.
- */
-
-DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uidx_t vs_size;
- duk_uidx_t uindex;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(DUK_INVALID_INDEX < 0);
-
- /* Care must be taken to avoid pointer wrapping in the index
- * validation. For instance, on a 32-bit platform with 8-byte
- * duk_tval the index 0x20000000UL would wrap the memory space
- * once.
- */
-
- /* Assume value stack sizes (in elements) fits into duk_idx_t. */
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
- DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
-
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
- } else {
- /* since index non-negative */
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
- }
-
- /* DUK_INVALID_INDEX won't be accepted as a valid index. */
- DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
-
- if (DUK_LIKELY(uindex < vs_size)) {
- return (duk_idx_t) uindex;
- }
- return DUK_INVALID_INDEX;
-}
-
-DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uidx_t vs_size;
- duk_uidx_t uindex;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(DUK_INVALID_INDEX < 0);
-
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
- DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
-
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
- } else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
- }
-
- /* DUK_INVALID_INDEX won't be accepted as a valid index. */
- DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
-
- if (DUK_LIKELY(uindex < vs_size)) {
- return (duk_idx_t) uindex;
- }
- DUK_ERROR_API_INDEX(thr, index);
- return 0; /* unreachable */
-}
-
-DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uidx_t vs_size;
- duk_uidx_t uindex;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(DUK_INVALID_INDEX < 0);
-
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
- DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
-
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
- } else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
- }
-
- /* DUK_INVALID_INDEX won't be accepted as a valid index. */
- DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
-
- if (DUK_LIKELY(uindex < vs_size)) {
- return thr->valstack_bottom + uindex;
- }
- return NULL;
-}
-
-DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uidx_t vs_size;
- duk_uidx_t uindex;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(DUK_INVALID_INDEX < 0);
-
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
- DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
-
- /* Use unsigned arithmetic to optimize comparison. */
- if (index < 0) {
- uindex = vs_size + (duk_uidx_t) index;
- } else {
- DUK_ASSERT(index != DUK_INVALID_INDEX);
- uindex = (duk_uidx_t) index;
- }
-
- /* DUK_INVALID_INDEX won't be accepted as a valid index. */
- DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
-
- if (DUK_LIKELY(uindex < vs_size)) {
- return thr->valstack_bottom + uindex;
- }
- DUK_ERROR_API_INDEX(thr, index);
- return NULL;
-}
-
-/* Non-critical. */
-DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(DUK_INVALID_INDEX < 0);
-
- return (duk_normalize_index(ctx, index) >= 0);
-}
-
-/* Non-critical. */
-DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(DUK_INVALID_INDEX < 0);
-
- if (duk_normalize_index(ctx, index) < 0) {
- DUK_ERROR_API_INDEX(thr, index);
- return; /* unreachable */
- }
-}
-
-/*
- * Value stack top handling
- */
-
-DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
-}
-
-/* Set stack top within currently allocated range, but don't reallocate.
- * This is performance critical especially for call handling, so whenever
- * changing, profile and look at generated code.
- */
-DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uidx_t vs_size;
- duk_uidx_t vs_limit;
- duk_uidx_t uindex;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(DUK_INVALID_INDEX < 0);
-
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
- vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
- vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom);
-
- if (index < 0) {
- /* Negative indices are always within allocated stack but
- * must not go below zero index.
- */
- uindex = vs_size + (duk_uidx_t) index;
- } else {
- /* Positive index can be higher than valstack top but must
- * not go above allocated stack (equality is OK).
- */
- uindex = (duk_uidx_t) index;
- }
-
- /* DUK_INVALID_INDEX won't be accepted as a valid index. */
- DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
- DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit);
-
-#if defined(DUK_USE_VALSTACK_UNSAFE)
- DUK_ASSERT(uindex <= vs_limit);
- DUK_UNREF(vs_limit);
-#else
- if (DUK_UNLIKELY(uindex > vs_limit)) {
- DUK_ERROR_API_INDEX(thr, index);
- return; /* unreachable */
- }
-#endif
- DUK_ASSERT(uindex <= vs_limit);
-
- /* Handle change in value stack top. Respect value stack
- * initialization policy: 'undefined' above top. Note that
- * DECREF may cause a side effect that reallocates valstack,
- * so must relookup after DECREF.
- */
-
- if (uindex >= vs_size) {
- /* Stack size increases or stays the same. */
-#if defined(DUK_USE_ASSERTIONS)
- duk_uidx_t count;
-
- count = uindex - vs_size;
- while (count != 0) {
- count--;
- tv = thr->valstack_top + count;
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
- }
-#endif
- thr->valstack_top = thr->valstack_bottom + uindex;
- } else {
- /* Stack size decreases. */
-#if defined(DUK_USE_REFERENCE_COUNTING)
- duk_uidx_t count;
-
- count = vs_size - uindex;
- DUK_ASSERT(count > 0);
- while (count > 0) {
- count--;
- tv = --thr->valstack_top; /* tv -> value just before prev top value; must relookup */
- DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
- }
-#else /* DUK_USE_REFERENCE_COUNTING */
- duk_uidx_t count;
- duk_tval *tv_end;
-
- count = vs_size - uindex;
- tv = thr->valstack_top;
- tv_end = tv - count;
- DUK_ASSERT(tv > tv_end);
- do {
- tv--;
- DUK_TVAL_SET_UNDEFINED(tv);
- } while (tv != tv_end);
- thr->valstack_top = tv_end;
-#endif /* DUK_USE_REFERENCE_COUNTING */
- }
-}
-
-DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
- if (DUK_UNLIKELY(ret < 0)) {
- /* Return invalid index; if caller uses this without checking
- * in another API call, the index won't map to a valid stack
- * entry.
- */
- return DUK_INVALID_INDEX;
- }
- return ret;
-}
-
-DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- ret = ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
- if (DUK_UNLIKELY(ret < 0)) {
- DUK_ERROR_API_INDEX(thr, -1);
- return 0; /* unreachable */
- }
- return ret;
-}
-
-/*
- * Value stack resizing.
- *
- * This resizing happens above the current "top": the value stack can be
- * grown or shrunk, but the "top" is not affected. The value stack cannot
- * be resized to a size below the current "top".
- *
- * The low level reallocation primitive must carefully recompute all value
- * stack pointers, and must also work if ALL pointers are NULL. The resize
- * is quite tricky because the valstack realloc may cause a mark-and-sweep,
- * which may run finalizers. Running finalizers may resize the valstack
- * recursively (the same value stack we're working on). So, after realloc
- * returns, we know that the valstack "top" should still be the same (there
- * should not be live values above the "top"), but its underlying size and
- * pointer may have changed.
- */
-
-/* XXX: perhaps refactor this to allow caller to specify some parameters, or
- * at least a 'compact' flag which skips any spare or round-up .. useful for
- * emergency gc.
- */
-
-DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_ptrdiff_t old_bottom_offset;
- duk_ptrdiff_t old_top_offset;
- duk_ptrdiff_t old_end_offset_post;
-#ifdef DUK_USE_DEBUG
- duk_ptrdiff_t old_end_offset_pre;
- duk_tval *old_valstack_pre;
- duk_tval *old_valstack_post;
-#endif
- duk_tval *new_valstack;
- duk_size_t new_alloc_size;
- duk_tval *p;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- 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((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */
- DUK_ASSERT(new_size <= thr->valstack_max); /* valstack limit caller has check, prevents wrapping */
- DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */
-
- /* get pointer offsets for tweaking below */
- old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack));
- old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack));
-#ifdef DUK_USE_DEBUG
- old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */
- old_valstack_pre = thr->valstack;
-#endif
-
- /* Allocate a new valstack.
- *
- * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may
- * invalidate the original thr->valstack base pointer inside the realloc
- * process. See doc/memory-management.rst.
- */
-
- new_alloc_size = sizeof(duk_tval) * new_size;
- new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
- if (!new_valstack) {
- /* Because new_size != 0, if condition doesn't need to be
- * (new_valstack != NULL || new_size == 0).
- */
- DUK_ASSERT(new_size != 0);
- DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)",
- (unsigned long) new_size, (unsigned long) new_alloc_size));
- return 0;
- }
-
- /* Note: the realloc may have triggered a mark-and-sweep which may
- * have resized our valstack internally. However, the mark-and-sweep
- * MUST NOT leave the stack bottom/top in a different state. Particular
- * assumptions and facts:
- *
- * - The thr->valstack pointer may be different after realloc,
- * and the offset between thr->valstack_end <-> thr->valstack
- * may have changed.
- * - The offset between thr->valstack_bottom <-> thr->valstack
- * and thr->valstack_top <-> thr->valstack MUST NOT have changed,
- * because mark-and-sweep must adhere to a strict stack policy.
- * In other words, logical bottom and top MUST NOT have changed.
- * - All values above the top are unreachable but are initialized
- * to UNDEFINED, up to the post-realloc valstack_end.
- * - 'old_end_offset' must be computed after realloc to be correct.
- */
-
- DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset);
- DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset);
-
- /* success, fixup pointers */
- old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */
-#ifdef DUK_USE_DEBUG
- old_valstack_post = thr->valstack;
-#endif
- thr->valstack = new_valstack;
- thr->valstack_end = new_valstack + new_size;
-#if !defined(DUK_USE_PREFER_SIZE)
- thr->valstack_size = new_size;
-#endif
- thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_bottom_offset);
- thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_top_offset);
-
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
-
- /* useful for debugging */
-#ifdef DUK_USE_DEBUG
- if (old_end_offset_pre != old_end_offset_post) {
- DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; "
- "end offset changed: %lu -> %lu",
- (unsigned long) old_end_offset_pre,
- (unsigned long) old_end_offset_post));
- }
- if (old_valstack_pre != old_valstack_post) {
- DUK_D(DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p",
- (void *) old_valstack_pre,
- (void *) old_valstack_post));
- }
-#endif
-
- DUK_DD(DUK_DDPRINT("resized valstack to %lu elements (%lu bytes), bottom=%ld, top=%ld, "
- "new pointers: start=%p end=%p bottom=%p top=%p",
- (unsigned long) new_size, (unsigned long) new_alloc_size,
- (long) (thr->valstack_bottom - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (void *) thr->valstack, (void *) thr->valstack_end,
- (void *) thr->valstack_bottom, (void *) thr->valstack_top));
-
- /* Init newly allocated slots (only). */
- p = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + old_end_offset_post);
- while (p < thr->valstack_end) {
- /* Never executed if new size is smaller. */
- DUK_TVAL_SET_UNDEFINED(p);
- p++;
- }
-
- /* Assert for value stack initialization policy. */
-#if defined(DUK_USE_ASSERTIONS)
- p = thr->valstack_top;
- while (p < thr->valstack_end) {
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
- p++;
- }
-#endif
-
- return 1;
-}
-
-DUK_INTERNAL
-duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
- duk_size_t min_new_size,
- duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t old_size;
- duk_size_t new_size;
- duk_bool_t is_shrink = 0;
- duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK);
- duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT);
- duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW);
-
- DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, "
- "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d",
- (unsigned long) min_new_size,
- (long) (thr->valstack_end - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (long) (thr->valstack_bottom - thr->valstack),
- (int) shrink_flag, (int) compact_flag, (int) throw_flag));
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
-
-#if defined(DUK_USE_PREFER_SIZE)
- old_size = (duk_size_t) (thr->valstack_end - thr->valstack);
-#else
- DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
- old_size = thr->valstack_size;
-#endif
-
- if (min_new_size <= old_size) {
- is_shrink = 1;
- if (!shrink_flag ||
- old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) {
- DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack"));
- return 1;
- }
- }
-
- new_size = min_new_size;
- if (!compact_flag) {
- if (is_shrink) {
- /* shrink case; leave some spare */
- new_size += DUK_VALSTACK_SHRINK_SPARE;
- }
-
- /* round up roughly to next 'grow step' */
- new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP;
- }
-
- DUK_DD(DUK_DDPRINT("want to %s valstack: %lu -> %lu elements (min_new_size %lu)",
- (const char *) (new_size > old_size ? "grow" : "shrink"),
- (unsigned long) old_size, (unsigned long) new_size,
- (unsigned long) min_new_size));
-
- if (new_size > thr->valstack_max) {
- /* Note: may be triggered even if minimal new_size would not reach the limit,
- * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account).
- */
- if (throw_flag) {
- DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
- } else {
- return 0;
- }
- }
-
- /*
- * When resizing the valstack, a mark-and-sweep may be triggered for
- * the allocation of the new valstack. If the mark-and-sweep needs
- * to use our thread for something, it may cause *the same valstack*
- * to be resized recursively. This happens e.g. when mark-and-sweep
- * finalizers are called. This is taken into account carefully in
- * duk__resize_valstack().
- *
- * 'new_size' is known to be <= valstack_max, which ensures that
- * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
- */
-
- if (!duk__resize_valstack(ctx, new_size)) {
- if (is_shrink) {
- DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore"));
- return 1;
- }
-
- DUK_DD(DUK_DDPRINT("valstack resize failed"));
-
- if (throw_flag) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- } else {
- return 0;
- }
- }
-
- DUK_DDD(DUK_DDDPRINT("valstack resize successful"));
- return 1;
-}
-
-DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t min_new_size;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- if (DUK_UNLIKELY(extra < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- extra = 0;
- }
-
- min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
- return duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- 0 /* no throw */);
-}
-
-DUK_EXTERNAL void duk_require_stack(duk_context *ctx, duk_idx_t extra) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_size_t min_new_size;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- if (DUK_UNLIKELY(extra < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- extra = 0;
- }
-
- min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
- (void) duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
-}
-
-DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) {
- duk_size_t min_new_size;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (DUK_UNLIKELY(top < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- top = 0;
- }
-
- min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
- return duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- 0 /* no throw */);
-}
-
-DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) {
- duk_size_t min_new_size;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (DUK_UNLIKELY(top < 0)) {
- /* Clamping to zero makes the API more robust to calling code
- * calculation errors.
- */
- top = 0;
- }
-
- min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
- (void) duk_valstack_resize_raw(ctx,
- min_new_size, /* min_new_size */
- 0 /* no shrink */ | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
-}
-
-/*
- * Basic stack manipulation: swap, dup, insert, replace, etc
- */
-
-DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
- duk_tval *tv1;
- duk_tval *tv2;
- duk_tval tv_tmp;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv1 = duk_require_tval(ctx, index1);
- DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, index2);
- DUK_ASSERT(tv2 != NULL);
-
- /* If tv1==tv2 this is a NOP, no check is needed */
- DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
- DUK_TVAL_SET_TVAL(tv1, tv2);
- DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
-}
-
-DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_swap(ctx, index, -1);
-}
-
-DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index) {
- duk_hthread *thr;
- duk_tval *tv_from;
- duk_tval *tv_to;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
-
- tv_from = duk_require_tval(ctx, from_index);
- tv_to = thr->valstack_top++;
- DUK_ASSERT(tv_from != NULL);
- DUK_ASSERT(tv_to != NULL);
- DUK_TVAL_SET_TVAL(tv_to, tv_from);
- DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
-}
-
-DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv_from;
- duk_tval *tv_to;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
-
- if (thr->valstack_top - thr->valstack_bottom <= 0) {
- DUK_ERROR_API_INDEX(thr, -1);
- return; /* unreachable */
- }
- tv_from = thr->valstack_top - 1;
- tv_to = thr->valstack_top++;
- DUK_ASSERT(tv_from != NULL);
- DUK_ASSERT(tv_to != NULL);
- DUK_TVAL_SET_TVAL(tv_to, tv_from);
- DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
-}
-
-DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index) {
- duk_tval *p;
- duk_tval *q;
- duk_tval tv_tmp;
- duk_size_t nbytes;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- p = duk_require_tval(ctx, to_index);
- DUK_ASSERT(p != NULL);
- q = duk_require_tval(ctx, -1);
- DUK_ASSERT(q != NULL);
-
- DUK_ASSERT(q >= p);
-
- /* nbytes
- * <--------->
- * [ ... | p | x | x | q ]
- * => [ ... | q | p | x | x ]
- */
-
- nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
-
- DUK_DDD(DUK_DDDPRINT("duk_insert: to_index=%ld, p=%p, q=%p, nbytes=%lu",
- (long) to_index, (void *) p, (void *) q, (unsigned long) nbytes));
-
- /* No net refcount changes. */
-
- if (nbytes > 0) {
- DUK_TVAL_SET_TVAL(&tv_tmp, q);
- DUK_ASSERT(nbytes > 0);
- DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes);
- DUK_TVAL_SET_TVAL(p, &tv_tmp);
- } else {
- /* nop: insert top to top */
- DUK_ASSERT(nbytes == 0);
- DUK_ASSERT(p == q);
- }
-}
-
-DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv1;
- duk_tval *tv2;
- duk_tval tv_tmp;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv1 = duk_require_tval(ctx, -1);
- DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, to_index);
- DUK_ASSERT(tv2 != NULL);
-
- /* For tv1 == tv2, both pointing to stack top, the end result
- * is same as duk_pop(ctx).
- */
- DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
- DUK_TVAL_SET_TVAL(tv2, tv1);
- DUK_TVAL_SET_UNDEFINED(tv1);
- thr->valstack_top--;
- DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
-}
-
-DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv1;
- duk_tval *tv2;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr); /* w/o refcounting */
-
- tv1 = duk_require_tval(ctx, from_index);
- DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, to_index);
- DUK_ASSERT(tv2 != NULL);
-
- /* For tv1 == tv2, this is a no-op (no explicit check needed). */
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */
-}
-
-DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *p;
- duk_tval *q;
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk_tval tv_tmp;
-#endif
- duk_size_t nbytes;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- p = duk_require_tval(ctx, index);
- DUK_ASSERT(p != NULL);
- q = duk_require_tval(ctx, -1);
- DUK_ASSERT(q != NULL);
-
- DUK_ASSERT(q >= p);
-
- /* nbytes zero size case
- * <--------->
- * [ ... | p | x | x | q ] [ ... | p==q ]
- * => [ ... | x | x | q ] [ ... ]
- */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- /* use a temp: decref only when valstack reachable values are correct */
- DUK_TVAL_SET_TVAL(&tv_tmp, p);
-#endif
-
- nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
- DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */
-
- DUK_TVAL_SET_UNDEFINED(q);
- thr->valstack_top--;
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
-#endif
-}
-
-/*
- * Stack slice primitives
- */
-
-DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy) {
- duk_hthread *to_thr = (duk_hthread *) to_ctx;
- duk_hthread *from_thr = (duk_hthread *) from_ctx;
- void *src;
- duk_size_t nbytes;
- duk_tval *p;
- duk_tval *q;
-
- /* XXX: several pointer comparison issues here */
-
- DUK_ASSERT_CTX_VALID(to_ctx);
- DUK_ASSERT_CTX_VALID(from_ctx);
- DUK_ASSERT(to_ctx != NULL);
- DUK_ASSERT(from_ctx != NULL);
-
- if (to_ctx == from_ctx) {
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_CONTEXT);
- return;
- }
- if ((count < 0) ||
- (count > (duk_idx_t) to_thr->valstack_max)) {
- /* Maximum value check ensures 'nbytes' won't wrap below. */
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
- return;
- }
-
- nbytes = sizeof(duk_tval) * count;
- if (nbytes == 0) {
- return;
- }
- DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
- if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) {
- DUK_ERROR_API(to_thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
- src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
- if (src < (void *) from_thr->valstack_bottom) {
- DUK_ERROR_API(to_thr, DUK_STR_INVALID_COUNT);
- }
-
- /* copy values (no overlap even if to_ctx == from_ctx; that's not
- * allowed now anyway)
- */
- DUK_ASSERT(nbytes > 0);
- DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
-
- p = to_thr->valstack_top;
- to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes);
-
- if (is_copy) {
- /* Incref copies, keep originals. */
- q = to_thr->valstack_top;
- while (p < q) {
- DUK_TVAL_INCREF(to_thr, p); /* no side effects */
- p++;
- }
- } else {
- /* No net refcount change. */
- p = from_thr->valstack_top;
- q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes);
- from_thr->valstack_top = q;
-
- while (p > q) {
- p--;
- DUK_TVAL_SET_UNDEFINED(p);
- /* XXX: fast primitive to set a bunch of values to UNDEFINED */
- }
- }
-}
-
-/*
- * Get/require
- */
-
-DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_UNDEFINED(tv)) {
- return;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "undefined", DUK_STR_NOT_UNDEFINED);
- return; /* not reachable */
-}
-
-DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NULL(tv)) {
- return;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "null", DUK_STR_NOT_NULL);
- return; /* not reachable */
-}
-
-DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index) {
- duk_bool_t ret = 0; /* default: false */
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
- ret = DUK_TVAL_GET_BOOLEAN(tv);
- }
-
- DUK_ASSERT(ret == 0 || ret == 1);
- return ret;
-}
-
-DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BOOLEAN(tv)) {
- duk_bool_t ret = DUK_TVAL_GET_BOOLEAN(tv);
- DUK_ASSERT(ret == 0 || ret == 1);
- return ret;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "boolean", DUK_STR_NOT_BOOLEAN);
- return 0; /* not reachable */
-}
-
-DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index) {
- duk_double_union ret;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- ret.d = DUK_DOUBLE_NAN; /* default: NaN */
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NUMBER(tv)) {
- ret.d = DUK_TVAL_GET_NUMBER(tv);
- }
-
- /*
- * Number should already be in NaN-normalized form, but let's
- * normalize anyway.
- */
-
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
- return ret.d;
-}
-
-DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_NUMBER(tv)) {
- duk_double_union ret;
- ret.d = DUK_TVAL_GET_NUMBER(tv);
-
- /*
- * Number should already be in NaN-normalized form,
- * but let's normalize anyway.
- */
-
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&ret);
- return ret.d;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "number", DUK_STR_NOT_NUMBER);
- return DUK_DOUBLE_NAN; /* not reachable */
-}
-
-DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
-}
-
-DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
-}
-
-DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 1 /*require*/);
-}
-
-DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index) {
- /* Custom coercion for API */
- DUK_ASSERT_CTX_VALID(ctx);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 1 /*require*/);
-}
-
-DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- const char *ret;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* default: NULL, length 0 */
- ret = NULL;
- if (out_len) {
- *out_len = 0;
- }
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_STRING(tv)) {
- /* Here we rely on duk_hstring instances always being zero
- * terminated even if the actual string is not.
- */
- duk_hstring *h = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h != NULL);
- ret = (const char *) DUK_HSTRING_GET_DATA(h);
- if (out_len) {
- *out_len = DUK_HSTRING_GET_BYTELEN(h);
- }
- }
-
- return ret;
-}
-
-DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- duk_hthread *thr = (duk_hthread *) ctx;
- const char *ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Note: this check relies on the fact that even a zero-size string
- * has a non-NULL pointer.
- */
- ret = duk_get_lstring(ctx, index, out_len);
- if (ret) {
- return ret;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "string", DUK_STR_NOT_STRING);
- return NULL; /* not reachable */
-}
-
-DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- return duk_get_lstring(ctx, index, NULL);
-}
-
-DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- return duk_require_lstring(ctx, index, NULL);
-}
-
-DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_POINTER(tv)) {
- void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
- return (void *) p;
- }
-
- return NULL;
-}
-
-DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Note: here we must be wary of the fact that a pointer may be
- * valid and be a NULL.
- */
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_POINTER(tv)) {
- void *p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
- return (void *) p;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "pointer", DUK_STR_NOT_POINTER);
- return NULL; /* not reachable */
-}
-
-#if 0 /*unused*/
-DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(h != NULL);
- return (void *) h;
- }
-
- return NULL;
-}
-#endif
-
-DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- if (out_size != NULL) {
- *out_size = 0;
- }
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- if (out_size) {
- *out_size = DUK_HBUFFER_GET_SIZE(h);
- }
- return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
- }
-
- if (throw_flag) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
- }
- return NULL;
-}
-
-DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_helper(ctx, index, out_size, 0 /*throw_flag*/);
-}
-
-DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_helper(ctx, index, out_size, 1 /*throw_flag*/);
-}
-
-DUK_LOCAL void *duk__get_buffer_data_helper(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_bool_t throw_flag) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- if (out_size != NULL) {
- *out_size = 0;
- }
-
- tv = duk_get_tval(ctx, index);
- if (tv == NULL) {
- goto fail;
- }
-
- if (DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- if (out_size) {
- *out_size = DUK_HBUFFER_GET_SIZE(h);
- }
- return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- /* XXX: this is probably a useful shared helper: for a
- * duk_hbufferobject, get a validated buffer pointer/length.
- */
- duk_hbufferobject *h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- if (h_bufobj->buf != NULL &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
- duk_uint8_t *p;
-
- p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf);
- if (out_size != NULL) {
- *out_size = (duk_size_t) h_bufobj->length;
- }
- return (void *) (p + h_bufobj->offset);
- }
- /* if slice not fully valid, treat as error */
- }
- }
-
- fail:
- if (throw_flag) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "buffer", DUK_STR_NOT_BUFFER);
- }
- return NULL;
-}
-
-DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_data_helper(ctx, index, out_size, 0 /*throw_flag*/);
-}
-
-DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size) {
- return duk__get_buffer_data_helper(ctx, index, out_size, 1 /*throw_flag*/);
-}
-
-/* Raw helper for getting a value from the stack, checking its tag.
- * The tag cannot be a number because numbers don't have an internal
- * tag in the packed representation.
- */
-
-DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t index, duk_uint_t tag) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && (DUK_TVAL_GET_TAG(tv) == tag)) {
- duk_heaphdr *ret;
- ret = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
- return ret;
- }
-
- return (duk_heaphdr *) NULL;
-}
-
-DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t index) {
- return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
-}
-
-DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_STRING);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "string", DUK_STR_NOT_STRING);
- }
- return (duk_hstring *) h;
-}
-
-DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t index) {
- return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
-}
-
-DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "object", DUK_STR_NOT_OBJECT);
- }
- return (duk_hobject *) h;
-}
-
-DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t index) {
- return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
-}
-
-DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t index) {
- duk_heaphdr *h;
- h = duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_BUFFER);
- if (h == NULL) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, index, "buffer", DUK_STR_NOT_BUFFER);
- }
- return (duk_hbuffer *) h;
-}
-
-DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) {
- h = NULL;
- }
- return (duk_hthread *) h;
-}
-
-DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "thread", DUK_STR_NOT_THREAD);
- }
- return (duk_hthread *) h;
-}
-
-DUK_INTERNAL duk_hcompiledfunction *duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- h = NULL;
- }
- return (duk_hcompiledfunction *) h;
-}
-
-DUK_INTERNAL duk_hcompiledfunction *duk_require_hcompiledfunction(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "compiledfunction", DUK_STR_NOT_COMPILEDFUNCTION);
- }
- return (duk_hcompiledfunction *) h;
-}
-
-DUK_INTERNAL duk_hnativefunction *duk_get_hnativefunction(duk_context *ctx, duk_idx_t index) {
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && !DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- h = NULL;
- }
- return (duk_hnativefunction *) h;
-}
-
-DUK_INTERNAL duk_hnativefunction *duk_require_hnativefunction(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_IS_NATIVEFUNCTION(h))) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
- }
- return (duk_hnativefunction *) h;
-}
-
-DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- duk_hobject *h;
- duk_hnativefunction *f;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return NULL;
- }
- if (!DUK_TVAL_IS_OBJECT(tv)) {
- return NULL;
- }
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- if (!DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- return NULL;
- }
- DUK_ASSERT(DUK_HOBJECT_HAS_NATIVEFUNCTION(h));
- f = (duk_hnativefunction *) h;
-
- return f->func;
-}
-
-DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_c_function ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- ret = duk_get_c_function(ctx, index);
- if (!ret) {
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "nativefunction", DUK_STR_NOT_NATIVEFUNCTION);
- }
- return ret;
-}
-
-DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t index) {
- if (!duk_is_function(ctx, index)) {
- DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, index, "function", DUK_STR_NOT_FUNCTION);
- }
-}
-
-DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- return (duk_context *) duk_get_hthread(ctx, index);
-}
-
-DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- return (duk_context *) duk_require_hthread(ctx, index);
-}
-
-DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- void *ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL);
- return ret;
- }
-
- return (void *) NULL;
-}
-
-DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- void *ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(ret != NULL);
- return ret;
- }
-
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "heapobject", DUK_STR_UNEXPECTED_TYPE);
- return (void *) NULL; /* not reachable */
-}
-
-#if 0
-/* This would be pointless: we'd return NULL for both lightfuncs and
- * unexpected types.
- */
-DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
-}
-#endif
-
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
- * to an object). Return value is NULL if value is neither an object nor a
- * lightfunc.
- */
-DUK_INTERNAL duk_hobject *duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_to_object(ctx, index);
- return duk_require_hobject(ctx, index);
- }
-
- return NULL;
-}
-
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Returns NULL for a lightfunc.
- */
-DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- return NULL;
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
- return NULL; /* not reachable */
-}
-
-/* Useful for internal call sites where we either expect an object (function)
- * or a lightfunc. Accepts an object (returned as is) or a lightfunc (coerced
- * to an object). Return value is never NULL.
- */
-DUK_INTERNAL duk_hobject *duk_require_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- return DUK_TVAL_GET_OBJECT(tv);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_to_object(ctx, index);
- return duk_require_hobject(ctx, index);
- }
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, "object", DUK_STR_NOT_OBJECT);
- return NULL; /* not reachable */
-}
-
-DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
- duk_hobject *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
- DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
-
- h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) {
- h = NULL;
- }
- return h;
-}
-
-DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t index, duk_small_uint_t classnum) {
- duk_hthread *thr;
- duk_hobject *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
- DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
- thr = (duk_hthread *) ctx;
-
- h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, index, DUK_TAG_OBJECT);
- if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) {
- duk_hstring *h_class;
- h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
- DUK_UNREF(h_class);
-
- DUK_ERROR_REQUIRE_TYPE_INDEX(thr, index, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
- }
- return h;
-}
-
-DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
-
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED:
- case DUK_TAG_NULL:
- case DUK_TAG_BOOLEAN:
- case DUK_TAG_POINTER:
- return 0;
- case DUK_TAG_STRING: {
- duk_hstring *h = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h != NULL);
- return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
- }
- case DUK_TAG_OBJECT: {
- duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
- }
- case DUK_TAG_BUFFER: {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
- }
- case DUK_TAG_LIGHTFUNC: {
- duk_small_uint_t lf_flags;
- lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
- return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default:
- /* number */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- return 0;
- }
-
- DUK_UNREACHABLE();
-}
-
-DUK_INTERNAL void duk_set_length(duk_context *ctx, duk_idx_t index, duk_size_t length) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h = duk_get_hobject(ctx, index);
- if (!h) {
- return;
- }
-
- duk_hobject_set_length(thr, h, (duk_uint32_t) length); /* XXX: typing */
-}
-
-/*
- * Conversions and coercions
- *
- * The conversion/coercions are in-place operations on the value stack.
- * Some operations are implemented here directly, while others call a
- * helper in duk_js_ops.c after validating arguments.
- */
-
-/* E5 Section 8.12.8 */
-
-DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t index, duk_small_int_t func_stridx) {
- if (duk_get_prop_stridx(ctx, index, func_stridx)) {
- /* [ ... func ] */
- if (duk_is_callable(ctx, -1)) {
- duk_dup(ctx, index); /* -> [ ... func this ] */
- duk_call_method(ctx, 0); /* -> [ ... retval ] */
- if (duk_is_primitive(ctx, -1)) {
- duk_replace(ctx, index);
- return 1;
- }
- /* [ ... retval ]; popped below */
- }
- }
- duk_pop(ctx); /* [ ... func/retval ] -> [ ... ] */
- return 0;
-}
-
-DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- /* inline initializer for coercers[] is not allowed by old compilers like BCC */
- duk_small_int_t coercers[2];
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- coercers[0] = DUK_STRIDX_VALUE_OF;
- coercers[1] = DUK_STRIDX_TO_STRING;
-
- index = duk_require_normalize_index(ctx, index);
- obj = duk_require_hobject_or_lfunc(ctx, index);
-
- if (hint == DUK_HINT_NONE) {
- if (obj != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_DATE) {
- hint = DUK_HINT_STRING;
- } else {
- hint = DUK_HINT_NUMBER;
- }
- }
-
- if (hint == DUK_HINT_STRING) {
- coercers[0] = DUK_STRIDX_TO_STRING;
- coercers[1] = DUK_STRIDX_VALUE_OF;
- }
-
- if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[0])) {
- return;
- }
-
- if (duk__defaultvalue_coerce_attempt(ctx, index, coercers[1])) {
- return;
- }
-
- DUK_ERROR_TYPE(thr, DUK_STR_DEFAULTVALUE_COERCE_FAILED);
-}
-
-DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
-}
-
-DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
-}
-
-/* E5 Section 9.1 */
-DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint) {
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
-
- index = duk_require_normalize_index(ctx, index);
-
- if (!duk_check_type_mask(ctx, index, DUK_TYPE_MASK_OBJECT |
- DUK_TYPE_MASK_LIGHTFUNC)) {
- /* everything except object stay as is */
- return;
- }
- duk_to_defaultvalue(ctx, index, hint);
-}
-
-/* E5 Section 9.2 */
-DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_bool_t val;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
-
- val = duk_js_toboolean(tv);
- DUK_ASSERT(val == 0 || val == 1);
-
- /* Note: no need to re-lookup tv, conversion is side effect free */
- DUK_ASSERT(tv != NULL);
- DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */
- return val;
-}
-
-DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_double_t d;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- /* XXX: fastint? */
- d = duk_js_tonumber(thr, tv);
-
- /* Note: need to re-lookup because ToNumber() may have side effects */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
- return d;
-}
-
-/* XXX: combine all the integer conversions: they share everything
- * but the helper function for coercion.
- */
-
-typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
-
-DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t index, duk__toint_coercer coerce_func) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_double_t d;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- d = coerce_func(thr, tv);
-
- /* XXX: fastint? */
-
- /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
- return d;
-}
-
-DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index) {
- /* Value coercion (in stack): ToInteger(), E5 Section 9.4
- * API return value coercion: custom
- */
- DUK_ASSERT_CTX_VALID(ctx);
- (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
- return (duk_int_t) duk__api_coerce_d2i(ctx, index, 0 /*require*/);
-}
-
-DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index) {
- /* Value coercion (in stack): ToInteger(), E5 Section 9.4
- * API return value coercion: custom
- */
- DUK_ASSERT_CTX_VALID(ctx);
- (void) duk__to_int_uint_helper(ctx, index, duk_js_tointeger);
- return (duk_uint_t) duk__api_coerce_d2ui(ctx, index, 0 /*require*/);
-}
-
-DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_int32_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- ret = duk_js_toint32(thr, tv);
-
- /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv, ret); /* side effects */
- return ret;
-}
-
-DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_uint32_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- ret = duk_js_touint32(thr, tv);
-
- /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
- return ret;
-}
-
-DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_uint16_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- ret = duk_js_touint16(thr, tv);
-
- /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
- tv = duk_require_tval(ctx, index);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv, ret); /* side effects */
- return ret;
-}
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Special coercion for Uint8ClampedArray. */
-DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t index) {
- duk_double_t d;
- duk_double_t t;
- duk_uint8_t ret;
-
- /* XXX: Simplify this algorithm, should be possible to come up with
- * a shorter and faster algorithm by inspecting IEEE representation
- * directly.
- */
-
- d = duk_to_number(ctx, index);
- if (d <= 0.0) {
- return 0;
- } else if (d >= 255) {
- return 255;
- } else if (DUK_ISNAN(d)) {
- /* Avoid NaN-to-integer coercion as it is compiler specific. */
- return 0;
- }
-
- t = d - DUK_FLOOR(d);
- if (t == 0.5) {
- /* Exact halfway, round to even. */
- ret = (duk_uint8_t) d;
- ret = (ret + 1) & 0xfe; /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4
- * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4
- */
- } else {
- /* Not halfway, round to nearest. */
- ret = (duk_uint8_t) (d + 0.5);
- }
- return ret;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- (void) duk_to_string(ctx, index);
- return duk_require_lstring(ctx, index, out_len);
-}
-
-DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_to_string(ctx, -1);
- return 1;
-}
-
-DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_require_normalize_index(ctx, index);
-
- /* We intentionally ignore the duk_safe_call() return value and only
- * check the output type. This way we don't also need to check that
- * the returned value is indeed a string in the success case.
- */
-
- duk_dup(ctx, index);
- (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
- if (!duk_is_string(ctx, -1)) {
- /* Error: try coercing error to string once. */
- (void) duk_safe_call(ctx, duk__safe_to_string_raw, 1 /*nargs*/, 1 /*nrets*/);
- if (!duk_is_string(ctx, -1)) {
- /* Double error */
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR);
- } else {
- ;
- }
- } else {
- ;
- }
- DUK_ASSERT(duk_is_string(ctx, -1));
- DUK_ASSERT(duk_get_string(ctx, -1) != NULL);
-
- duk_replace(ctx, index);
- return duk_get_lstring(ctx, index, out_len);
-}
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
-DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t index) {
- (void) duk_safe_to_string(ctx, index);
- DUK_ASSERT(duk_is_string(ctx, index));
- DUK_ASSERT(duk_get_hstring(ctx, index) != NULL);
- return duk_get_hstring(ctx, index);
-}
-#endif
-
-/* Coerce top into Object.prototype.toString() output. */
-DUK_INTERNAL void duk_to_object_class_string_top(duk_context *ctx) {
- duk_hthread *thr;
- duk_uint_t typemask;
- duk_hstring *h_strclass;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- typemask = duk_get_type_mask(ctx, -1);
- if (typemask & DUK_TYPE_MASK_UNDEFINED) {
- h_strclass = DUK_HTHREAD_STRING_UC_UNDEFINED(thr);
- } else if (typemask & DUK_TYPE_MASK_NULL) {
- h_strclass = DUK_HTHREAD_STRING_UC_NULL(thr);
- } else {
- duk_hobject *h_obj;
-
- duk_to_object(ctx, -1);
- h_obj = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_obj != NULL);
-
- h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h_obj);
- }
- DUK_ASSERT(h_strclass != NULL);
-
- duk_pop(ctx);
- duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
-}
-
-#if !defined(DUK_USE_PARANOID_ERRORS)
-DUK_INTERNAL void duk_push_hobject_class_string(duk_context *ctx, duk_hobject *h) {
- duk_hthread *thr;
- duk_hstring *h_strclass;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(h != NULL);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_strclass = DUK_HOBJECT_GET_CLASS_STRING(thr->heap, h);
- DUK_ASSERT(h_strclass != NULL);
- duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
-}
-#endif /* !DUK_USE_PARANOID_ERRORS */
-
-/* XXX: other variants like uint, u32 etc */
-DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_tval tv_tmp;
- duk_double_t d, dmin, dmax;
- duk_int_t res;
- duk_bool_t clamped = 0;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */
-
- dmin = (duk_double_t) minval;
- dmax = (duk_double_t) maxval;
-
- if (d < dmin) {
- clamped = 1;
- res = minval;
- d = dmin;
- } else if (d > dmax) {
- clamped = 1;
- res = maxval;
- d = dmax;
- } else {
- res = (duk_int_t) d;
- }
- DUK_UNREF(d); /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */
- /* 'd' and 'res' agree here */
-
- /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
- tv = duk_get_tval(ctx, index);
- DUK_ASSERT(tv != NULL); /* not popped by side effect */
- DUK_TVAL_SET_TVAL(&tv_tmp, tv);
-#if defined(DUK_USE_FASTINT)
-#if (DUK_INT_MAX <= 0x7fffffffL)
- DUK_TVAL_SET_FASTINT_I32(tv, res);
-#else
- /* Clamping needed if duk_int_t is 64 bits. */
- if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) {
- DUK_TVAL_SET_FASTINT(tv, res);
- } else {
- DUK_TVAL_SET_NUMBER(tv, d);
- }
-#endif
-#else
- DUK_TVAL_SET_NUMBER(tv, d); /* no need to incref */
-#endif
- DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
-
- if (out_clamped) {
- *out_clamped = clamped;
- } else {
- /* coerced value is updated to value stack even when RangeError thrown */
- if (clamped) {
- DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE);
- }
- }
-
- return res;
-}
-
-DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t index, duk_idx_t minval, duk_idx_t maxval) {
- duk_bool_t dummy;
- return duk_to_int_clamped_raw(ctx, index, minval, maxval, &dummy);
-}
-
-DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t index, duk_int_t minval, duk_int_t maxval) {
- return duk_to_int_clamped_raw(ctx, index, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
-}
-
-DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
-
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED: {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
- break;
- }
- case DUK_TAG_NULL: {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
- break;
- }
- case DUK_TAG_BOOLEAN: {
- if (DUK_TVAL_GET_BOOLEAN(tv)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE);
- } else {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE);
- }
- break;
- }
- case DUK_TAG_STRING: {
- /* nop */
- goto skip_replace;
- }
- case DUK_TAG_OBJECT: {
- duk_to_primitive(ctx, index, DUK_HINT_STRING);
- return duk_to_string(ctx, index); /* Note: recursive call */
- }
- case DUK_TAG_BUFFER: {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
-
- /* Note: this allows creation of internal strings. */
-
- DUK_ASSERT(h != NULL);
- duk_push_lstring(ctx,
- (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
- (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
- break;
- }
- case DUK_TAG_POINTER: {
- void *ptr = DUK_TVAL_GET_POINTER(tv);
- if (ptr != NULL) {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) ptr);
- } else {
- /* Represent a null pointer as 'null' to be consistent with
- * the JX format variant. Native '%p' format for a NULL
- * pointer may be e.g. '(nil)'.
- */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
- }
- break;
- }
- case DUK_TAG_LIGHTFUNC: {
- /* Should match Function.prototype.toString() */
- duk_push_lightfunc_tostring(ctx, tv);
- break;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default: {
- /* number */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- duk_push_tval(ctx, tv);
- duk_numconv_stringify(ctx,
- 10 /*radix*/,
- 0 /*precision:shortest*/,
- 0 /*force_exponential*/);
- break;
- }
- }
-
- duk_replace(ctx, index);
-
- skip_replace:
- return duk_require_string(ctx, index);
-}
-
-DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t index) {
- duk_hstring *ret;
- DUK_ASSERT_CTX_VALID(ctx);
- duk_to_string(ctx, index);
- ret = duk_get_hstring(ctx, index);
- DUK_ASSERT(ret != NULL);
- return ret;
-}
-
-DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t mode) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hbuffer *h_buf;
- const duk_uint8_t *src_data;
- duk_size_t src_size;
- duk_uint8_t *dst_data;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(thr);
-
- index = duk_require_normalize_index(ctx, index);
-
- h_buf = duk_get_hbuffer(ctx, index);
- if (h_buf != NULL) {
- /* Buffer is kept as is, with the fixed/dynamic nature of the
- * buffer only changed if requested. An external buffer
- * is converted into a non-external dynamic buffer in a
- * duk_to_dynamic_buffer() call.
- */
- duk_uint_t tmp;
- duk_uint8_t *tmp_ptr;
-
- tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf);
- src_data = (const duk_uint8_t *) tmp_ptr;
- src_size = DUK_HBUFFER_GET_SIZE(h_buf);
-
- tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED);
- if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) ||
- mode == DUK_BUF_MODE_DONTCARE) {
- /* Note: src_data may be NULL if input is a zero-size
- * dynamic buffer.
- */
- dst_data = tmp_ptr;
- goto skip_copy;
- }
- } else {
- /* Non-buffer value is first ToString() coerced, then converted
- * to a buffer (fixed buffer is used unless a dynamic buffer is
- * explicitly requested).
- */
-
- src_data = (const duk_uint8_t *) duk_to_lstring(ctx, index, &src_size);
- }
-
- dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
- if (DUK_LIKELY(src_size > 0)) {
- /* When src_size == 0, src_data may be NULL (if source
- * buffer is dynamic), and dst_data may be NULL (if
- * target buffer is dynamic). Avoid zero-size memcpy()
- * with an invalid pointer.
- */
- DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
- }
- duk_replace(ctx, index);
- skip_copy:
-
- if (out_size) {
- *out_size = src_size;
- }
- return dst_data;
-}
-
-DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- void *res;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
-
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED:
- case DUK_TAG_NULL:
- case DUK_TAG_BOOLEAN:
- res = NULL;
- break;
- case DUK_TAG_POINTER:
- res = DUK_TVAL_GET_POINTER(tv);
- break;
- case DUK_TAG_STRING:
- case DUK_TAG_OBJECT:
- case DUK_TAG_BUFFER:
- /* Heap allocated: return heap pointer which is NOT useful
- * for the caller, except for debugging.
- */
- res = (void *) DUK_TVAL_GET_HEAPHDR(tv);
- break;
- case DUK_TAG_LIGHTFUNC:
- /* Function pointers do not always cast correctly to void *
- * (depends on memory and segmentation model for instance),
- * so they coerce to NULL.
- */
- res = NULL;
- break;
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default:
- /* number */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- res = NULL;
- break;
- }
-
- duk_push_pointer(ctx, res);
- duk_replace(ctx, index);
- return res;
-}
-
-DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_uint_t flags = 0; /* shared flags for a subset of types */
- duk_small_int_t proto = 0;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_require_normalize_index(ctx, index);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
-
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED:
- case DUK_TAG_NULL: {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
- break;
- }
- case DUK_TAG_BOOLEAN: {
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
- proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
- goto create_object;
- }
- case DUK_TAG_STRING: {
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
- proto = DUK_BIDX_STRING_PROTOTYPE;
- goto create_object;
- }
- case DUK_TAG_OBJECT: {
- /* nop */
- break;
- }
- case DUK_TAG_BUFFER: {
- /* A plain buffer coerces to a Duktape.Buffer because it's the
- * object counterpart of the plain buffer value. But it might
- * still make more sense to produce an ArrayBuffer here?
- */
-
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
-
- h_val = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE((duk_hobject *) h_bufobj));
- DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj));
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- DUK_ASSERT(h_bufobj->offset == 0);
- h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
- DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
- goto replace_value;
- }
- case DUK_TAG_POINTER: {
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
- proto = DUK_BIDX_POINTER_PROTOTYPE;
- goto create_object;
- }
- case DUK_TAG_LIGHTFUNC: {
- /* Lightfunc coerces to a Function instance with concrete
- * properties. Since 'length' is virtual for Duktape/C
- * functions, don't need to define that.
- *
- * The result is made extensible to mimic what happens to
- * strings:
- * > Object.isExtensible(Object('foo'))
- * true
- */
- duk_small_uint_t lf_flags;
- 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_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
- if (nargs == DUK_LFUNC_NARGS_VARARGS) {
- nargs = (duk_idx_t) DUK_VARARGS;
- }
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_NEWENV |
- DUK_HOBJECT_FLAG_STRICT |
- 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, nargs, flags);
-
- lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- 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);
- }
- duk_push_lightfunc_name(ctx, tv);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
-
- nf = duk_get_hnativefunction(ctx, -1);
- DUK_ASSERT(nf != NULL);
- nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
-
- /* Enable DUKFUNC exotic behavior once properties are set up. */
- DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf);
- goto replace_value;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default: {
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
- proto = DUK_BIDX_NUMBER_PROTOTYPE;
- goto create_object;
- }
- }
- return;
-
- create_object:
- (void) duk_push_object_helper(ctx, flags, proto);
-
- /* Note: Boolean prototype's internal value property is not writable,
- * but duk_xdef_prop_stridx() disregards the write protection. Boolean
- * instances are immutable.
- *
- * String and buffer special behaviors are already enabled which is not
- * ideal, but a write to the internal value is not affected by them.
- */
- duk_dup(ctx, index);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
-
- replace_value:
- duk_replace(ctx, index);
-}
-
-/*
- * Type checking
- */
-
-DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t index, duk_small_uint_t tag) {
- duk_tval *tv;
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
- return (DUK_TVAL_GET_TAG(tv) == tag);
-}
-
-DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t index, duk_uint_t flag_mask) {
- duk_hobject *obj;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj = duk_get_hobject(ctx, index);
- if (obj) {
- return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
- }
- return 0;
-}
-
-DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return DUK_TYPE_NONE;
- }
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED:
- return DUK_TYPE_UNDEFINED;
- case DUK_TAG_NULL:
- return DUK_TYPE_NULL;
- case DUK_TAG_BOOLEAN:
- return DUK_TYPE_BOOLEAN;
- case DUK_TAG_STRING:
- return DUK_TYPE_STRING;
- case DUK_TAG_OBJECT:
- return DUK_TYPE_OBJECT;
- case DUK_TAG_BUFFER:
- return DUK_TYPE_BUFFER;
- case DUK_TAG_POINTER:
- return DUK_TYPE_POINTER;
- case DUK_TAG_LIGHTFUNC:
- return DUK_TYPE_LIGHTFUNC;
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default:
- /* Note: number has no explicit tag (in 8-byte representation) */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- return DUK_TYPE_NUMBER;
- }
- DUK_UNREACHABLE();
-}
-
-#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
-DUK_LOCAL const char *duk__type_names[] = {
- "none",
- "undefined",
- "null",
- "boolean",
- "number",
- "string",
- "object",
- "buffer",
- "pointer",
- "lightfunc"
-};
-
-DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t index) {
- duk_int_t type_tag;
-
- type_tag = duk_get_type(ctx, index);
- DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
- DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
-
- return duk__type_names[type_tag];
-}
-#endif
-
-DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- return (duk_get_type(ctx, index) == type) ? 1 : 0;
-}
-
-DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return DUK_TYPE_MASK_NONE;
- }
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED:
- return DUK_TYPE_MASK_UNDEFINED;
- case DUK_TAG_NULL:
- return DUK_TYPE_MASK_NULL;
- case DUK_TAG_BOOLEAN:
- return DUK_TYPE_MASK_BOOLEAN;
- case DUK_TAG_STRING:
- return DUK_TYPE_MASK_STRING;
- case DUK_TAG_OBJECT:
- return DUK_TYPE_MASK_OBJECT;
- case DUK_TAG_BUFFER:
- return DUK_TYPE_MASK_BUFFER;
- case DUK_TAG_POINTER:
- return DUK_TYPE_MASK_POINTER;
- case DUK_TAG_LIGHTFUNC:
- return DUK_TYPE_MASK_LIGHTFUNC;
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default:
- /* Note: number has no explicit tag (in 8-byte representation) */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- return DUK_TYPE_MASK_NUMBER;
- }
- DUK_UNREACHABLE();
-}
-
-DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (duk_get_type_mask(ctx, index) & mask) {
- return 1;
- }
- if (mask & DUK_TYPE_MASK_THROW) {
- DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
- DUK_UNREACHABLE();
- }
- return 0;
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_UNDEFINED);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_NULL);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
- duk_small_uint_t tag;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
- tag = DUK_TVAL_GET_TAG(tv);
- return (tag == DUK_TAG_UNDEFINED) || (tag == DUK_TAG_NULL);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_BOOLEAN);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /*
- * Number is special because it doesn't have a specific
- * tag in the 8-byte representation.
- */
-
- /* XXX: shorter version for 12-byte representation? */
-
- tv = duk_get_tval(ctx, index);
- if (!tv) {
- return 0;
- }
- return DUK_TVAL_IS_NUMBER(tv);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index) {
- /* XXX: This will now return false for non-numbers, even though they would
- * coerce to NaN (as a general rule). In particular, duk_get_number()
- * returns a NaN for non-numbers, so should this function also return
- * true for non-numbers?
- */
-
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (!tv || !DUK_TVAL_IS_NUMBER(tv)) {
- return 0;
- }
- return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_STRING);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_OBJECT);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_BUFFER);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_POINTER);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__tag_check(ctx, index, DUK_TAG_LIGHTFUNC);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index) {
- duk_hobject *obj;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- obj = duk_get_hobject(ctx, index);
- if (obj) {
- return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
- }
- return 0;
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_LIGHTFUNC(tv)) {
- return 1;
- }
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_BOUND);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_NATIVEFUNCTION);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_BOUND);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk__obj_flag_any_default_false(ctx,
- index,
- DUK_HOBJECT_FLAG_THREAD);
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
- }
- return 0;
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
- }
- return 0;
-}
-
-DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index) {
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv = duk_get_tval(ctx, index);
- if (tv && DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
- }
- return 0;
-}
-
-DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
- duk_uint_t sanity;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h = duk_get_hobject(ctx, index);
-
- sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
- do {
- if (!h) {
- return DUK_ERR_NONE;
- }
- if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
- return DUK_ERR_EVAL_ERROR;
- }
- if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) {
- return DUK_ERR_RANGE_ERROR;
- }
- if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) {
- return DUK_ERR_REFERENCE_ERROR;
- }
- if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) {
- return DUK_ERR_SYNTAX_ERROR;
- }
- if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) {
- return DUK_ERR_TYPE_ERROR;
- }
- if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) {
- return DUK_ERR_URI_ERROR;
- }
- if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) {
- return DUK_ERR_ERROR;
- }
-
- h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
- } while (--sanity > 0);
-
- return DUK_ERR_NONE;
-}
-
-/*
- * Pushers
- */
-
-DUK_INTERNAL void duk_push_tval(duk_context *ctx, duk_tval *tv) {
- duk_hthread *thr;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(tv != NULL);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_TVAL(tv_slot, tv);
- DUK_TVAL_INCREF(thr, tv); /* no side effects */
-}
-
-DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
-
- /* Because value stack init policy is 'undefined above top',
- * we don't need to write, just assert.
- */
- thr->valstack_top++;
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
-}
-
-DUK_EXTERNAL void duk_push_null(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_NULL(tv_slot);
-}
-
-DUK_EXTERNAL void duk_push_boolean(duk_context *ctx, duk_bool_t val) {
- duk_hthread *thr;
- duk_tval *tv_slot;
- duk_small_int_t b;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_BOOLEAN(tv_slot, b);
-}
-
-DUK_EXTERNAL void duk_push_true(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
-}
-
-DUK_EXTERNAL void duk_push_false(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
-}
-
-/* normalize NaN which may not match our canonical internal NaN */
-DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
- duk_hthread *thr;
- duk_tval *tv_slot;
- duk_double_union du;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- du.d = val;
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_NUMBER(tv_slot, du.d);
-}
-
-DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
-#if defined(DUK_USE_FASTINT)
- duk_hthread *thr;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- tv_slot = thr->valstack_top++;
-#if DUK_INT_MAX <= 0x7fffffffL
- DUK_TVAL_SET_FASTINT_I32(tv_slot, (duk_int32_t) val);
-#else
- if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) {
- DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
- } else {
- duk_double_t = (duk_double_t) val;
- DUK_TVAL_SET_NUMBER(tv_slot, d);
- }
-#endif
-#else /* DUK_USE_FASTINT */
- duk_hthread *thr;
- duk_tval *tv_slot;
- duk_double_t d;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- d = (duk_double_t) val;
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_NUMBER(tv_slot, d);
-#endif /* DUK_USE_FASTINT */
-}
-
-DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
-#if defined(DUK_USE_FASTINT)
- duk_hthread *thr;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- tv_slot = thr->valstack_top++;
-#if DUK_UINT_MAX <= 0xffffffffUL
- DUK_TVAL_SET_FASTINT_U32(tv_slot, (duk_uint32_t) val);
-#else
- if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */
- /* XXX: take advantage of val being unsigned, no need to mask */
- DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
- } else {
- duk_double_t = (duk_double_t) val;
- DUK_TVAL_SET_NUMBER(tv_slot, d);
- }
-#endif
-#else /* DUK_USE_FASTINT */
- duk_hthread *thr;
- duk_tval *tv_slot;
- duk_double_t d;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- d = (duk_double_t) val;
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_NUMBER(tv_slot, d);
-#endif /* DUK_USE_FASTINT */
-}
-
-DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv_slot;
- duk_double_union du;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- DUK_DBLUNION_SET_NAN(&du);
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_NUMBER(tv_slot, du.d);
-}
-
-DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* check stack before interning (avoid hanging temp) */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
-
- /* NULL with zero length represents an empty string; NULL with higher
- * length is also now trated like an empty string although it is
- * a bit dubious. This is unlike duk_push_string() which pushes a
- * 'null' if the input string is a NULL.
- */
- if (!str) {
- len = 0;
- }
-
- /* Check for maximum string length */
- if (len > DUK_HSTRING_MAX_BYTELEN) {
- DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
- }
-
- h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
- DUK_ASSERT(h != NULL);
-
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_STRING(tv_slot, h);
- DUK_HSTRING_INCREF(thr, h); /* no side effects */
-
- return (const char *) DUK_HSTRING_GET_DATA(h);
-}
-
-DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (str) {
- return duk_push_lstring(ctx, str, DUK_STRLEN(str));
- } else {
- duk_push_null(ctx);
- return NULL;
- }
-}
-
-#ifdef DUK_USE_FILE_IO
-/* This is a bit clunky because it is ANSI C portable. Should perhaps
- * relocate to another file because this is potentially platform
- * dependent.
- */
-DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_file *f = NULL;
- char *buf;
- long sz; /* ANSI C typing */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (!path) {
- goto fail;
- }
- f = DUK_FOPEN(path, "rb");
- if (!f) {
- goto fail;
- }
- if (DUK_FSEEK(f, 0, SEEK_END) < 0) {
- goto fail;
- }
- sz = DUK_FTELL(f);
- if (sz < 0) {
- goto fail;
- }
- if (DUK_FSEEK(f, 0, SEEK_SET) < 0) {
- goto fail;
- }
- buf = (char *) duk_push_fixed_buffer(ctx, (duk_size_t) sz);
- DUK_ASSERT(buf != NULL);
- if ((duk_size_t) DUK_FREAD(buf, 1, (size_t) sz, f) != (duk_size_t) sz) {
- goto fail;
- }
- (void) DUK_FCLOSE(f); /* ignore fclose() error */
- f = NULL;
- return duk_to_string(ctx, -1);
-
- fail:
- if (f) {
- DUK_FCLOSE(f);
- }
-
- if (flags != 0) {
- DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
- duk_push_undefined(ctx);
- } else {
- /* XXX: string not shared because it is conditional */
- DUK_ERROR_TYPE(thr, "read file error");
- }
- return NULL;
-}
-#else
-DUK_EXTERNAL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(path);
-
- if (flags != 0) {
- DUK_ASSERT(flags == DUK_STRING_PUSH_SAFE); /* only flag now */
- duk_push_undefined(ctx);
- } else {
- /* XXX: string not shared because it is conditional */
- DUK_ERROR_UNSUPPORTED(thr, "file I/O disabled");
- }
- return NULL;
-}
-#endif /* DUK_USE_FILE_IO */
-
-DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) {
- duk_hthread *thr;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK__CHECK_SPACE();
- tv_slot = thr->valstack_top++;
- DUK_TVAL_SET_POINTER(tv_slot, val);
-}
-
-DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) {
- duk_hthread *thr;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- thr = (duk_hthread *) ctx;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
- DUK__CHECK_SPACE();
-
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */
- tv_slot = thr->valstack_top++;
-
- if (DUK_UNLIKELY(thr->callstack_top == 0)) {
- if (check_object_coercible) {
- goto type_error;
- }
- /* 'undefined' already on stack top */
- } else {
- duk_tval *tv;
-
- /* 'this' binding is just before current activation's bottom */
- DUK_ASSERT(thr->valstack_bottom > thr->valstack);
- tv = thr->valstack_bottom - 1;
- if (check_object_coercible &&
- (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) {
- /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */
- goto type_error;
- }
-
- DUK_TVAL_SET_TVAL(tv_slot, tv);
- DUK_TVAL_INCREF(thr, tv);
- }
- return;
-
- type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
-}
-
-DUK_EXTERNAL void duk_push_this(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk__push_this_helper(ctx, 0 /*check_object_coercible*/);
-}
-
-DUK_INTERNAL void duk_push_this_check_object_coercible(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
-}
-
-DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) {
- duk_hobject *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
- duk_to_object(ctx, -1);
- h = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h != NULL);
- return h;
-}
-
-DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) {
- duk_hstring *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
- duk_to_string(ctx, -1);
- h = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h != NULL);
- return h;
-}
-
-DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
-
- DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */
- DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */
- DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */
-
- return thr->valstack_bottom - 1;
-}
-
-DUK_EXTERNAL void duk_push_current_function(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
-
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- duk_push_tval(ctx, &act->tv_func);
- } else {
- duk_push_undefined(ctx);
- }
-}
-
-DUK_EXTERNAL void duk_push_current_thread(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
-
- if (thr->heap->curr_thread) {
- duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread);
- } else {
- duk_push_undefined(ctx);
- }
-}
-
-DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
-}
-
-/* XXX: size optimize */
-DUK_LOCAL void duk__push_stash(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE)) {
- DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
- duk_pop(ctx);
- duk_push_object_internal(ctx);
- duk_dup_top(ctx);
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
- }
- duk_remove(ctx, -2);
-}
-
-DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_heap *heap;
- DUK_ASSERT_CTX_VALID(ctx);
- heap = thr->heap;
- DUK_ASSERT(heap->heap_object != NULL);
- duk_push_hobject(ctx, heap->heap_object);
- duk__push_stash(ctx);
-}
-
-DUK_EXTERNAL void duk_push_global_stash(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_push_global_object(ctx);
- duk__push_stash(ctx);
-}
-
-DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- if (!target_ctx) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return; /* not reached */
- }
- duk_push_hobject(ctx, (duk_hobject *) target_ctx);
- duk__push_stash(ctx);
-}
-
-/* XXX: duk_ssize_t would be useful here */
-DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
- duk_int_t len;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_UNREF(ctx);
-
- /* NUL terminator handling doesn't matter here */
- len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
- if (len < (duk_int_t) sz) {
- /* Return value of 'sz' or more indicates output was (potentially)
- * truncated.
- */
- return (duk_int_t) len;
- }
- return -1;
-}
-
-DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
- duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
- duk_bool_t pushed_buf = 0;
- void *buf;
- duk_int_t len; /* XXX: duk_ssize_t */
- const char *res;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* special handling of fmt==NULL */
- if (!fmt) {
- duk_hstring *h_str;
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
- h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr); /* rely on interning, must be this string */
- return (const char *) DUK_HSTRING_GET_DATA(h_str);
- }
-
- /* initial estimate based on format string */
- sz = DUK_STRLEN(fmt) + 16; /* format plus something to avoid just missing */
- if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) {
- sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
- }
- DUK_ASSERT(sz > 0);
-
- /* Try to make do with a stack buffer to avoid allocating a temporary buffer.
- * This works 99% of the time which is quite nice.
- */
- for (;;) {
- va_list ap_copy; /* copied so that 'ap' can be reused */
-
- if (sz <= sizeof(stack_buf)) {
- buf = stack_buf;
- } else if (!pushed_buf) {
- pushed_buf = 1;
- buf = duk_push_dynamic_buffer(ctx, sz);
- } else {
- buf = duk_resize_buffer(ctx, -1, sz);
- }
- DUK_ASSERT(buf != NULL);
-
- DUK_VA_COPY(ap_copy, ap);
- len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap_copy);
- va_end(ap_copy);
- if (len >= 0) {
- break;
- }
-
- /* failed, resize and try again */
- sz = sz * 2;
- if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) {
- DUK_ERROR_API(thr, DUK_STR_SPRINTF_TOO_LONG);
- }
- }
-
- /* Cannot use duk_to_string() on the buffer because it is usually
- * larger than 'len'. Also, 'buf' is usually a stack buffer.
- */
- res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
- if (pushed_buf) {
- duk_remove(ctx, -2);
- }
- return res;
-}
-
-DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) {
- va_list ap;
- const char *ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* allow fmt==NULL */
- va_start(ap, fmt);
- ret = duk_push_vsprintf(ctx, fmt, ap);
- va_end(ap);
-
- return ret;
-}
-
-DUK_INTERNAL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv_slot;
- duk_hobject *h;
- duk_idx_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(prototype_bidx == -1 ||
- (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
-
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
-
- h = duk_hobject_alloc(thr->heap, hobject_flags_and_class);
- if (!h) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
-
- DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags));
-
- tv_slot = thr->valstack_top;
- DUK_TVAL_SET_OBJECT(tv_slot, h);
- DUK_HOBJECT_INCREF(thr, h); /* no side effects */
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
- thr->valstack_top++;
-
- /* object is now reachable */
-
- if (prototype_bidx >= 0) {
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]);
- } else {
- DUK_ASSERT(prototype_bidx == -1);
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
- }
-
- return ret;
-}
-
-DUK_INTERNAL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
- duk_hobject *h;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- ret = duk_push_object_helper(ctx, hobject_flags_and_class, -1);
- h = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto);
- return ret;
-}
-
-DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- return duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- DUK_BIDX_OBJECT_PROTOTYPE);
-}
-
-DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- duk_idx_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- ret = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_ARRAY_PART |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY),
- DUK_BIDX_ARRAY_PROTOTYPE);
-
- obj = duk_require_hobject(ctx, ret);
-
- /*
- * An array must have a 'length' property (E5 Section 15.4.5.2).
- * The special array behavior flag must only be enabled once the
- * length property has been added.
- *
- * The internal property must be a number (and preferably a
- * fastint if fastint support is enabled).
- */
-
- duk_push_int(ctx, 0);
-#if defined(DUK_USE_FASTINT)
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(duk_require_tval(ctx, -1)));
-#endif
-
- duk_hobject_define_property_internal(thr,
- obj,
- DUK_HTHREAD_STRING_LENGTH(thr),
- DUK_PROPDESC_FLAGS_W);
- DUK_HOBJECT_SET_EXOTIC_ARRAY(obj);
-
- return ret;
-}
-
-DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hthread *obj;
- duk_idx_t ret;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
-
- obj = duk_hthread_alloc(thr->heap,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_THREAD |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
- obj->state = DUK_HTHREAD_STATE_INACTIVE;
-#if defined(DUK_USE_ROM_STRINGS)
- /* Nothing to initialize, strs[] is in ROM. */
-#else
-#if defined(DUK_USE_HEAPPTR16)
- obj->strs16 = thr->strs16;
-#else
- obj->strs = thr->strs;
-#endif
-#endif
- DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
-
- /* make the new thread reachable */
- tv_slot = thr->valstack_top;
- DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
- DUK_HTHREAD_INCREF(thr, obj);
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
- thr->valstack_top++;
-
- /* important to do this *after* pushing, to make the thread reachable for gc */
- if (!duk_hthread_init_stacks(thr->heap, obj)) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
-
- /* initialize built-ins - either by copying or creating new ones */
- if (flags & DUK_THREAD_NEW_GLOBAL_ENV) {
- duk_hthread_create_builtin_objects(obj);
- } else {
- duk_hthread_copy_builtin_objects(thr, obj);
- }
-
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
-
- /* Initial stack size satisfies the stack spare constraints so there
- * is no need to require stack here.
- */
- DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
- DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
-
- return ret;
-}
-
-DUK_INTERNAL duk_idx_t duk_push_compiledfunction(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hcompiledfunction *obj;
- duk_idx_t ret;
- duk_tval *tv_slot;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
-
- /* Template functions are not strictly constructable (they don't
- * have a "prototype" property for instance), so leave the
- * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
- */
-
- obj = duk_hcompiledfunction_alloc(thr->heap,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
-
- DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
-
- tv_slot = thr->valstack_top;
- DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
- DUK_HOBJECT_INCREF(thr, obj);
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
- thr->valstack_top++;
-
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
-
- return ret;
-}
-
-DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hnativefunction *obj;
- duk_idx_t ret;
- duk_tval *tv_slot;
- duk_int16_t func_nargs;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
- if (func == NULL) {
- goto api_error;
- }
- if (nargs >= 0 && nargs < DUK_HNATIVEFUNCTION_NARGS_MAX) {
- func_nargs = (duk_int16_t) nargs;
- } else if (nargs == DUK_VARARGS) {
- func_nargs = DUK_HNATIVEFUNCTION_NARGS_VARARGS;
- } else {
- goto api_error;
- }
-
- obj = duk_hnativefunction_alloc(thr->heap, flags);
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
-
- obj->func = func;
- obj->nargs = func_nargs;
-
- DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld",
- (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs));
-
- tv_slot = thr->valstack_top;
- DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
- DUK_HOBJECT_INCREF(thr, obj);
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
- thr->valstack_top++;
-
- /* default prototype (Note: 'obj' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
-
- return ret;
-
- api_error:
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return 0; /* not reached */
-}
-
-DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
- duk_uint_t flags;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_NEWENV |
- DUK_HOBJECT_FLAG_STRICT |
- DUK_HOBJECT_FLAG_NOTAIL |
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
-
- return duk__push_c_function_raw(ctx, func, nargs, flags);
-}
-
-DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
- duk_uint_t flags;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_NEWENV |
- DUK_HOBJECT_FLAG_STRICT |
- DUK_HOBJECT_FLAG_NOTAIL |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
-
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
-}
-
-DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
- duk_uint_t flags;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_NATIVEFUNCTION |
- DUK_HOBJECT_FLAG_NEWENV |
- DUK_HOBJECT_FLAG_STRICT |
- DUK_HOBJECT_FLAG_NOTAIL |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
-
- (void) duk__push_c_function_raw(ctx, func, nargs, flags);
-}
-
-DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval tv_tmp;
- duk_small_uint_t lf_flags;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
-
- if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
- /* as is */
- } else if (nargs == DUK_VARARGS) {
- nargs = DUK_LFUNC_NARGS_VARARGS;
- } else {
- goto api_error;
- }
- if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) {
- goto api_error;
- }
- if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) {
- goto api_error;
- }
-
- lf_flags = DUK_LFUNC_FLAGS_PACK(magic, length, nargs);
- DUK_TVAL_SET_LIGHTFUNC(&tv_tmp, func, lf_flags);
- duk_push_tval(ctx, &tv_tmp); /* XXX: direct valstack write */
- DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
- return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
-
- api_error:
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- return 0; /* not reached */
-}
-
-DUK_INTERNAL duk_hbufferobject *duk_push_bufferobject_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hbufferobject *obj;
- duk_tval *tv_slot;
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(prototype_bidx >= 0);
-
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
-
- obj = duk_hbufferobject_alloc(thr->heap, hobject_flags_and_class);
- if (!obj) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
-
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
- DUK_ASSERT_HBUFFEROBJECT_VALID(obj);
-
- tv_slot = thr->valstack_top;
- DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
- DUK_HOBJECT_INCREF(thr, obj);
- thr->valstack_top++;
-
- return obj;
-}
-
-/* XXX: There's quite a bit of overlap with buffer creation handling in
- * duk_bi_buffer.c. Look for overlap and refactor.
- */
-#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,isview) \
- (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (isview))
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-static const duk_uint32_t duk__bufobj_flags_lookup[] = {
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DUKTAPE_BUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_NODEJS_BUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_DATAVIEW */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
-};
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-/* Only allow Duktape.Buffer when support disabled. */
-static const duk_uint32_t duk__bufobj_flags_lookup[] = {
- DUK__PACK_ARGS(DUK_HOBJECT_CLASS_BUFFER, DUK_BIDX_BUFFER_PROTOTYPE, DUK_HBUFFEROBJECT_ELEM_UINT8, 0, 0) /* DUK_BUFOBJ_DUKTAPE_BUFFER */
-};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#undef DUK__PACK_ARGS
-
-DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
- duk_hthread *thr;
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
- duk_uint32_t tmp;
- duk_uint_t classnum;
- duk_uint_t protobidx;
- duk_uint_t lookupidx;
- duk_uint_t uint_offset, uint_length, uint_added;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /* The underlying types for offset/length in duk_hbufferobject is
- * duk_uint_t; make sure argument values fit and that offset + length
- * does not wrap.
- */
- uint_offset = (duk_uint_t) byte_offset;
- uint_length = (duk_uint_t) byte_length;
- if (sizeof(duk_size_t) != sizeof(duk_uint_t)) {
- if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) {
- goto range_error;
- }
- }
- uint_added = uint_offset + uint_length;
- if (uint_added < uint_offset) {
- goto range_error;
- }
- DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
-
- DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */
- lookupidx = flags & 0x0f; /* 4 low bits */
- if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) {
- goto arg_error;
- }
- tmp = duk__bufobj_flags_lookup[lookupidx];
- classnum = tmp >> 24;
- protobidx = (tmp >> 16) & 0xff;
-
- h_val = duk_require_hbuffer(ctx, idx_buffer);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
- protobidx);
- DUK_ASSERT(h_bufobj != NULL);
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = uint_offset;
- h_bufobj->length = uint_length;
- h_bufobj->shift = (tmp >> 4) & 0x0f;
- h_bufobj->elem_type = (tmp >> 8) & 0xff;
- h_bufobj->is_view = tmp & 0x0f;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- /* TypedArray views need an automatic ArrayBuffer which must be
- * provided as .buffer property of the view. Just create a new
- * ArrayBuffer sharing the same underlying buffer.
- */
- if (flags & DUK_BUFOBJ_CREATE_ARRBUF) {
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
-
- DUK_ASSERT(h_bufobj != NULL);
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = uint_offset;
- h_bufobj->length = uint_length;
- DUK_ASSERT(h_bufobj->shift == 0);
- h_bufobj->elem_type = DUK_HBUFFEROBJECT_ELEM_UINT8;
- DUK_ASSERT(h_bufobj->is_view == 0);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
- }
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
- return;
-
- range_error:
- DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
- return; /* not reached */
-
- arg_error:
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_CALL_ARGS);
- return; /* not reached */
-}
-
-DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
- duk_hobject *proto;
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- duk_bool_t noblame_fileline;
-#endif
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_UNREF(filename);
- DUK_UNREF(line);
-
- /* Error code also packs a tracedata related flag. */
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE;
-#endif
- err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
-
- /* error gets its 'name' from the prototype */
- proto = duk_error_prototype_from_code(thr, err_code);
- ret = duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
- proto);
-
- /* ... and its 'message' from an instance property */
- if (fmt) {
- duk_push_vsprintf(ctx, fmt, ap);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
- } else {
- /* If no explicit message given, put error code into message field
- * (as a number). This is not fully in keeping with the Ecmascript
- * error model because messages are supposed to be strings (Error
- * constructors use ToString() on their argument). However, it's
- * probably more useful than having a separate 'code' property.
- */
- duk_push_int(ctx, err_code);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
- }
-
- /* XXX: .code = err_code disabled, not sure if useful */
-
- /* Creation time error augmentation */
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- /* filename may be NULL in which case file/line is not recorded */
- duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */
-#endif
-
- return ret;
-}
-
-DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
- va_list ap;
- duk_idx_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- va_start(ap, fmt);
- ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- va_end(ap);
- return ret;
-}
-
-#if !defined(DUK_USE_VARIADIC_MACROS)
-DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
- const char *filename = duk_api_global_filename;
- duk_int_t line = duk_api_global_line;
- va_list ap;
- duk_idx_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_api_global_filename = NULL;
- duk_api_global_line = 0;
- va_start(ap, fmt);
- ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- va_end(ap);
- return ret;
-}
-#endif /* DUK_USE_VARIADIC_MACROS */
-
-DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv_slot;
- duk_hbuffer *h;
- void *buf_data;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* check stack first */
- if (thr->valstack_top >= thr->valstack_end) {
- DUK_ERROR_API(thr, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
- }
-
- /* Check for maximum buffer length. */
- if (size > DUK_HBUFFER_MAX_BYTELEN) {
- DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
- }
-
- h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
- if (!h) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
-
- tv_slot = thr->valstack_top;
- DUK_TVAL_SET_BUFFER(tv_slot, h);
- DUK_HBUFFER_INCREF(thr, h);
- thr->valstack_top++;
-
- return (void *) buf_data;
-}
-
-DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t ret;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
-
- if (ptr == NULL) {
- goto push_undefined;
- }
-
- switch ((int) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
- case DUK_HTYPE_STRING:
- duk_push_hstring(ctx, (duk_hstring *) ptr);
- break;
- case DUK_HTYPE_OBJECT:
- duk_push_hobject(ctx, (duk_hobject *) ptr);
- break;
- case DUK_HTYPE_BUFFER:
- duk_push_hbuffer(ctx, (duk_hbuffer *) ptr);
- break;
- default:
- goto push_undefined;
- }
- return ret;
-
- push_undefined:
- duk_push_undefined(ctx);
- return ret;
-}
-
-DUK_INTERNAL duk_idx_t duk_push_object_internal(duk_context *ctx) {
- return duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- -1); /* no prototype */
-}
-
-DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) {
- duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(h != NULL);
- DUK_TVAL_SET_STRING(&tv, h);
- duk_push_tval(ctx, &tv);
-}
-
-DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
- DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
- duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
-}
-
-DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) {
- duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(h != NULL);
- DUK_TVAL_SET_OBJECT(&tv, h);
- duk_push_tval(ctx, &tv);
-}
-
-DUK_INTERNAL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) {
- duk_tval tv;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(h != NULL);
- DUK_TVAL_SET_BUFFER(&tv, h);
- duk_push_tval(ctx, &tv);
-}
-
-DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
- DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
- duk_push_hobject(ctx, thr->builtins[builtin_idx]);
-}
-
-/*
- * Poppers
- */
-
-DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (DUK_UNLIKELY(count < 0)) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
- return;
- }
-
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) {
- DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
- }
-
- /*
- * Must be very careful here, every DECREF may cause reallocation
- * of our valstack.
- */
-
- /* XXX: inlined DECREF macro would be nice here: no NULL check,
- * refzero queueing but no refzero algorithm run (= no pointer
- * instability), inline code.
- */
-
- /* XXX: optimize loops */
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
- while (count > 0) {
- count--;
- tv = --thr->valstack_top; /* tv points to element just below prev top */
- DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
- }
-#else
- tv = thr->valstack_top;
- while (count > 0) {
- count--;
- tv--;
- DUK_ASSERT(tv >= thr->valstack_bottom);
- DUK_TVAL_SET_UNDEFINED(tv);
- }
- thr->valstack_top = tv;
-#endif
-
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
-}
-
-/* Popping one element is called so often that when footprint is not an issue,
- * compile a specialized function for it.
- */
-#if defined(DUK_USE_PREFER_SIZE)
-DUK_EXTERNAL void duk_pop(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 1);
-}
-#else
-DUK_EXTERNAL void duk_pop(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- DUK_ASSERT_CTX_VALID(ctx);
-
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
- DUK_ERROR_API(thr, DUK_STR_POP_TOO_MANY);
- }
-
- tv = --thr->valstack_top; /* tv points to element just below prev top */
- DUK_ASSERT(tv >= thr->valstack_bottom);
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
-#else
- DUK_TVAL_SET_UNDEFINED(tv);
-#endif
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
-}
-#endif /* !DUK_USE_PREFER_SIZE */
-
-DUK_EXTERNAL void duk_pop_2(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 2);
-}
-
-DUK_EXTERNAL void duk_pop_3(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
- duk_pop_n(ctx, 3);
-}
-
-/*
- * Error throwing
- */
-
-DUK_EXTERNAL void duk_throw(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
-
- if (thr->valstack_top == thr->valstack_bottom) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
-
- /* Errors are augmented when they are created, not when they are
- * thrown or re-thrown. The current error handler, however, runs
- * just before an error is thrown.
- */
-
- /* Sync so that augmentation sees up-to-date activations, NULL
- * thr->ptr_curr_pc so that it's not used if side effects occur
- * in augmentation or longjmp handling.
- */
- duk_hthread_sync_and_null_currpc(thr);
-
-#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_err_augment_error_throw(thr);
-#endif
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
-
- /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
- * need to check that here. If the value is NULL, a panic occurs because
- * we can't return.
- */
-
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
-}
-
-DUK_EXTERNAL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(thr->heap->fatal_func != NULL);
-
- DUK_D(DUK_DPRINT("fatal error occurred, code %ld, message %s",
- (long) err_code, (const char *) err_msg));
-
- /* fatal_func should be noreturn, but noreturn declarations on function
- * pointers has a very spotty support apparently so it's not currently
- * done.
- */
- thr->heap->fatal_func(ctx, err_code, err_msg);
-
- DUK_PANIC(DUK_ERR_API_ERROR, "fatal handler returned");
-}
-
-DUK_EXTERNAL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- duk_throw(ctx);
-}
-
-DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
- va_list ap;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- va_start(ap, fmt);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- va_end(ap);
- duk_throw(ctx);
-}
-
-#if !defined(DUK_USE_VARIADIC_MACROS)
-DUK_EXTERNAL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
- const char *filename;
- duk_int_t line;
- va_list ap;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- filename = duk_api_global_filename;
- line = duk_api_global_line;
- duk_api_global_filename = NULL;
- duk_api_global_line = 0;
-
- va_start(ap, fmt);
- duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
- va_end(ap);
- duk_throw(ctx);
-}
-#endif /* DUK_USE_VARIADIC_MACROS */
-
-/*
- * Comparison
- */
-
-DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv1, *tv2;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv1 = duk_get_tval(ctx, index1);
- tv2 = duk_get_tval(ctx, index2);
- if ((tv1 == NULL) || (tv2 == NULL)) {
- return 0;
- }
-
- /* Coercion may be needed, the helper handles that by pushing the
- * tagged values to the stack.
- */
- return duk_js_equals(thr, tv1, tv2);
-}
-
-DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
- duk_tval *tv1, *tv2;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- tv1 = duk_get_tval(ctx, index1);
- tv2 = duk_get_tval(ctx, index2);
- if ((tv1 == NULL) || (tv2 == NULL)) {
- return 0;
- }
-
- /* No coercions or other side effects, so safe */
- return duk_js_strict_equals(tv1, tv2);
-}
-
-/*
- * instanceof
- */
-
-DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2) {
- duk_tval *tv1, *tv2;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- /* Index validation is strict, which differs from duk_equals().
- * The strict behavior mimics how instanceof itself works, e.g.
- * it is a TypeError if rval is not a -callable- object. It would
- * be somewhat inconsistent if rval would be allowed to be
- * non-existent without a TypeError.
- */
- tv1 = duk_require_tval(ctx, index1);
- DUK_ASSERT(tv1 != NULL);
- tv2 = duk_require_tval(ctx, index2);
- DUK_ASSERT(tv2 != NULL);
-
- return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2);
-}
-
-/*
- * Lightfunc
- */
-
-DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
- duk_c_function func;
-
- DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
-
- /* Lightfunc name, includes Duktape/C native function pointer, which
- * can often be used to locate the function from a symbol table.
- * The name also includes the 16-bit duk_tval flags field because it
- * includes the magic value. Because a single native function often
- * provides different functionality depending on the magic value, it
- * seems reasonably to include it in the name.
- *
- * On the other hand, a complicated name increases string table
- * pressure in low memory environments (but only when function name
- * is accessed).
- */
-
- func = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv);
- duk_push_sprintf(ctx, "light_");
- duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func));
- duk_push_sprintf(ctx, "_%04x", (unsigned int) DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv));
- duk_concat(ctx, 3);
-}
-
-DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
- DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
-
- duk_push_string(ctx, "function ");
- duk_push_lightfunc_name(ctx, tv);
- duk_push_string(ctx, "() {\"light\"}");
- duk_concat(ctx, 3);
-}
-
-/*
- * Function pointers
- *
- * Printing function pointers is non-portable, so we do that by hex printing
- * bytes from memory.
- */
-
-DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz) {
- duk_uint8_t buf[32 * 2];
- duk_uint8_t *p, *q;
- duk_small_uint_t i;
- duk_small_uint_t t;
-
- DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */
-
- p = buf;
-#if defined(DUK_USE_INTEGER_LE)
- q = ptr + sz;
-#else
- q = ptr;
-#endif
- for (i = 0; i < sz; i++) {
-#if defined(DUK_USE_INTEGER_LE)
- t = *(--q);
-#else
- t = *(q++);
-#endif
- *p++ = duk_lc_digits[t >> 4];
- *p++ = duk_lc_digits[t & 0x0f];
- }
-
- duk_push_lstring(ctx, (const char *) buf, sz * 2);
-}
-
-#if !defined(DUK_USE_PARANOID_ERRORS)
-/*
- * Push readable string summarizing duk_tval. The operation is side effect
- * free and will only throw from internal errors (e.g. out of memory).
- * This is used by e.g. property access code to summarize a key/base safely,
- * and is not intended to be fast (but small and safe).
- */
-
-#define DUK__READABLE_STRING_MAXCHARS 32
-
-/* String sanitizer which escapes ASCII control characters and a few other
- * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
- * question marks. No errors are thrown for any input string, except in out
- * of memory situations.
- */
-DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) {
- duk_hthread *thr;
- const duk_uint8_t *p, *p_start, *p_end;
- duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS +
- 2 /*quotes*/ + 3 /*periods*/];
- duk_uint8_t *q;
- duk_ucodepoint_t cp;
- duk_small_uint_t nchars;
-
- DUK_ASSERT_CTX_VALID(ctx);
- DUK_ASSERT(h_input != NULL);
- thr = (duk_hthread *) ctx;
-
- p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
- p = p_start;
- q = buf;
-
- nchars = 0;
- *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
- for (;;) {
- if (p >= p_end) {
- break;
- }
- if (nchars == DUK__READABLE_STRING_MAXCHARS) {
- *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
- *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
- *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
- break;
- }
- if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
- if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) {
- DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */
- DUK_ASSERT((cp >> 4) <= 0x0f);
- *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH;
- *q++ = (duk_uint8_t) DUK_ASC_LC_X;
- *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4];
- *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f];
- } else {
- q += duk_unicode_encode_xutf8(cp, q);
- }
- } else {
- p++; /* advance manually */
- *q++ = (duk_uint8_t) DUK_ASC_QUESTION;
- }
- nchars++;
- }
- *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
-
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf));
-}
-
-DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) {
- duk_hthread *thr;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- if (tv == NULL) {
- duk_push_string(ctx, "none");
- } else {
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_STRING: {
- duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv));
- break;
- }
- case DUK_TAG_OBJECT: {
- duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- duk_push_hobject_class_string(ctx, h);
- break;
- }
- case DUK_TAG_BUFFER: {
- /* XXX: Hex encoded, length limited buffer summary here? */
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
- break;
- }
- case DUK_TAG_POINTER: {
- /* Surround with parentheses like in JX, ensures NULL pointer
- * is distinguishable from null value ("(null)" vs "null").
- */
- duk_push_tval(ctx, tv);
- duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1));
- duk_remove(ctx, -2);
- break;
- }
- default: {
- duk_push_tval(ctx, tv);
- break;
- }
- }
- }
-
- return duk_to_string(ctx, -1);
-}
-
-DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t index) {
- DUK_ASSERT_CTX_VALID(ctx);
- return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, index));
-}
-#endif /* !DUK_USE_PARANOID_ERRORS */
-
-#undef DUK__CHECK_SPACE
-#undef DUK__PACK_ARGS
-#undef DUK__READABLE_STRING_MAXCHARS
-#line 1 "duk_api_string.c"
-/*
- * String manipulation
- */
-
-/* include removed: duk_internal.h */
-
-DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uint_t count;
- duk_uint_t i;
- duk_size_t idx;
- duk_size_t len;
- duk_hstring *h;
- duk_uint8_t *buf;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- if (DUK_UNLIKELY(count_in <= 0)) {
- if (count_in < 0) {
- DUK_ERROR_API(thr, DUK_STR_INVALID_COUNT);
- return;
- }
- DUK_ASSERT(count_in == 0);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
- return;
- }
- count = (duk_uint_t) count_in;
-
- if (is_join) {
- duk_size_t t1, t2, limit;
- h = duk_to_hstring(ctx, -((duk_idx_t) count) - 1);
- DUK_ASSERT(h != NULL);
-
- /* A bit tricky overflow test, see doc/code-issues.rst. */
- t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
- t2 = (duk_size_t) (count - 1);
- limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
- if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
- /* Combined size of separators already overflows */
- goto error_overflow;
- }
- len = (duk_size_t) (t1 * t2);
- } else {
- len = (duk_size_t) 0;
- }
-
- for (i = count; i >= 1; i--) {
- duk_size_t new_len;
- duk_to_string(ctx, -((duk_idx_t) i));
- h = duk_require_hstring(ctx, -((duk_idx_t) i));
- new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
-
- /* Impose a string maximum length, need to handle overflow
- * correctly.
- */
- if (new_len < len || /* wrapped */
- new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) {
- goto error_overflow;
- }
- len = new_len;
- }
-
- DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
- (unsigned long) count, (unsigned long) len));
-
- /* use stack allocated buffer to ensure reachability in errors (e.g. intern error) */
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, len);
- DUK_ASSERT(buf != NULL);
-
- /* [... (sep) str1 str2 ... strN buf] */
-
- idx = 0;
- for (i = count; i >= 1; i--) {
- if (is_join && i != count) {
- h = duk_require_hstring(ctx, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
- DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
- idx += DUK_HSTRING_GET_BYTELEN(h);
- }
- h = duk_require_hstring(ctx, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
- DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
- idx += DUK_HSTRING_GET_BYTELEN(h);
- }
-
- DUK_ASSERT(idx == len);
-
- /* [... (sep) str1 str2 ... strN buf] */
-
- /* get rid of the strings early to minimize memory use before intern */
-
- if (is_join) {
- duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */
- duk_pop_n(ctx, count);
- } else {
- duk_replace(ctx, -((duk_idx_t) count) - 1); /* overwrite str1 */
- duk_pop_n(ctx, count-1);
- }
-
- /* [... buf] */
-
- (void) duk_to_string(ctx, -1);
-
- /* [... res] */
- return;
-
- error_overflow:
- DUK_ERROR_RANGE(thr, DUK_STR_CONCAT_RESULT_TOO_LONG);
-}
-
-DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk__concat_and_join_helper(ctx, count, 0 /*is_join*/);
-}
-
-DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- duk__concat_and_join_helper(ctx, count, 1 /*is_join*/);
-}
-
-/* XXX: could map/decode be unified with duk_unicode_support.c code?
- * Case conversion needs also the character surroundings though.
- */
-
-DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_input;
- const duk_uint8_t *p, *p_start, *p_end;
- duk_codepoint_t cp;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h_input = duk_require_hstring(ctx, index);
- DUK_ASSERT(h_input != NULL);
-
- p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
- p = p_start;
-
- for (;;) {
- if (p >= p_end) {
- break;
- }
- cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
- callback(udata, cp);
- }
-}
-
-DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_input;
- duk_bufwriter_ctx bw_alloc;
- duk_bufwriter_ctx *bw;
- const duk_uint8_t *p, *p_start, *p_end;
- duk_codepoint_t cp;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_normalize_index(ctx, index);
-
- h_input = duk_require_hstring(ctx, index);
- DUK_ASSERT(h_input != NULL);
-
- bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* reasonable output estimate */
-
- p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
- p = p_start;
-
- for (;;) {
- /* XXX: could write output in chunks with fewer ensure calls,
- * but relative benefit would be small here.
- */
-
- if (p >= p_end) {
- break;
- }
- cp = (int) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
- cp = callback(udata, cp);
-
- DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
- }
-
- DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1);
- duk_replace(ctx, index);
-}
-
-DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_offset, duk_size_t end_offset) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h;
- duk_hstring *res;
- duk_size_t start_byte_offset;
- duk_size_t end_byte_offset;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_require_normalize_index(ctx, index);
- h = duk_require_hstring(ctx, index);
- DUK_ASSERT(h != NULL);
-
- if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
- end_offset = DUK_HSTRING_GET_CHARLEN(h);
- }
- if (start_offset > end_offset) {
- start_offset = end_offset;
- }
-
- DUK_ASSERT_DISABLE(start_offset >= 0);
- DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h));
- DUK_ASSERT_DISABLE(end_offset >= 0);
- DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
-
- /* guaranteed by string limits */
- DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
- DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
-
- start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset);
- end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
-
- DUK_ASSERT(end_byte_offset >= start_byte_offset);
- DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* guaranteed by string limits */
-
- /* no size check is necessary */
- res = duk_heap_string_intern_checked(thr,
- DUK_HSTRING_GET_DATA(h) + start_byte_offset,
- (duk_uint32_t) (end_byte_offset - start_byte_offset));
-
- duk_push_hstring(ctx, res);
- duk_replace(ctx, index);
-}
-
-/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
- * forwards with a callback to process codepoints?
- */
-DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h;
- const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
- const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
- duk_codepoint_t cp;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- index = duk_require_normalize_index(ctx, index);
- h = duk_require_hstring(ctx, index);
- DUK_ASSERT(h != NULL);
-
- p_start = DUK_HSTRING_GET_DATA(h);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
-
- p = p_start;
- while (p < p_end) {
- p_tmp1 = p;
- cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end);
- if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
- break;
- }
- p = p_tmp1;
- }
- q_start = p;
- if (p == p_end) {
- /* entire string is whitespace */
- q_end = p;
- goto scan_done;
- }
-
- p = p_end;
- while (p > p_start) {
- p_tmp1 = p;
- while (p > p_start) {
- p--;
- if (((*p) & 0xc0) != 0x80) {
- break;
- }
- }
- p_tmp2 = p;
-
- cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end);
- if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
- p = p_tmp1;
- break;
- }
- }
- q_end = p;
-
- scan_done:
- /* This may happen when forward and backward scanning disagree
- * (possible for non-extended-UTF-8 strings).
- */
- if (q_end < q_start) {
- q_end = q_start;
- }
-
- DUK_ASSERT(q_start >= p_start && q_start <= p_end);
- DUK_ASSERT(q_end >= p_start && q_end <= p_end);
- DUK_ASSERT(q_end >= q_start);
-
- DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
- (const void *) p_start, (const void *) p_end,
- (const void *) q_start, (const void *) q_end));
-
- if (q_start == p_start && q_end == p_end) {
- DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)"));
- return;
- }
-
- duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start));
- duk_replace(ctx, index);
-}
-
-DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h;
- duk_ucodepoint_t cp;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h = duk_require_hstring(ctx, index);
- DUK_ASSERT(h != NULL);
-
- DUK_ASSERT_DISABLE(char_offset >= 0); /* always true, arg is unsigned */
- if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
- return 0;
- }
-
- DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* guaranteed by string limits */
- cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset);
- return (duk_codepoint_t) cp;
-}
-#line 1 "duk_api_var.c"
-/*
- * Variable access
- */
-
-/* include removed: duk_internal.h */
-
-DUK_EXTERNAL void duk_get_var(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_hstring *h_varname;
- duk_small_int_t throw_flag = 1; /* always throw ReferenceError for unresolvable */
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h_varname = duk_require_hstring(ctx, -1); /* XXX: tostring? */
- DUK_ASSERT(h_varname != NULL);
-
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- (void) duk_js_getvar_activation(thr, act, h_varname, throw_flag); /* -> [ ... varname val this ] */
- } else {
- /* Outside any activation -> look up from global. */
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
- (void) duk_js_getvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, throw_flag);
- }
-
- /* [ ... varname val this ] (because throw_flag == 1, always resolved) */
-
- duk_pop(ctx);
- duk_remove(ctx, -2);
-
- /* [ ... val ] */
-
- /* Return value would be pointless: because throw_flag==1, we always
- * throw if the identifier doesn't resolve.
- */
- return;
-}
-
-DUK_EXTERNAL void duk_put_var(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_hstring *h_varname;
- duk_tval *tv_val;
- duk_small_int_t throw_flag;
-
- DUK_ASSERT_CTX_VALID(ctx);
-
- h_varname = duk_require_hstring(ctx, -2); /* XXX: tostring? */
- DUK_ASSERT(h_varname != NULL);
-
- tv_val = duk_require_tval(ctx, -1);
-
- throw_flag = duk_is_strict_call(ctx);
-
- act = duk_hthread_get_current_activation(thr);
- if (act) {
- duk_js_putvar_activation(thr, act, h_varname, tv_val, throw_flag); /* -> [ ... varname val this ] */
- } else {
- /* Outside any activation -> put to global. */
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
- duk_js_putvar_envrec(thr, thr->builtins[DUK_BIDX_GLOBAL_ENV], h_varname, tv_val, throw_flag);
- }
-
- /* [ ... varname val ] */
-
- duk_pop_2(ctx);
-
- /* [ ... ] */
-
- return;
-}
-
-DUK_EXTERNAL duk_bool_t duk_del_var(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
- return 0;
-}
-
-DUK_EXTERNAL duk_bool_t duk_has_var(duk_context *ctx) {
- DUK_ASSERT_CTX_VALID(ctx);
-
- DUK_ERROR_UNIMPLEMENTED_DEFMSG((duk_hthread *) ctx);
- return 0;
-}
-#line 1 "duk_bi_array.c"
-/*
- * Array built-ins
- *
- * Note that most Array built-ins are intentionally generic and work even
- * when the 'this' binding is not an Array instance. To ensure this,
- * Array algorithms do not assume "magical" Array behavior for the "length"
- * property, for instance.
- *
- * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and
- * [[Delete]] operations, but it's currently false throughout. Go through
- * all put/delete cases and check throw flag use. Need a new API primitive
- * which allows throws flag to be specified.
- *
- * XXX: array lengths above 2G won't work reliably. There are many places
- * where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff],
- * i.e. -33- bits). Although array 'length' cannot be written to be outside
- * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so)
- * some intermediate values may be above 0xffffffff and this may not be always
- * correctly handled now (duk_uint32_t is not enough for all algorithms).
- *
- * For instance, push() can legitimately write entries beyond length 0xffffffff
- * and cause a RangeError only at the end. To do this properly, the current
- * push() implementation tracks the array index using a 'double' instead of a
- * duk_uint32_t (which is somewhat awkward). See test-bi-array-push-maxlen.js.
- *
- * On using "put" vs. "def" prop
- * =============================
- *
- * Code below must be careful to use the appropriate primitive as it matters
- * for compliance. When using "put" there may be inherited properties in
- * Array.prototype which cause side effects when values are written. When
- * using "define" there are no such side effects, and many test262 test cases
- * check for this (for real world code, such side effects are very rare).
- * Both "put" and "define" are used in the E5.1 specification; as a rule,
- * "put" is used when modifying an existing array (or a non-array 'this'
- * binding) and "define" for setting values into a fresh result array.
- *
- * Also note that Array instance 'length' should be writable, but not
- * enumerable and definitely not configurable: even Duktape code internally
- * assumes that an Array instance will always have a 'length' property.
- * Preventing deletion of the property is critical.
- */
-
-/* include removed: duk_internal.h */
-
-/* Perform an intermediate join when this many elements have been pushed
- * on the value stack.
- */
-#define DUK__ARRAY_MID_JOIN_LIMIT 4096
-
-/* Shared entry code for many Array built-ins. Note that length is left
- * on stack (it could be popped, but that's not necessary).
- */
-DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) {
- duk_uint32_t len;
-
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
- len = duk_to_uint32(ctx, -1);
-
- /* -> [ ... ToObject(this) ToUint32(length) ] */
- return len;
-}
-
-DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
- /* Range limited to [0, 0x7fffffff] range, i.e. range that can be
- * represented with duk_int32_t. Use this when the method doesn't
- * handle the full 32-bit unsigned range correctly.
- */
- duk_uint32_t ret = duk__push_this_obj_len_u32(ctx);
- if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_ARRAY_LENGTH_OVER_2G);
- }
- return ret;
-}
-
-/*
- * Constructor
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
- duk_idx_t nargs;
- duk_double_t d;
- duk_uint32_t len;
- duk_idx_t i;
-
- nargs = duk_get_top(ctx);
- duk_push_array(ctx);
-
- if (nargs == 1 && duk_is_number(ctx, 0)) {
- /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
- d = duk_get_number(ctx, 0);
- len = duk_to_uint32(ctx, 0);
- if (((duk_double_t) len) != d) {
- return DUK_RET_RANGE_ERROR;
- }
-
- /* XXX: if 'len' is low, may want to ensure array part is kept:
- * the caller is likely to want a dense array.
- */
- duk_push_u32(ctx, len);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W); /* [ ToUint32(len) array ToUint32(len) ] -> [ ToUint32(len) array ] */
- return 1;
- }
-
- /* XXX: optimize by creating array into correct size directly, and
- * operating on the array part directly; values can be memcpy()'d from
- * value stack directly as long as refcounts are increased.
- */
- for (i = 0; i < nargs; i++) {
- duk_dup(ctx, i);
- duk_xdef_prop_index_wec(ctx, -2, (duk_uarridx_t) i);
- }
-
- duk_push_u32(ctx, (duk_uint32_t) nargs);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
- return 1;
-}
-
-/*
- * isArray()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
- duk_hobject *h;
-
- h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY);
- duk_push_boolean(ctx, (h != NULL));
- return 1;
-}
-
-/*
- * toString()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_JOIN);
-
- /* [ ... this func ] */
- if (!duk_is_callable(ctx, -1)) {
- /* Fall back to the initial (original) Object.toString(). We don't
- * currently have pointers to the built-in functions, only the top
- * level global objects (like "Array") so this is now done in a bit
- * of a hacky manner. It would be cleaner to push the (original)
- * function and use duk_call_method().
- */
-
- /* XXX: 'this' will be ToObject() coerced twice, which is incorrect
- * but should have no visible side effects.
- */
- DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
- duk_set_top(ctx, 0);
- return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */
- }
-
- /* [ ... this func ] */
-
- duk_insert(ctx, -2);
-
- /* [ ... func this ] */
-
- DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_call_method(ctx, 0);
-
- return 1;
-}
-
-/*
- * concat()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
- duk_idx_t i, n;
- duk_uarridx_t idx, idx_last;
- duk_uarridx_t j, len;
- duk_hobject *h;
-
- /* XXX: the insert here is a bit expensive if there are a lot of items.
- * It could also be special cased in the outermost for loop quite easily
- * (as the element is dup()'d anyway).
- */
-
- (void) duk_push_this_coercible_to_object(ctx);
- duk_insert(ctx, 0);
- n = duk_get_top(ctx);
- duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */
-
- /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
- * (which differs from the official algorithm). If no error is thrown, this
- * doesn't matter as the length is updated at the end. However, if an error
- * is thrown, the length will be unset. That shouldn't matter because the
- * caller won't get a reference to the intermediate value.
- */
-
- idx = 0;
- idx_last = 0;
- for (i = 0; i < n; i++) {
- DUK_ASSERT_TOP(ctx, n + 1);
-
- /* [ ToObject(this) item1 ... itemN arr ] */
-
- duk_dup(ctx, i);
- h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
- if (!h) {
- duk_xdef_prop_index_wec(ctx, -2, idx++);
- idx_last = idx;
- continue;
- }
-
- /* [ ToObject(this) item1 ... itemN arr item(i) ] */
-
- /* XXX: an array can have length higher than 32 bits; this is not handled
- * correctly now.
- */
- len = (duk_uarridx_t) duk_get_length(ctx, -1);
- for (j = 0; j < len; j++) {
- if (duk_get_prop_index(ctx, -1, j)) {
- /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
- duk_xdef_prop_index_wec(ctx, -3, idx++);
- idx_last = idx;
- } else {
- idx++;
- duk_pop(ctx);
-#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER)
- /* According to E5.1 Section 15.4.4.4 nonexistent trailing
- * elements do not affect 'length' of the result. Test262
- * and other engines disagree, so update idx_last here too.
- */
- idx_last = idx;
-#else
- /* Strict standard behavior, ignore trailing elements for
- * result 'length'.
- */
-#endif
- }
- }
- duk_pop(ctx);
- }
-
- /* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly
- * in the end, but because we're operating with an internal value which
- * is known to be an array, this should be equivalent.
- */
- duk_push_uarridx(ctx, idx_last);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
-
- DUK_ASSERT_TOP(ctx, n + 1);
- return 1;
-}
-
-/*
- * join(), toLocaleString()
- *
- * Note: checking valstack is necessary, but only in the per-element loop.
- *
- * Note: the trivial approach of pushing all the elements on the value stack
- * and then calling duk_join() fails when the array contains a large number
- * of elements. This problem can't be offloaded to duk_join() because the
- * elements to join must be handled here and have special handling. Current
- * approach is to do intermediate joins with very large number of elements.
- * There is no fancy handling; the prefix gets re-joined multiple times.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
- duk_uint32_t len, count;
- duk_uint32_t idx;
- duk_small_int_t to_locale_string = duk_get_current_magic(ctx);
- duk_idx_t valstack_required;
-
- /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and
- * setting the top essentially pushes an undefined to the stack,
- * thus defaulting to a comma separator.
- */
- duk_set_top(ctx, 1);
- if (duk_is_undefined(ctx, 0)) {
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA);
- } else {
- duk_to_string(ctx, 0);
- }
-
- len = duk__push_this_obj_len_u32(ctx);
-
- /* [ sep ToObject(this) len ] */
-
- DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (unsigned long) len));
-
- /* The extra (+4) is tight. */
- valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ?
- DUK__ARRAY_MID_JOIN_LIMIT : len) + 4;
- duk_require_stack(ctx, valstack_required);
-
- duk_dup(ctx, 0);
-
- /* [ sep ToObject(this) len sep ] */
-
- count = 0;
- idx = 0;
- for (;;) {
- if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */
- idx >= len) { /* end of loop (careful with len==0) */
- /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
- DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
- (long) count, (long) idx, (long) len));
- duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
- duk_dup(ctx, 0); /* -> [ sep ToObject(this) len str sep ] */
- duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */
- count = 1;
- }
- if (idx >= len) {
- /* if true, the stack already contains the final result */
- break;
- }
-
- duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx);
- if (duk_is_null_or_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
- } else {
- if (to_locale_string) {
- duk_to_object(ctx, -1);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING);
- duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */
- duk_call_method(ctx, 0);
- duk_to_string(ctx, -1);
- } else {
- duk_to_string(ctx, -1);
- }
- }
-
- count++;
- idx++;
- }
-
- /* [ sep ToObject(this) len sep result ] */
-
- return 1;
-}
-
-/*
- * pop(), push()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) {
- duk_uint32_t len;
- duk_uint32_t idx;
-
- DUK_ASSERT_TOP(ctx, 0);
- len = duk__push_this_obj_len_u32(ctx);
- if (len == 0) {
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
- return 0;
- }
- idx = len - 1;
-
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx);
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx);
- duk_push_u32(ctx, idx);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
- /* Note: 'this' is not necessarily an Array object. The push()
- * algorithm is supposed to work for other kinds of objects too,
- * so the algorithm has e.g. an explicit update for the 'length'
- * property which is normally "magical" in arrays.
- */
-
- duk_uint32_t len;
- duk_idx_t i, n;
-
- n = duk_get_top(ctx);
- len = duk__push_this_obj_len_u32(ctx);
-
- /* [ arg1 ... argN obj length ] */
-
- /* Technically Array.prototype.push() can create an Array with length
- * longer than 2^32-1, i.e. outside the 32-bit range. The final length
- * is *not* wrapped to 32 bits in the specification.
- *
- * This implementation tracks length with a uint32 because it's much
- * more practical.
- *
- * See: test-bi-array-push-maxlen.js.
- */
-
- if (len + (duk_uint32_t) n < len) {
- DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
- }
-
- for (i = 0; i < n; i++) {
- duk_dup(ctx, i);
- duk_put_prop_index(ctx, -3, len + i);
- }
- len += n;
-
- duk_push_u32(ctx, len);
- duk_dup_top(ctx);
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
-
- /* [ arg1 ... argN obj length new_length ] */
- return 1;
-}
-
-/*
- * sort()
- *
- * Currently qsort with random pivot. This is now really, really slow,
- * because there is no fast path for array parts.
- *
- * Signed indices are used because qsort() leaves and degenerate cases
- * may use a negative offset.
- */
-
-DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t idx1, duk_int_t idx2) {
- duk_bool_t have1, have2;
- duk_bool_t undef1, undef2;
- duk_small_int_t ret;
- duk_idx_t idx_obj = 1; /* fixed offsets in valstack */
- duk_idx_t idx_fn = 0;
- duk_hstring *h1, *h2;
-
- /* Fast exit if indices are identical. This is valid for a non-existent property,
- * for an undefined value, and almost always for ToString() coerced comparison of
- * arbitrary values (corner cases where this is not the case include e.g. a an
- * object with varying ToString() coercion).
- *
- * The specification does not prohibit "caching" of values read from the array, so
- * assuming equality for comparing an index with itself falls into the category of
- * "caching".
- *
- * Also, compareFn may be inconsistent, so skipping a call to compareFn here may
- * have an effect on the final result. The specification does not require any
- * specific behavior for inconsistent compare functions, so again, this fast path
- * is OK.
- */
-
- if (idx1 == idx2) {
- DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit",
- (long) idx1, (long) idx2));
- return 0;
- }
-
- have1 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx1);
- have2 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx2);
-
- DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
- (long) idx1, (long) idx2, (long) have1, (long) have2,
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
-
- if (have1) {
- if (have2) {
- ;
- } else {
- ret = -1;
- goto pop_ret;
- }
- } else {
- if (have2) {
- ret = 1;
- goto pop_ret;
- } else {
- ret = 0;
- goto pop_ret;
- }
- }
-
- undef1 = duk_is_undefined(ctx, -2);
- undef2 = duk_is_undefined(ctx, -1);
- if (undef1) {
- if (undef2) {
- ret = 0;
- goto pop_ret;
- } else {
- ret = 1;
- goto pop_ret;
- }
- } else {
- if (undef2) {
- ret = -1;
- goto pop_ret;
- } else {
- ;
- }
- }
-
- if (!duk_is_undefined(ctx, idx_fn)) {
- duk_double_t d;
-
- /* no need to check callable; duk_call() will do that */
- duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */
- duk_insert(ctx, -3); /* -> [ ... fn x y ] */
- duk_call(ctx, 2); /* -> [ ... res ] */
-
- /* The specification is a bit vague what to do if the return
- * value is not a number. Other implementations seem to
- * tolerate non-numbers but e.g. V8 won't apparently do a
- * ToNumber().
- */
-
- /* XXX: best behavior for real world compatibility? */
-
- d = duk_to_number(ctx, -1);
- if (d < 0.0) {
- ret = -1;
- } else if (d > 0.0) {
- ret = 1;
- } else {
- ret = 0;
- }
-
- duk_pop(ctx);
- DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
- return ret;
- }
-
- /* string compare is the default (a bit oddly) */
-
- h1 = duk_to_hstring(ctx, -2);
- h2 = duk_to_hstring(ctx, -1);
- DUK_ASSERT(h1 != NULL);
- DUK_ASSERT(h2 != NULL);
-
- ret = duk_js_string_compare(h1, h2); /* retval is directly usable */
- goto pop_ret;
-
- pop_ret:
- duk_pop_2(ctx);
- DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
- return ret;
-}
-
-DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) {
- duk_bool_t have_l, have_r;
- duk_idx_t idx_obj = 1; /* fixed offset in valstack */
-
- if (l == r) {
- return;
- }
-
- /* swap elements; deal with non-existent elements correctly */
- have_l = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- have_r = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
-
- if (have_r) {
- /* right exists, [[Put]] regardless whether or not left exists */
- duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- } else {
- duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
- duk_pop(ctx);
- }
-
- if (have_l) {
- duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
- } else {
- duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
- duk_pop(ctx);
- }
-}
-
-#if defined(DUK_USE_DDDPRINT)
-/* Debug print which visualizes the qsort partitioning process. */
-DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
- char buf[4096];
- char *ptr = buf;
- duk_int_t i, n;
- n = (duk_int_t) duk_get_length(ctx, 1);
- if (n > 4000) {
- n = 4000;
- }
- *ptr++ = '[';
- for (i = 0; i < n; i++) {
- if (i == pivot) {
- *ptr++ = '|';
- } else if (i == lo) {
- *ptr++ = '<';
- } else if (i == hi) {
- *ptr++ = '>';
- } else if (i >= lo && i <= hi) {
- *ptr++ = '-';
- } else {
- *ptr++ = ' ';
- }
- }
- *ptr++ = ']';
- *ptr++ = '\0';
-
- DUK_DDD(DUK_DDDPRINT("%s (lo=%ld, hi=%ld, pivot=%ld)",
- (const char *) buf, (long) lo, (long) hi, (long) pivot));
-}
-#endif
-
-DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_int_t p, l, r;
-
- /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
-
- DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
- (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1)));
-
- DUK_ASSERT_TOP(ctx, 3);
-
- /* In some cases it may be that lo > hi, or hi < 0; these
- * degenerate cases happen e.g. for empty arrays, and in
- * recursion leaves.
- */
-
- /* trivial cases */
- if (hi - lo < 1) {
- DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately"));
- return;
- }
- DUK_ASSERT(hi > lo);
- DUK_ASSERT(hi - lo + 1 >= 2);
-
- /* randomized pivot selection */
- p = lo + (duk_util_tinyrandom_get_bits(thr, 30) % (hi - lo + 1)); /* rnd in [lo,hi] */
- DUK_ASSERT(p >= lo && p <= hi);
- DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld",
- (long) lo, (long) hi, (long) p));
-
- /* move pivot out of the way */
- duk__array_sort_swap(ctx, p, lo);
- p = lo;
- DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
-
- l = lo + 1;
- r = hi;
- for (;;) {
- /* find elements to swap */
- for (;;) {
- DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld",
- (long) l, (long) r, (long) p));
- if (l >= hi) {
- break;
- }
- if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */
- break;
- }
- l++;
- }
- for (;;) {
- DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld",
- (long) l, (long) r, (long) p));
- if (r <= lo) {
- break;
- }
- if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */
- break;
- }
- r--;
- }
- if (l >= r) {
- goto done;
- }
- DUK_ASSERT(l < r);
-
- DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
-
- duk__array_sort_swap(ctx, l, r);
-
- DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
- l++;
- r--;
- }
- done:
- /* Note that 'l' and 'r' may cross, i.e. r < l */
- DUK_ASSERT(l >= lo && l <= hi);
- DUK_ASSERT(r >= lo && r <= hi);
-
- /* XXX: there's no explicit recursion bound here now. For the average
- * qsort recursion depth O(log n) that's not really necessary: e.g. for
- * 2**32 recursion depth would be about 32 which is OK. However, qsort
- * worst case recursion depth is O(n) which may be a problem.
- */
-
- /* move pivot to its final place */
- DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
- duk__array_sort_swap(ctx, lo, r);
-
-#if defined(DUK_USE_DDDPRINT)
- duk__debuglog_qsort_state(ctx, lo, hi, r);
-#endif
-
- DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1)));
- duk__array_qsort(ctx, lo, r - 1);
- duk__array_qsort(ctx, r + 1, hi);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
- duk_uint32_t len;
-
- /* XXX: len >= 0x80000000 won't work below because a signed type
- * is needed by qsort.
- */
- len = duk__push_this_obj_len_u32_limited(ctx);
-
- /* stack[0] = compareFn
- * stack[1] = ToObject(this)
- * stack[2] = ToUint32(length)
- */
-
- if (len > 0) {
- /* avoid degenerate cases, so that (len - 1) won't underflow */
- duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1));
- }
-
- DUK_ASSERT_TOP(ctx, 3);
- duk_pop(ctx);
- return 1; /* return ToObject(this) */
-}
-
-/*
- * splice()
- */
-
-/* XXX: this compiles to over 500 bytes now, even without special handling
- * for an array part. Uses signed ints so does not handle full array range correctly.
- */
-
-/* XXX: can shift() / unshift() use the same helper?
- * shift() is (close to?) <--> splice(0, 1)
- * unshift is (close to?) <--> splice(0, 0, [items])?
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
- duk_idx_t nargs;
- duk_uint32_t len;
- duk_bool_t have_delcount;
- duk_int_t item_count;
- duk_int_t act_start;
- duk_int_t del_count;
- duk_int_t i, n;
-
- DUK_UNREF(have_delcount);
-
- nargs = duk_get_top(ctx);
- if (nargs < 2) {
- duk_set_top(ctx, 2);
- nargs = 2;
- have_delcount = 0;
- } else {
- have_delcount = 1;
- }
-
- /* XXX: len >= 0x80000000 won't work below because we need to be
- * able to represent -len.
- */
- len = duk__push_this_obj_len_u32_limited(ctx);
-
- act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
- if (act_start < 0) {
- act_start = len + act_start;
- }
- DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len);
-
-#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
- if (have_delcount) {
-#endif
- del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
-#ifdef DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT
- } else {
- /* E5.1 standard behavior when deleteCount is not given would be
- * to treat it just like if 'undefined' was given, which coerces
- * ultimately to 0. Real world behavior is to splice to the end
- * of array, see test-bi-array-proto-splice-no-delcount.js.
- */
- del_count = len - act_start;
- }
-#endif
-
- DUK_ASSERT(nargs >= 2);
- item_count = (duk_int_t) (nargs - 2);
-
- DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start);
- DUK_ASSERT(del_count + act_start <= (duk_int_t) len);
-
- /* For now, restrict result array into 32-bit length range. */
- if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
- DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
- }
-
- duk_push_array(ctx);
-
- /* stack[0] = start
- * stack[1] = deleteCount
- * stack[2...nargs-1] = items
- * stack[nargs] = ToObject(this) -3
- * stack[nargs+1] = ToUint32(length) -2
- * stack[nargs+2] = result array -1
- */
-
- DUK_ASSERT_TOP(ctx, nargs + 3);
-
- /* Step 9: copy elements-to-be-deleted into the result array */
-
- for (i = 0; i < del_count; i++) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) {
- duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */
- } else {
- duk_pop(ctx);
- }
- }
- duk_push_u32(ctx, (duk_uint32_t) del_count);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
-
- /* Steps 12 and 13: reorganize elements to make room for itemCount elements */
-
- if (item_count < del_count) {
- /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1
- * -> [ A B F G H ] (conceptual intermediate step)
- * -> [ A B . F G H ] (placeholder marked)
- * [ A B C F G H ] (actual result at this point, C will be replaced)
- */
-
- DUK_ASSERT_TOP(ctx, nargs + 3);
-
- n = len - del_count;
- for (i = act_start; i < n; i++) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
- } else {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
- }
- }
-
- DUK_ASSERT_TOP(ctx, nargs + 3);
-
- /* loop iterator init and limit changed from standard algorithm */
- n = len - del_count + item_count;
- for (i = len - 1; i >= n; i--) {
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) i);
- }
-
- DUK_ASSERT_TOP(ctx, nargs + 3);
- } else if (item_count > del_count) {
- /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4
- * -> [ A B F G H ] (conceptual intermediate step)
- * -> [ A B . . . . F G H ] (placeholder marked)
- * [ A B C D E F F G H ] (actual result at this point)
- */
-
- DUK_ASSERT_TOP(ctx, nargs + 3);
-
- /* loop iterator init and limit changed from standard algorithm */
- for (i = len - del_count - 1; i >= act_start; i--) {
- if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
- } else {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
- }
- }
-
- DUK_ASSERT_TOP(ctx, nargs + 3);
- } else {
- /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3
- * -> [ A B F G H ] (conceptual intermediate step)
- * -> [ A B . . . F G H ] (placeholder marked)
- * [ A B C D E F G H ] (actual result at this point)
- */
- }
- DUK_ASSERT_TOP(ctx, nargs + 3);
-
- /* Step 15: insert itemCount elements into the hole made above */
-
- for (i = 0; i < item_count; i++) {
- duk_dup(ctx, i + 2); /* args start at index 2 */
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) (act_start + i));
- }
-
- /* Step 16: update length; note that the final length may be above 32 bit range
- * (but we checked above that this isn't the case here)
- */
-
- duk_push_u32(ctx, len - del_count + item_count);
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
-
- /* result array is already at the top of stack */
- DUK_ASSERT_TOP(ctx, nargs + 3);
- return 1;
-}
-
-/*
- * reverse()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
- duk_uint32_t len;
- duk_uint32_t middle;
- duk_uint32_t lower, upper;
- duk_bool_t have_lower, have_upper;
-
- len = duk__push_this_obj_len_u32(ctx);
- middle = len / 2;
-
- /* If len <= 1, middle will be 0 and for-loop bails out
- * immediately (0 < 0 -> false).
- */
-
- for (lower = 0; lower < middle; lower++) {
- DUK_ASSERT(len >= 2);
- DUK_ASSERT_TOP(ctx, 2);
-
- DUK_ASSERT(len >= lower + 1);
- upper = len - lower - 1;
-
- have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower);
- have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper);
-
- /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
-
- if (have_upper) {
- duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower);
- } else {
- duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower);
- duk_pop(ctx);
- }
-
- if (have_lower) {
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper);
- } else {
- duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper);
- duk_pop(ctx);
- }
-
- DUK_ASSERT_TOP(ctx, 2);
- }
-
- DUK_ASSERT_TOP(ctx, 2);
- duk_pop(ctx); /* -> [ ToObject(this) ] */
- return 1;
-}
-
-/*
- * slice()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
- duk_uint32_t len;
- duk_int_t start, end;
- duk_int_t i;
- duk_uarridx_t idx;
- duk_uint32_t res_length = 0;
-
- /* XXX: len >= 0x80000000 won't work below because we need to be
- * able to represent -len.
- */
- len = duk__push_this_obj_len_u32_limited(ctx);
- duk_push_array(ctx);
-
- /* stack[0] = start
- * stack[1] = end
- * stack[2] = ToObject(this)
- * stack[3] = ToUint32(length)
- * stack[4] = result array
- */
-
- start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
- if (start < 0) {
- start = len + start;
- }
- /* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
- * (the upper limit)?
- */
- if (duk_is_undefined(ctx, 1)) {
- end = len;
- } else {
- end = duk_to_int_clamped(ctx, 1, -((duk_int_t) len), (duk_int_t) len);
- if (end < 0) {
- end = len + end;
- }
- }
- DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len);
- DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len);
-
- idx = 0;
- for (i = start; i < end; i++) {
- DUK_ASSERT_TOP(ctx, 5);
- if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- duk_xdef_prop_index_wec(ctx, 4, idx);
- res_length = idx + 1;
- } else {
- duk_pop(ctx);
- }
- idx++;
- DUK_ASSERT_TOP(ctx, 5);
- }
-
- duk_push_u32(ctx, res_length);
- duk_xdef_prop_stridx(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
-
- DUK_ASSERT_TOP(ctx, 5);
- return 1;
-}
-
-/*
- * shift()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
- duk_uint32_t len;
- duk_uint32_t i;
-
- len = duk__push_this_obj_len_u32(ctx);
- if (len == 0) {
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
- return 0;
- }
-
- duk_get_prop_index(ctx, 0, 0);
-
- /* stack[0] = object (this)
- * stack[1] = ToUint32(length)
- * stack[2] = elem at index 0 (retval)
- */
-
- for (i = 1; i < len; i++) {
- DUK_ASSERT_TOP(ctx, 3);
- if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) {
- /* fromPresent = true */
- duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
- } else {
- /* fromPresent = false */
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
- duk_pop(ctx);
- }
- }
- duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1));
-
- duk_push_u32(ctx, (duk_uint32_t) (len - 1));
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LENGTH);
-
- DUK_ASSERT_TOP(ctx, 3);
- return 1;
-}
-
-/*
- * unshift()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
- duk_idx_t nargs;
- duk_uint32_t len;
- duk_uint32_t i;
-
- nargs = duk_get_top(ctx);
- len = duk__push_this_obj_len_u32(ctx);
-
- /* stack[0...nargs-1] = unshift args (vararg)
- * stack[nargs] = ToObject(this)
- * stack[nargs+1] = ToUint32(length)
- */
-
- DUK_ASSERT_TOP(ctx, nargs + 2);
-
- /* Note: unshift() may operate on indices above unsigned 32-bit range
- * and the final length may be >= 2**32. However, we restrict the
- * final result to 32-bit range for practicality.
- */
-
- if (len + (duk_uint32_t) nargs < len) {
- DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
- return DUK_RET_RANGE_ERROR;
- }
-
- i = len;
- while (i > 0) {
- DUK_ASSERT_TOP(ctx, nargs + 2);
- i--;
- /* k+argCount-1; note that may be above 32-bit range */
-
- if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) {
- /* fromPresent = true */
- /* [ ... ToObject(this) ToUint32(length) val ] */
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
- } else {
- /* fromPresent = false */
- /* [ ... ToObject(this) ToUint32(length) val ] */
- duk_pop(ctx);
- duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
- }
- DUK_ASSERT_TOP(ctx, nargs + 2);
- }
-
- for (i = 0; i < (duk_uint32_t) nargs; i++) {
- DUK_ASSERT_TOP(ctx, nargs + 2);
- duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
- duk_put_prop_index(ctx, -3, (duk_uarridx_t) i);
- DUK_ASSERT_TOP(ctx, nargs + 2);
- }
-
- DUK_ASSERT_TOP(ctx, nargs + 2);
- duk_push_u32(ctx, len + nargs);
- duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_LENGTH);
- return 1;
-}
-
-/*
- * indexOf(), lastIndexOf()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
- duk_idx_t nargs;
- duk_int_t i, len;
- duk_int_t from_index;
- duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
-
- /* lastIndexOf() needs to be a vararg function because we must distinguish
- * between an undefined fromIndex and a "not given" fromIndex; indexOf() is
- * made vararg for symmetry although it doesn't strictly need to be.
- */
-
- nargs = duk_get_top(ctx);
- duk_set_top(ctx, 2);
-
- /* XXX: must be able to represent -len */
- len = (duk_int_t) duk__push_this_obj_len_u32_limited(ctx);
- if (len == 0) {
- goto not_found;
- }
-
- /* Index clamping is a bit tricky, we must ensure that we'll only iterate
- * through elements that exist and that the specific requirements from E5.1
- * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially:
- *
- * - indexOf: clamp to [-len,len], negative handling -> [0,len],
- * if clamped result is len, for-loop bails out immediately
- *
- * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1],
- * if clamped result is -1, for-loop bails out immediately
- *
- * If fromIndex is not given, ToInteger(undefined) = 0, which is correct
- * for indexOf() but incorrect for lastIndexOf(). Hence special handling,
- * and why lastIndexOf() needs to be a vararg function.
- */
-
- if (nargs >= 2) {
- /* indexOf: clamp fromIndex to [-len, len]
- * (if fromIndex == len, for-loop terminates directly)
- *
- * lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
- * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
- */
- from_index = duk_to_int_clamped(ctx,
- 1,
- (idx_step > 0 ? -len : -len - 1),
- (idx_step > 0 ? len : len - 1));
- if (from_index < 0) {
- /* for lastIndexOf, result may be -1 (mark immediate termination) */
- from_index = len + from_index;
- }
- } else {
- /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
- * handle both indexOf and lastIndexOf specially here.
- */
- if (idx_step > 0) {
- from_index = 0;
- } else {
- from_index = len - 1;
- }
- }
-
- /* stack[0] = searchElement
- * stack[1] = fromIndex
- * stack[2] = object
- * stack[3] = length (not needed, but not popped above)
- */
-
- for (i = from_index; i >= 0 && i < len; i += idx_step) {
- DUK_ASSERT_TOP(ctx, 4);
-
- if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- DUK_ASSERT_TOP(ctx, 5);
- if (duk_strict_equals(ctx, 0, 4)) {
- duk_push_int(ctx, i);
- return 1;
- }
- }
-
- duk_pop(ctx);
- }
-
- not_found:
- duk_push_int(ctx, -1);
- return 1;
-}
-
-/*
- * every(), some(), forEach(), map(), filter()
- */
-
-#define DUK__ITER_EVERY 0
-#define DUK__ITER_SOME 1
-#define DUK__ITER_FOREACH 2
-#define DUK__ITER_MAP 3
-#define DUK__ITER_FILTER 4
-
-/* XXX: This helper is a bit awkward because the handling for the different iteration
- * callers is quite different. This now compiles to a bit less than 500 bytes, so with
- * 5 callers the net result is about 100 bytes / caller.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
- duk_uint32_t len;
- duk_uint32_t i;
- duk_uarridx_t k;
- duk_bool_t bval;
- duk_small_int_t iter_type = duk_get_current_magic(ctx);
- duk_uint32_t res_length = 0;
-
- /* each call this helper serves has nargs==2 */
- DUK_ASSERT_TOP(ctx, 2);
-
- len = duk__push_this_obj_len_u32(ctx);
- duk_require_callable(ctx, 0);
- /* if thisArg not supplied, behave as if undefined was supplied */
-
- if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
- duk_push_array(ctx);
- } else {
- duk_push_undefined(ctx);
- }
-
- /* stack[0] = callback
- * stack[1] = thisArg
- * stack[2] = object
- * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop)
- * stack[4] = result array (or undefined)
- */
-
- k = 0; /* result index for filter() */
- for (i = 0; i < len; i++) {
- DUK_ASSERT_TOP(ctx, 5);
-
- if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
-#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER)
- /* Real world behavior for map(): trailing non-existent
- * elements don't invoke the user callback, but are still
- * counted towards result 'length'.
- */
- if (iter_type == DUK__ITER_MAP) {
- res_length = i + 1;
- }
-#else
- /* Standard behavior for map(): trailing non-existent
- * elements don't invoke the user callback and are not
- * counted towards result 'length'.
- */
-#endif
- duk_pop(ctx);
- continue;
- }
-
- /* The original value needs to be preserved for filter(), hence
- * this funny order. We can't re-get the value because of side
- * effects.
- */
-
- duk_dup(ctx, 0);
- duk_dup(ctx, 1);
- duk_dup(ctx, -3);
- duk_push_u32(ctx, i);
- duk_dup(ctx, 2); /* [ ... val callback thisArg val i obj ] */
- duk_call_method(ctx, 3); /* -> [ ... val retval ] */
-
- switch (iter_type) {
- case DUK__ITER_EVERY:
- bval = duk_to_boolean(ctx, -1);
- if (!bval) {
- /* stack top contains 'false' */
- return 1;
- }
- break;
- case DUK__ITER_SOME:
- bval = duk_to_boolean(ctx, -1);
- if (bval) {
- /* stack top contains 'true' */
- return 1;
- }
- break;
- case DUK__ITER_FOREACH:
- /* nop */
- break;
- case DUK__ITER_MAP:
- duk_dup(ctx, -1);
- duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */
- res_length = i + 1;
- break;
- case DUK__ITER_FILTER:
- bval = duk_to_boolean(ctx, -1);
- if (bval) {
- duk_dup(ctx, -2); /* orig value */
- duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k);
- k++;
- res_length = k;
- }
- break;
- default:
- DUK_UNREACHABLE();
- break;
- }
- duk_pop_2(ctx);
-
- DUK_ASSERT_TOP(ctx, 5);
- }
-
- switch (iter_type) {
- case DUK__ITER_EVERY:
- duk_push_true(ctx);
- break;
- case DUK__ITER_SOME:
- duk_push_false(ctx);
- break;
- case DUK__ITER_FOREACH:
- duk_push_undefined(ctx);
- break;
- case DUK__ITER_MAP:
- case DUK__ITER_FILTER:
- DUK_ASSERT_TOP(ctx, 5);
- DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */
- duk_push_u32(ctx, res_length);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
- break;
- default:
- DUK_UNREACHABLE();
- break;
- }
-
- return 1;
-}
-
-/*
- * reduce(), reduceRight()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
- duk_idx_t nargs;
- duk_bool_t have_acc;
- duk_uint32_t i, len;
- duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */
-
- /* We're a varargs function because we need to detect whether
- * initialValue was given or not.
- */
- nargs = duk_get_top(ctx);
- DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
-
- duk_set_top(ctx, 2);
- len = duk__push_this_obj_len_u32(ctx);
- if (!duk_is_callable(ctx, 0)) {
- goto type_error;
- }
-
- /* stack[0] = callback fn
- * stack[1] = initialValue
- * stack[2] = object (coerced this)
- * stack[3] = length (not needed, but not popped above)
- * stack[4] = accumulator
- */
-
- have_acc = 0;
- if (nargs >= 2) {
- duk_dup(ctx, 1);
- have_acc = 1;
- }
- DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
- (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3)));
-
- /* For len == 0, i is initialized to len - 1 which underflows.
- * The condition (i < len) will then exit the for-loop on the
- * first round which is correct. Similarly, loop termination
- * happens by i underflowing.
- */
-
- for (i = (idx_step >= 0 ? 0 : len - 1);
- i < len; /* i >= 0 would always be true */
- i += idx_step) {
- DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
- (long) i, (long) len, (long) have_acc,
- (long) duk_get_top(ctx),
- (duk_tval *) duk_get_tval(ctx, 4)));
-
- DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
- (!have_acc && duk_get_top(ctx) == 4));
-
- if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) {
- continue;
- }
-
- if (!have_acc) {
- DUK_ASSERT_TOP(ctx, 4);
- duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
- have_acc = 1;
- DUK_ASSERT_TOP(ctx, 5);
- } else {
- DUK_ASSERT_TOP(ctx, 5);
- duk_dup(ctx, 0);
- duk_dup(ctx, 4);
- duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
- duk_push_u32(ctx, i);
- duk_dup(ctx, 2);
- DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
- (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4),
- (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_call(ctx, 4);
- DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_replace(ctx, 4);
- DUK_ASSERT_TOP(ctx, 5);
- }
- }
-
- if (!have_acc) {
- goto type_error;
- }
-
- DUK_ASSERT_TOP(ctx, 5);
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-
-#undef DUK__ARRAY_MID_JOIN_LIMIT
-
-#undef DUK__ITER_EVERY
-#undef DUK__ITER_SOME
-#undef DUK__ITER_FOREACH
-#undef DUK__ITER_MAP
-#undef DUK__ITER_FILTER
-#line 1 "duk_bi_boolean.c"
-/*
- * Boolean built-ins
- */
-
-/* include removed: duk_internal.h */
-
-/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
- * the primitive value to stack top, and optionally coerces with ToString().
- */
-DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) {
- duk_tval *tv;
- duk_hobject *h;
- duk_small_int_t coerce_tostring = duk_get_current_magic(ctx);
-
- /* XXX: there is room to use a shared helper here, many built-ins
- * check the 'this' type, and if it's an object, check its class,
- * then get its internal value, etc.
- */
-
- duk_push_this(ctx);
- tv = duk_get_tval(ctx, -1);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_BOOLEAN(tv)) {
- goto type_ok;
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_boolean(ctx, -1));
- goto type_ok;
- }
- }
-
- return DUK_RET_TYPE_ERROR;
-
- type_ok:
- if (coerce_tostring) {
- duk_to_string(ctx, -1);
- }
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_this;
-
- DUK_UNREF(thr);
-
- duk_to_boolean(ctx, 0);
-
- if (duk_is_constructor_call(ctx)) {
- /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
- duk_push_this(ctx);
- h_this = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_this != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
-
- DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
-
- duk_dup(ctx, 0); /* -> [ val obj val ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
- } /* unbalanced stack */
-
- return 1;
-}
-#line 1 "duk_bi_buffer.c"
-/*
- * Duktape.Buffer, Node.js Buffer, and Khronos/ES6 TypedArray built-ins
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Misc helpers
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK_HBUFFEROBJECT_ELEM_xxx to duk_hobject class number.
- * Sync with duk_hbufferobject.h and duk_hobject.h.
- */
-static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
- DUK_HOBJECT_CLASS_UINT8ARRAY,
- DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY,
- DUK_HOBJECT_CLASS_INT8ARRAY,
- DUK_HOBJECT_CLASS_UINT16ARRAY,
- DUK_HOBJECT_CLASS_INT16ARRAY,
- DUK_HOBJECT_CLASS_UINT32ARRAY,
- DUK_HOBJECT_CLASS_INT32ARRAY,
- DUK_HOBJECT_CLASS_FLOAT32ARRAY,
- DUK_HOBJECT_CLASS_FLOAT64ARRAY
-};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK_HBUFFEROBJECT_ELEM_xxx to prototype object built-in index.
- * Sync with duk_hbufferobject.h.
- */
-static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
- DUK_BIDX_UINT8ARRAY_PROTOTYPE,
- DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
- DUK_BIDX_INT8ARRAY_PROTOTYPE,
- DUK_BIDX_UINT16ARRAY_PROTOTYPE,
- DUK_BIDX_INT16ARRAY_PROTOTYPE,
- DUK_BIDX_UINT32ARRAY_PROTOTYPE,
- DUK_BIDX_INT32ARRAY_PROTOTYPE,
- DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
- DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
-};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Map DUK__FLX_xxx to byte size.
- */
-static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
- 1, /* DUK__FLD_8BIT */
- 2, /* DUK__FLD_16BIT */
- 4, /* DUK__FLD_32BIT */
- 4, /* DUK__FLD_FLOAT */
- 8, /* DUK__FLD_DOUBLE */
- 0 /* DUK__FLD_VARINT; not relevant here */
-};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Bitfield for each DUK_HBUFFEROBJECT_ELEM_xxx indicating which element types
- * are compatible with a blind byte copy for the TypedArray set() method (also
- * used for TypedArray constructor). Array index is target buffer elem type,
- * bitfield indicates compatible source types. The types must have same byte
- * size and they must be coercion compatible.
- */
-static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
-
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED
- * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00.
- */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED),
-
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT8 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8) |
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT8),
-
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT16 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
-
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT16 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT16) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT16),
-
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_UINT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
-
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_INT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_UINT32) |
- (1U << DUK_HBUFFEROBJECT_ELEM_INT32),
-
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT32 */
- (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT32),
-
- /* xxx -> DUK_HBUFFEROBJECT_ELEM_FLOAT64 */
- (1U << DUK_HBUFFEROBJECT_ELEM_FLOAT64)
-};
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Shared helper. */
-DUK_LOCAL duk_hbufferobject *duk__getrequire_bufobj_this(duk_context *ctx, duk_bool_t throw_flag) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_hbufferobject *h_this;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
-
- tv = duk_get_borrowed_this_tval(ctx);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- h_this = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h_this != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_this)) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
- return h_this;
- }
- }
-
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
- }
- return NULL;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that 'this' is a duk_hbufferobject and return a pointer to it. */
-DUK_LOCAL duk_hbufferobject *duk__get_bufobj_this(duk_context *ctx) {
- return duk__getrequire_bufobj_this(ctx, 0);
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that 'this' is a duk_hbufferobject and return a pointer to it
- * (NULL if not).
- */
-DUK_LOCAL duk_hbufferobject *duk__require_bufobj_this(duk_context *ctx) {
- return duk__getrequire_bufobj_this(ctx, 1);
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Check that value is a duk_hbufferobject and return a pointer to it. */
-DUK_LOCAL duk_hbufferobject *duk__require_bufobj_value(duk_context *ctx, duk_idx_t index) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_hbufferobject *h_obj;
-
- thr = (duk_hthread *) ctx;
-
- /* Don't accept relative indices now. */
- DUK_ASSERT(index >= 0);
-
- tv = duk_require_tval(ctx, index);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- h_obj = (duk_hbufferobject *) DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h_obj != NULL);
- if (DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_obj)) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_obj);
- return h_obj;
- }
- }
-
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
- return NULL; /* not reachable */
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_hbuffer *h_val) {
- duk_hthread *thr;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(h_bufobj != NULL);
- DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */
- DUK_ASSERT(h_val != NULL);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
- DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-}
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_LOCAL duk_hbufferobject *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) {
- duk_hbuffer *h_val;
- duk_hbufferobject *h_bufobj;
-
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
-
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- return h_bufobj;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Shared offset/length coercion helper. */
-DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
- duk_hbufferobject *h_bufarg,
- duk_idx_t idx_offset,
- duk_idx_t idx_length,
- duk_uint_t *out_offset,
- duk_uint_t *out_length,
- duk_bool_t throw_flag) {
- duk_hthread *thr;
- duk_int_t offset_signed;
- duk_int_t length_signed;
- duk_uint_t offset;
- duk_uint_t length;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- offset_signed = duk_to_int(ctx, idx_offset);
- if (offset_signed < 0) {
- goto fail_range;
- }
- offset = (duk_uint_t) offset_signed;
- if (offset > h_bufarg->length) {
- goto fail_range;
- }
- DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */
- DUK_ASSERT(offset <= h_bufarg->length);
-
- if (duk_is_undefined(ctx, idx_length)) {
- DUK_ASSERT(h_bufarg->length >= offset);
- length = h_bufarg->length - offset; /* >= 0 */
- } else {
- length_signed = duk_to_int(ctx, idx_length);
- if (length_signed < 0) {
- goto fail_range;
- }
- length = (duk_uint_t) length_signed;
- DUK_ASSERT(h_bufarg->length >= offset);
- if (length > h_bufarg->length - offset) {
- /* Unlike for negative arguments, some call sites
- * want length to be clamped if it's positive.
- */
- if (throw_flag) {
- goto fail_range;
- } else {
- length = h_bufarg->length - offset;
- }
- }
- }
- DUK_ASSERT_DISABLE(length >= 0); /* unsigned */
- DUK_ASSERT(offset + length <= h_bufarg->length);
-
- *out_offset = offset;
- *out_length = length;
- return;
-
- fail_range:
- DUK_ERROR_RANGE(thr, DUK_STR_INVALID_CALL_ARGS);
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Shared lenient buffer length clamping helper. No negative indices, no
- * element/byte shifting.
- */
-DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
- duk_hbufferobject *h_bufobj,
- duk_idx_t idx_start,
- duk_idx_t idx_end,
- duk_int_t *out_start_offset,
- duk_int_t *out_end_offset) {
- duk_int_t buffer_length;
- duk_int_t start_offset;
- duk_int_t end_offset;
-
- DUK_ASSERT(out_start_offset != NULL);
- DUK_ASSERT(out_end_offset != NULL);
-
- buffer_length = (duk_int_t) h_bufobj->length;
-
- /* undefined coerces to zero which is correct */
- start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length);
- if (duk_is_undefined(ctx, idx_end)) {
- end_offset = buffer_length;
- } else {
- end_offset = duk_to_int_clamped(ctx, idx_end, start_offset, buffer_length);
- }
-
- DUK_ASSERT(start_offset >= 0);
- DUK_ASSERT(start_offset <= buffer_length);
- DUK_ASSERT(end_offset >= 0);
- DUK_ASSERT(end_offset <= buffer_length);
- DUK_ASSERT(start_offset <= end_offset);
-
- *out_start_offset = start_offset;
- *out_end_offset = end_offset;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Shared lenient buffer length clamping helper. Indices are treated as
- * element indices (though output values are byte offsets) which only
- * really matters for TypedArray views as other buffer object have a zero
- * shift. Negative indices are counted from end of input slice; crossed
- * indices are clamped to zero length; and final indices are clamped
- * against input slice. Used for e.g. ArrayBuffer slice().
- */
-DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
- duk_hbufferobject *h_bufobj,
- duk_idx_t idx_start,
- duk_idx_t idx_end,
- duk_int_t *out_start_offset,
- duk_int_t *out_end_offset) {
- duk_int_t buffer_length;
- duk_int_t start_offset;
- duk_int_t end_offset;
-
- DUK_ASSERT(out_start_offset != NULL);
- DUK_ASSERT(out_end_offset != NULL);
-
- buffer_length = (duk_int_t) h_bufobj->length;
- buffer_length >>= h_bufobj->shift; /* as elements */
-
- /* Resolve start/end offset as element indices first; arguments
- * at idx_start/idx_end are element offsets. Working with element
- * indices first also avoids potential for wrapping.
- */
-
- start_offset = duk_to_int(ctx, idx_start);
- if (start_offset < 0) {
- start_offset = buffer_length + start_offset;
- }
- if (duk_is_undefined(ctx, idx_end)) {
- end_offset = buffer_length;
- } else {
- end_offset = duk_to_int(ctx, idx_end);
- if (end_offset < 0) {
- end_offset = buffer_length + end_offset;
- }
- }
- /* Note: start_offset/end_offset can still be < 0 here. */
-
- if (start_offset < 0) {
- start_offset = 0;
- } else if (start_offset > buffer_length) {
- start_offset = buffer_length;
- }
- if (end_offset < start_offset) {
- end_offset = start_offset;
- } else if (end_offset > buffer_length) {
- end_offset = buffer_length;
- }
- DUK_ASSERT(start_offset >= 0);
- DUK_ASSERT(start_offset <= buffer_length);
- DUK_ASSERT(end_offset >= 0);
- DUK_ASSERT(end_offset <= buffer_length);
- DUK_ASSERT(start_offset <= end_offset);
-
- /* Convert indices to byte offsets. */
- start_offset <<= h_bufobj->shift;
- end_offset <<= h_bufobj->shift;
-
- *out_start_offset = start_offset;
- *out_end_offset = end_offset;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Indexed read/write helpers (also used from outside this file)
- */
-
-DUK_INTERNAL void duk_hbufferobject_push_validated_read(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
- duk_double_union du;
-
- DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
-
- switch (h_bufobj->elem_type) {
- case DUK_HBUFFEROBJECT_ELEM_UINT8:
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
-#endif
- duk_push_uint(ctx, (duk_uint_t) du.uc[0]);
- break;
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- /* These are not needed when only Duktape.Buffer is supported. */
- case DUK_HBUFFEROBJECT_ELEM_INT8:
- duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]);
- break;
- case DUK_HBUFFEROBJECT_ELEM_UINT16:
- duk_push_uint(ctx, (duk_uint_t) du.us[0]);
- break;
- case DUK_HBUFFEROBJECT_ELEM_INT16:
- duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]);
- break;
- case DUK_HBUFFEROBJECT_ELEM_UINT32:
- duk_push_uint(ctx, (duk_uint_t) du.ui[0]);
- break;
- case DUK_HBUFFEROBJECT_ELEM_INT32:
- duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]);
- break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
- duk_push_number(ctx, (duk_double_t) du.f[0]);
- break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
- duk_push_number(ctx, (duk_double_t) du.d);
- break;
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
- default:
- DUK_UNREACHABLE();
- }
-}
-
-DUK_INTERNAL void duk_hbufferobject_validated_write(duk_context *ctx, duk_hbufferobject *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
- duk_double_union du;
-
- /* NOTE! Caller must ensure that any side effects from the
- * coercions below are safe. If that cannot be guaranteed
- * (which is normally the case), caller must coerce the
- * argument using duk_to_number() before any pointer
- * validations; the result of duk_to_number() always coerces
- * without side effects here.
- */
-
- switch (h_bufobj->elem_type) {
- case DUK_HBUFFEROBJECT_ELEM_UINT8:
- du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1);
- break;
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
- /* These are not needed when only Duktape.Buffer is supported. */
- case DUK_HBUFFEROBJECT_ELEM_UINT8CLAMPED:
- du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1);
- break;
- case DUK_HBUFFEROBJECT_ELEM_INT8:
- du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1);
- break;
- case DUK_HBUFFEROBJECT_ELEM_UINT16:
- du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1);
- break;
- case DUK_HBUFFEROBJECT_ELEM_INT16:
- du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1);
- break;
- case DUK_HBUFFEROBJECT_ELEM_UINT32:
- du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1);
- break;
- case DUK_HBUFFEROBJECT_ELEM_INT32:
- du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1);
- break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT32:
- du.f[0] = (duk_float_t) duk_to_number(ctx, -1);
- break;
- case DUK_HBUFFEROBJECT_ELEM_FLOAT64:
- du.d = (duk_double_t) duk_to_number(ctx, -1);
- break;
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
- default:
- DUK_UNREACHABLE();
- }
-
- DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size);
-}
-
-/*
- * Duktape.Buffer: constructor
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_buffer_constructor(duk_context *ctx) {
- duk_hthread *thr;
- duk_size_t buf_size;
- duk_small_int_t buf_dynamic;
- duk_uint8_t *buf_data;
- const duk_uint8_t *src_data;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /*
- * Constructor arguments are currently somewhat compatible with
- * (keep it that way if possible):
- *
- * http://nodejs.org/api/buffer.html
- *
- * Note that the ToBuffer() coercion (duk_to_buffer()) does NOT match
- * the constructor behavior.
- */
-
- buf_dynamic = duk_get_boolean(ctx, 1); /* default to false */
-
- switch (duk_get_type(ctx, 0)) {
- case DUK_TYPE_NUMBER: {
- /* new buffer of specified size */
- buf_size = (duk_size_t) duk_to_int(ctx, 0);
- (void) duk_push_buffer(ctx, buf_size, buf_dynamic);
- break;
- }
- case DUK_TYPE_BUFFER: {
- /* return input buffer, converted to a Duktape.Buffer object
- * if called as a constructor (no change if called as a
- * function).
- */
- duk_set_top(ctx, 1);
- break;
- }
- case DUK_TYPE_STRING: {
- /* new buffer with string contents */
- src_data = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &buf_size);
- DUK_ASSERT(src_data != NULL); /* even for zero-length string */
- buf_data = (duk_uint8_t *) duk_push_buffer(ctx, buf_size, buf_dynamic);
- DUK_MEMCPY((void *) buf_data, (const void *) src_data, (size_t) buf_size);
- break;
- }
- case DUK_TYPE_OBJECT: {
- /* For all duk_hbufferobjects, get the plain buffer inside
- * without making a copy. This is compatible with Duktape 1.2
- * but means that a slice/view information is ignored and the
- * full underlying buffer is returned.
- *
- * If called as a constructor, a new Duktape.Buffer object
- * pointing to the same plain buffer is created below.
- */
- duk_hbufferobject *h_bufobj;
- h_bufobj = (duk_hbufferobject *) duk_get_hobject(ctx, 0);
- DUK_ASSERT(h_bufobj != NULL);
- if (!DUK_HOBJECT_IS_BUFFEROBJECT((duk_hobject *) h_bufobj)) {
- return DUK_RET_TYPE_ERROR;
- }
- if (h_bufobj->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
- }
- duk_push_hbuffer(ctx, h_bufobj->buf);
- break;
- }
- case DUK_TYPE_NONE:
- default: {
- return DUK_RET_TYPE_ERROR;
- }
- }
- DUK_ASSERT(duk_is_buffer(ctx, -1));
-
- /* stack is unbalanced, but: [ <something> buf ] */
-
- if (duk_is_constructor_call(ctx)) {
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
-
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
-
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
- }
- /* Note: unbalanced stack on purpose */
-
- return 1;
-}
-
-/*
- * Node.js Buffer: constructor
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
- /* Internal class is Object: Object.prototype.toString.call(new Buffer(0))
- * prints "[object Object]".
- */
- duk_int_t len;
- duk_int_t i;
- duk_hbuffer *h_buf;
- duk_hbufferobject *h_bufobj;
- duk_size_t buf_size;
-
- switch (duk_get_type(ctx, 0)) {
- case DUK_TYPE_BUFFER: {
- /* Custom behavior: plain buffer is used as internal buffer
- * without making a copy (matches Duktape.Buffer).
- */
- duk_set_top(ctx, 1); /* -> [ buffer ] */
- break;
- }
- case DUK_TYPE_NUMBER: {
- len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX);
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- break;
- }
- case DUK_TYPE_OBJECT: {
- duk_uint8_t *buf;
-
- (void) duk_get_prop_string(ctx, 0, "length");
- len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX);
- duk_pop(ctx);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- for (i = 0; i < len; i++) {
- /* XXX: fast path for array arguments? */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU);
- duk_pop(ctx);
- }
- break;
- }
- case DUK_TYPE_STRING: {
- /* ignore encoding for now */
- duk_dup(ctx, 0);
- (void) duk_to_buffer(ctx, -1, &buf_size);
- break;
- }
- default:
- return DUK_RET_TYPE_ERROR;
- }
-
- DUK_ASSERT(duk_is_buffer(ctx, -1));
- h_buf = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_buf != NULL);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
-
- h_bufobj->buf = h_buf;
- DUK_HBUFFER_INCREF(thr, h_buf);
- DUK_ASSERT(h_bufobj->offset == 0);
- h_bufobj->length = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_buf);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * ArrayBuffer, DataView, and TypedArray constructors
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
-
- DUK_ASSERT_CTX_VALID(ctx);
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- if (duk_is_buffer(ctx, 0)) {
- /* Custom behavior: plain buffer is used as internal buffer
- * without making a copy (matches Duktape.Buffer).
- */
-
- h_val = duk_get_hbuffer(ctx, 0);
- DUK_ASSERT(h_val != NULL);
-
- /* XXX: accept any duk_hbufferobject type as an input also? */
- } else {
- duk_int_t len;
- len = duk_to_int(ctx, 0);
- if (len < 0) {
- goto fail_length;
- }
- (void) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- h_val = (duk_hbuffer *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
-#if !defined(DUK_USE_ZERO_BUFFER_DATA)
- /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
- * is not set.
- */
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
- DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) len);
-#endif
- }
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
- DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufobj != NULL);
-
- duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- return 1;
-
- fail_length:
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-
-/* Format of magic, bits:
- * 0...1: elem size shift (0-3)
- * 2...5: elem type (DUK_HBUFFEROBJECT_ELEM_xxx)
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_hobject *h_obj;
- duk_hbufferobject *h_bufobj = NULL;
- duk_hbufferobject *h_bufarr = NULL;
- duk_hbufferobject *h_bufarg = NULL;
- duk_hbuffer *h_val;
- duk_small_uint_t magic;
- duk_small_uint_t shift;
- duk_small_uint_t elem_type;
- duk_small_uint_t elem_size;
- duk_small_uint_t class_num;
- duk_small_uint_t proto_bidx;
- duk_uint_t align_mask;
- duk_uint_t elem_length;
- duk_int_t elem_length_signed;
- duk_uint_t byte_length;
- duk_small_uint_t copy_mode;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- /* We could fit built-in index into magic but that'd make the magic
- * number dependent on built-in numbering (genbuiltins.py doesn't
- * handle that yet). So map both class and prototype from the
- * element type.
- */
- magic = duk_get_current_magic(ctx);
- shift = magic & 0x03; /* bits 0...1: shift */
- elem_type = (magic >> 2) & 0x0f; /* bits 2...5: type */
- elem_size = 1 << shift;
- align_mask = elem_size - 1;
- DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
- proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
- DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS);
- DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t));
- class_num = duk__buffer_class_from_elemtype[elem_type];
-
- DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, "
- "elem_size=%d, proto_bidx=%d, class_num=%d",
- (int) magic, (int) shift, (int) elem_type, (int) elem_size,
- (int) proto_bidx, (int) class_num));
-
- /* Argument variants. When the argument is an ArrayBuffer a view to
- * the same buffer is created; otherwise a new ArrayBuffer is always
- * created.
- */
-
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL); /* arg count */
- if (DUK_TVAL_IS_OBJECT(tv)) {
- h_obj = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h_obj != NULL);
-
- if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
- /* ArrayBuffer: unlike any other argument variant, create
- * a view into the existing buffer.
- */
-
- duk_int_t byte_offset_signed;
- duk_uint_t byte_offset;
-
- h_bufarg = (duk_hbufferobject *) h_obj;
-
- byte_offset_signed = duk_to_int(ctx, 1);
- if (byte_offset_signed < 0) {
- goto fail_arguments;
- }
- byte_offset = (duk_uint_t) byte_offset_signed;
- if (byte_offset > h_bufarg->length ||
- (byte_offset & align_mask) != 0) {
- /* Must be >= 0 and multiple of element size. */
- goto fail_arguments;
- }
- if (duk_is_undefined(ctx, 2)) {
- DUK_ASSERT(h_bufarg->length >= byte_offset);
- byte_length = h_bufarg->length - byte_offset;
- if ((byte_length & align_mask) != 0) {
- /* Must be element size multiple from
- * start offset to end of buffer.
- */
- goto fail_arguments;
- }
- elem_length = (byte_length >> shift);
- } else {
- elem_length_signed = duk_to_int(ctx, 2);
- if (elem_length_signed < 0) {
- goto fail_arguments;
- }
- elem_length = (duk_uint_t) elem_length_signed;
- byte_length = elem_length << shift;
- if ((byte_length >> shift) != elem_length) {
- /* Byte length would overflow. */
- /* XXX: easier check with less code? */
- goto fail_arguments;
- }
- DUK_ASSERT(h_bufarg->length >= byte_offset);
- if (byte_length > h_bufarg->length - byte_offset) {
- /* Not enough data. */
- goto fail_arguments;
- }
- }
- DUK_UNREF(elem_length);
- DUK_ASSERT_DISABLE(byte_offset >= 0);
- DUK_ASSERT(byte_offset <= h_bufarg->length);
- DUK_ASSERT_DISABLE(byte_length >= 0);
- DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
- DUK_ASSERT((elem_length << shift) == byte_length);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
- proto_bidx);
- h_val = h_bufarg->buf;
- if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
- }
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = h_bufarg->offset + byte_offset;
- h_bufobj->length = byte_length;
- 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);
-
- /* Set .buffer to the argument ArrayBuffer. */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
- return 1;
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- /* TypedArray (or other non-ArrayBuffer duk_hbufferobject).
- * Conceptually same behavior as for an Array-like argument,
- * with a few fast paths.
- */
-
- h_bufarg = (duk_hbufferobject *) h_obj;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
- elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift);
- if (h_bufarg->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
- }
-
- /* Select copy mode. Must take into account element
- * compatibility and validity of the underlying source
- * buffer.
- */
-
- DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, "
- "src byte_length=%ld, src shift=%d, "
- "src/dst elem_length=%ld; "
- "dst shift=%d -> dst byte_length=%ld",
- (long) h_bufarg->length, (int) h_bufarg->shift,
- (long) elem_length_signed, (int) shift,
- (long) (elem_length_signed << shift)));
-
- copy_mode = 2; /* default is explicit index read/write copy */
- DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
- if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) {
- DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy"));
- DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */
- copy_mode = 0;
- } else {
- DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy"));
- copy_mode = 1;
- }
- }
- } else {
- /* Array or Array-like */
- elem_length_signed = (duk_int_t) duk_get_length(ctx, 0);
- copy_mode = 2;
- }
- } else if (DUK_TVAL_IS_BUFFER(tv)) {
- /* Accept plain buffer values like array initializers
- * (new in Duktape 1.4.0).
- */
- duk_hbuffer *h_srcbuf;
- h_srcbuf = DUK_TVAL_GET_BUFFER(tv);
- elem_length_signed = (duk_int_t) DUK_HBUFFER_GET_SIZE(h_srcbuf);
- copy_mode = 2; /* XXX: could add fast path for u8 compatible views */
- } else {
- /* Non-object argument is simply int coerced, matches
- * V8 behavior (except for "null", which we coerce to
- * 0 but V8 TypeErrors).
- */
- elem_length_signed = duk_to_int(ctx, 0);
- copy_mode = 3;
- }
- if (elem_length_signed < 0) {
- goto fail_arguments;
- }
- elem_length = (duk_uint_t) elem_length_signed;
- byte_length = (duk_uint_t) (elem_length << shift);
- if ((byte_length >> shift) != elem_length) {
- /* Byte length would overflow. */
- /* XXX: easier check with less code? */
- goto fail_arguments;
- }
-
- DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld",
- (long) elem_length, (long) byte_length));
-
- /* ArrayBuffer argument is handled specially above; the rest of the
- * argument variants are handled by shared code below.
- */
-
- /* Push a new ArrayBuffer (becomes view .buffer) */
- h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length);
- DUK_ASSERT(h_bufarr != NULL);
- h_val = h_bufarr->buf;
- DUK_ASSERT(h_val != NULL);
-
- /* Push the resulting view object and attach the ArrayBuffer. */
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
- proto_bidx);
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- DUK_ASSERT(h_bufobj->offset == 0);
- h_bufobj->length = byte_length;
- 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);
-
- /* Set .buffer */
- duk_dup(ctx, -2);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
-
- /* Copy values, the copy method depends on the arguments.
- *
- * Copy mode decision may depend on the validity of the underlying
- * buffer of the source argument; there must be no harmful side effects
- * from there to here for copy_mode to still be valid.
- */
- DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode));
- switch (copy_mode) {
- case 0: {
- /* Use byte copy. */
-
- duk_uint8_t *p_src;
- duk_uint8_t *p_dst;
-
- DUK_ASSERT(h_bufobj != NULL);
- DUK_ASSERT(h_bufobj->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
- DUK_ASSERT(h_bufarg != NULL);
- DUK_ASSERT(h_bufarg->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
-
- p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
- p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
-
- DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
- (void *) p_src, (void *) p_dst, (long) byte_length));
-
- DUK_MEMCPY((void *) p_dst, (const void *) p_src, (size_t) byte_length);
- break;
- }
- case 1: {
- /* Copy values through direct validated reads and writes. */
-
- duk_small_uint_t src_elem_size;
- duk_small_uint_t dst_elem_size;
- duk_uint8_t *p_src;
- duk_uint8_t *p_src_end;
- duk_uint8_t *p_dst;
-
- DUK_ASSERT(h_bufobj != NULL);
- DUK_ASSERT(h_bufobj->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj));
- DUK_ASSERT(h_bufarg != NULL);
- DUK_ASSERT(h_bufarg->buf != NULL);
- DUK_ASSERT(DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg));
-
- src_elem_size = 1 << h_bufarg->shift;
- dst_elem_size = elem_size;
-
- p_src = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
- p_dst = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj);
- p_src_end = p_src + h_bufarg->length;
-
- DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, "
- "src_elem_size=%d, dst_elem_size=%d",
- (void *) p_src, (void *) p_src_end, (void *) p_dst,
- (int) src_elem_size, (int) dst_elem_size));
-
- while (p_src != p_src_end) {
- DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
- "p_src=%p, p_src_end=%p, p_dst=%p",
- (void *) p_src, (void *) p_src_end, (void *) p_dst));
- /* A validated read() is always a number, so it's write coercion
- * is always side effect free an won't invalidate pointers etc.
- */
- duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
- duk_hbufferobject_validated_write(ctx, h_bufobj, p_dst, dst_elem_size);
- duk_pop(ctx);
- p_src += src_elem_size;
- p_dst += dst_elem_size;
- }
- break;
- }
- case 2: {
- /* Copy values by index reads and writes. Let virtual
- * property handling take care of coercion.
- */
- duk_uint_t i;
-
- DUK_DDD(DUK_DDDPRINT("using slow copy"));
-
- for (i = 0; i < elem_length; i++) {
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- duk_put_prop_index(ctx, -2, (duk_uarridx_t) i);
- }
- break;
- }
- default:
- case 3: {
- /* No copy, leave zero bytes in the buffer. There's no
- * ambiguity with Float32/Float64 because zero bytes also
- * represent 0.0.
- */
-#if !defined(DUK_USE_ZERO_BUFFER_DATA)
- /* Khronos/ES6 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
- * is not set.
- */
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) h_val));
- DUK_MEMZERO((void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_val), (duk_size_t) byte_length);
-#endif
-
- DUK_DDD(DUK_DDDPRINT("using no copy"));
- break;
- }
- }
-
- return 1;
-
- fail_arguments:
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
- duk_hbufferobject *h_bufarg;
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
- duk_uint_t offset;
- duk_uint_t length;
-
- /* XXX: function flag to make this automatic? */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- h_bufarg = duk__require_bufobj_value(ctx, 0);
- DUK_ASSERT(h_bufarg != NULL);
-
- duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
- DUK_ASSERT(offset <= h_bufarg->length);
- DUK_ASSERT(offset + length <= h_bufarg->length);
-
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
- DUK_BIDX_DATAVIEW_PROTOTYPE);
-
- h_val = h_bufarg->buf;
- if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
- }
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = h_bufarg->offset + offset;
- h_bufobj->length = length;
- DUK_ASSERT(h_bufobj->shift == 0);
- DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFFEROBJECT_ELEM_UINT8);
- h_bufobj->is_view = 1;
-
- /* The DataView .buffer property is ordinarily set to the argument
- * which is an ArrayBuffer. We accept any duk_hbufferobject as
- * an argument and .buffer will be set to the argument regardless
- * of what it is. This may be a bit confusing if the argument
- * is e.g. a DataView or another TypedArray view.
- *
- * XXX: Copy .buffer property from a DataView/TypedArray argument?
- * Create a fresh ArrayBuffer for Duktape.Buffer and Node.js Buffer
- * arguments? See: test-bug-dataview-buffer-prop.js.
- */
-
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_compact(ctx, -1);
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * ArrayBuffer.isView()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
- duk_hobject *h_obj;
- duk_bool_t ret = 0;
-
- h_obj = duk_get_hobject(ctx, 0);
- if (h_obj != NULL && DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- ret = ((duk_hbufferobject *) h_obj)->is_view;
- }
- duk_push_boolean(ctx, ret);
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer: toString([encoding], [start], [end])
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- duk_int_t start_offset, end_offset;
- duk_uint8_t *buf_slice;
- duk_size_t slice_length;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__get_bufobj_this(ctx);
- if (h_this == NULL) {
- /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
- duk_push_string(ctx, "[object Object]");
- return 1;
- }
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
-
- /* ignore encoding for now */
-
- duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &start_offset, &end_offset);
-
- slice_length = (duk_size_t) (end_offset - start_offset);
- buf_slice = (duk_uint8_t *) duk_push_fixed_buffer(ctx, slice_length);
- DUK_ASSERT(buf_slice != NULL);
-
- if (h_this->buf == NULL) {
- goto type_error;
- }
-
- if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) {
- DUK_MEMCPY((void *) buf_slice,
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
- (size_t) slice_length);
- } else {
- /* not covered, return all zeroes */
- ;
- }
-
- duk_to_string(ctx, -1);
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Duktape.Buffer: toString(), valueOf()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_small_int_t to_string = duk_get_current_magic(ctx);
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- tv = duk_get_borrowed_this_tval(ctx);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_BUFFER(tv)) {
- duk_hbuffer *h_buf;
- h_buf = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h_buf != NULL);
- duk_push_hbuffer(ctx, h_buf);
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h;
- duk_hbufferobject *h_bufobj;
-
- /* Accept any duk_hbufferobject, though we're only normally
- * called for Duktape.Buffer values.
- */
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- if (!DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- DUK_DD(DUK_DDPRINT("toString/valueOf() called for a non-bufferobject object"));
- goto type_error;
- }
- h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- if (h_bufobj->buf == NULL) {
- DUK_DD(DUK_DDPRINT("toString/valueOf() called for a bufferobject with NULL buf"));
- goto type_error;
- }
- duk_push_hbuffer(ctx, h_bufobj->buf);
- } else {
- goto type_error;
- }
-
- if (to_string) {
- duk_to_string(ctx, -1);
- }
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_prototype_tostring_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.prototype: toJSON()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- duk_uint8_t *buf;
- duk_uint_t i;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
- h_this = duk__require_bufobj_this(ctx);
- DUK_ASSERT(h_this != NULL);
-
- if (h_this->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
- /* Serialize uncovered backing buffer as a null; doesn't
- * really matter as long we're memory safe.
- */
- duk_push_null(ctx);
- return 1;
- }
-
- duk_push_object(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_TYPE);
-
- duk_push_array(ctx);
- for (i = 0; i < h_this->length; i++) {
- /* XXX: regetting the pointer may be overkill - we're writing
- * to a side-effect free array here.
- */
- DUK_ASSERT(h_this->buf != NULL);
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
- duk_push_uint(ctx, (duk_uint_t) buf[i]);
- duk_put_prop_index(ctx, -2, (duk_idx_t) i);
- }
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_DATA);
-
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.prototype.equals()
- * Node.js Buffer.prototype.compare()
- * Node.js Buffer.compare()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_uint_t magic;
- duk_hbufferobject *h_bufarg1;
- duk_hbufferobject *h_bufarg2;
- duk_small_int_t comp_res;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- magic = duk_get_current_magic(ctx);
- if (magic & 0x02) {
- /* Static call style. */
- h_bufarg1 = duk__require_bufobj_value(ctx, 0);
- h_bufarg2 = duk__require_bufobj_value(ctx, 1);
- } else {
- h_bufarg1 = duk__require_bufobj_this(ctx);
- h_bufarg2 = duk__require_bufobj_value(ctx, 0);
- }
- DUK_ASSERT(h_bufarg1 != NULL);
- DUK_ASSERT(h_bufarg2 != NULL);
-
- /* We want to compare the slice/view areas of the arguments.
- * If either slice/view is invalid (underlying buffer is shorter)
- * ensure equals() is false, but otherwise the only thing that
- * matters is to be memory safe.
- */
-
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg1) &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg2)) {
- comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset,
- (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset,
- (duk_size_t) h_bufarg1->length,
- (duk_size_t) h_bufarg2->length);
- } else {
- comp_res = -1; /* either nonzero value is ok */
- }
-
- if (magic & 0x01) {
- /* compare: similar to string comparison but for buffer data. */
- duk_push_int(ctx, comp_res);
- } else {
- /* equals */
- duk_push_boolean(ctx, (comp_res == 0));
- }
-
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.prototype.fill()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- const duk_uint8_t *fill_str_ptr;
- duk_size_t fill_str_len;
- duk_uint8_t fill_value;
- duk_int_t fill_offset;
- duk_int_t fill_end;
- duk_size_t fill_length;
- duk_uint8_t *p;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
- DUK_ASSERT(h_this != NULL);
- if (h_this->buf == NULL) {
- return DUK_RET_TYPE_ERROR;
- }
-
- /* [ value offset end ] */
-
- if (duk_is_string(ctx, 0)) {
- fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len);
- DUK_ASSERT(fill_str_ptr != NULL);
- } else {
- fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0);
- fill_str_ptr = (const duk_uint8_t *) &fill_value;
- fill_str_len = 1;
- }
-
- /* Fill offset handling is more lenient than in Node.js. */
-
- duk__clamp_startend_nonegidx_noshift(ctx, h_this, 1 /*idx_start*/, 2 /*idx_end*/, &fill_offset, &fill_end);
-
- DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld",
- (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length));
-
- DUK_ASSERT(fill_end - fill_offset >= 0);
- DUK_ASSERT(h_this->buf != NULL);
-
- p = (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
- fill_length = (duk_size_t) (fill_end - fill_offset);
- if (fill_str_len == 1) {
- /* Handle single character fills as memset() even when
- * the fill data comes from a one-char argument.
- */
- DUK_MEMSET((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
- } else if (fill_str_len > 1) {
- duk_size_t i, n, t;
-
- for (i = 0, n = (fill_end - fill_offset), t = 0; i < n; i++) {
- p[i] = fill_str_ptr[t++];
- if (t >= fill_str_len) {
- t = 0;
- }
- }
- } else {
- DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently"));
- }
-
- /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
- duk_push_this(ctx);
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.prototype.write(string, [offset], [length], [encoding])
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- duk_uint_t offset;
- duk_uint_t length;
- const duk_uint8_t *str_data;
- duk_size_t str_len;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
- DUK_ASSERT(h_this != NULL);
-
- /* Argument must be a string, e.g. a buffer is not allowed. */
- str_data = (const duk_uint8_t *) duk_require_lstring(ctx, 0, &str_len);
-
- duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
- DUK_ASSERT(offset <= h_this->length);
- DUK_ASSERT(offset + length <= h_this->length);
-
- /* XXX: encoding is ignored now. */
-
- if (length > str_len) {
- length = (duk_uint_t) str_len;
- }
-
- if (DUK_HBUFFEROBJECT_VALID_SLICE(h_this)) {
- /* Cannot overlap. */
- DUK_MEMCPY((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset),
- (const void *) str_data,
- (size_t) length);
- } else {
- DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
- }
-
- duk_push_uint(ctx, length);
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.prototype.copy()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- duk_hbufferobject *h_bufarg;
- duk_int_t source_length;
- duk_int_t target_length;
- duk_int_t target_start, source_start, source_end;
- duk_uint_t target_ustart, source_ustart, source_uend;
- duk_uint_t copy_size = 0;
-
- /* [ targetBuffer targetStart sourceStart sourceEnd ] */
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
- h_bufarg = duk__require_bufobj_value(ctx, 0);
- DUK_ASSERT(h_this != NULL);
- DUK_ASSERT(h_bufarg != NULL);
- source_length = (duk_int_t) h_this->length;
- target_length = (duk_int_t) h_bufarg->length;
-
- target_start = duk_to_int(ctx, 1);
- source_start = duk_to_int(ctx, 2);
- if (duk_is_undefined(ctx, 3)) {
- source_end = source_length;
- } else {
- source_end = duk_to_int(ctx, 3);
- }
-
- DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
- "source_start=%ld, source_end=%ld, source_length=%ld",
- (long) target_start, (long) h_bufarg->length,
- (long) source_start, (long) source_end, (long) source_length));
-
- /* This behavior mostly mimics Node.js now. */
-
- if (source_start < 0 || source_end < 0 || target_start < 0) {
- /* Negative offsets cause a RangeError. */
- goto fail_bounds;
- }
- source_ustart = (duk_uint_t) source_start;
- source_uend = (duk_uint_t) source_end;
- target_ustart = (duk_uint_t) target_start;
- if (source_ustart >= source_uend || /* crossed offsets or zero size */
- source_ustart >= (duk_uint_t) source_length || /* source out-of-bounds (but positive) */
- target_ustart >= (duk_uint_t) target_length) { /* target out-of-bounds (but positive) */
- goto silent_ignore;
- }
- if (source_uend >= (duk_uint_t) source_length) {
- /* Source end clamped silently to available length. */
- source_uend = source_length;
- }
- copy_size = source_uend - source_ustart;
- if (target_ustart + copy_size > (duk_uint_t) target_length) {
- /* Clamp to target's end if too long.
- *
- * NOTE: there's no overflow possibility in the comparison;
- * both target_ustart and copy_size are >= 0 and based on
- * values in duk_int_t range. Adding them as duk_uint_t
- * values is then guaranteed not to overflow.
- */
- DUK_ASSERT(target_ustart + copy_size >= target_ustart); /* no overflow */
- DUK_ASSERT(target_ustart + copy_size >= copy_size); /* no overflow */
- copy_size = (duk_uint_t) target_length - target_ustart;
- }
-
- DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu",
- (unsigned long) target_ustart, (unsigned long) source_ustart,
- (unsigned long) copy_size));
-
- DUK_ASSERT(copy_size >= 1);
- DUK_ASSERT(source_ustart <= (duk_uint_t) source_length);
- DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length);
- DUK_ASSERT(target_ustart <= (duk_uint_t) target_length);
- DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length);
-
- /* Ensure copy is covered by underlying buffers. */
- DUK_ASSERT(h_bufarg->buf != NULL); /* length check */
- DUK_ASSERT(h_this->buf != NULL); /* length check */
- if (DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
- DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
- /* Must use memmove() because copy area may overlap (source and target
- * buffer may be the same, or from different slices.
- */
- DUK_MEMMOVE((void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
- (size_t) copy_size);
- } else {
- DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
- }
-
- silent_ignore:
- /* Return value is like write(), number of bytes written.
- * The return value matters because of code like:
- * "off += buf.copy(...)".
- */
- duk_push_uint(ctx, copy_size);
- return 1;
-
- fail_bounds:
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * TypedArray.prototype.set()
- *
- * TypedArray set() is pretty interesting to implement because:
- *
- * - The source argument may be a plain array or a typedarray. If the
- * source is a TypedArray, values are decoded and re-encoded into the
- * target (not as a plain byte copy). This may happen even when the
- * element byte size is the same, e.g. integer values may be re-encoded
- * into floats.
- *
- * - Source and target may refer to the same underlying buffer, so that
- * the set() operation may overlap. The specification requires that this
- * must work as if a copy was made before the operation. Note that this
- * is NOT a simple memmove() situation because the source and target
- * byte sizes may be different -- e.g. a 4-byte source (Int8Array) may
- * expand to a 16-byte target (Uint32Array) so that the target overlaps
- * the source both from beginning and the end (unlike in typical memmove).
- *
- * - Even if 'buf' pointers of the source and target differ, there's no
- * guarantee that their memory areas don't overlap. This may be the
- * case with external buffers.
- *
- * Even so, it is nice to optimize for the common case:
- *
- * - Source and target separate buffers or non-overlapping.
- *
- * - Source and target have a compatible type so that a plain byte copy
- * is possible. Note that while e.g. uint8 and int8 are compatible
- * (coercion one way or another doesn't change the byte representation),
- * e.g. int8 and uint8clamped are NOT compatible when writing int8
- * values into uint8clamped typedarray (-1 would clamp to 0 for instance).
- *
- * See test-bi-typedarray-proto-set.js.
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
- duk_hthread *thr;
- duk_hbufferobject *h_this;
- duk_hobject *h_obj;
- duk_uarridx_t i, n;
- duk_int_t offset_signed;
- duk_uint_t offset_elems;
- duk_uint_t offset_bytes;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- h_this = duk__require_bufobj_this(ctx);
- DUK_ASSERT(h_this != NULL);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_this);
-
- if (h_this->buf == NULL) {
- DUK_DDD(DUK_DDDPRINT("source neutered, skip copy"));
- return 0;
- }
-
- h_obj = duk_require_hobject(ctx, 0);
- DUK_ASSERT(h_obj != NULL);
-
- /* XXX: V8 throws a TypeError for negative values. Would it
- * be more useful to interpret negative offsets here from the
- * end of the buffer too?
- */
- offset_signed = duk_to_int(ctx, 1);
- if (offset_signed < 0) {
- return DUK_RET_TYPE_ERROR;
- }
- offset_elems = (duk_uint_t) offset_signed;
- offset_bytes = offset_elems << h_this->shift;
- if ((offset_bytes >> h_this->shift) != offset_elems) {
- /* Byte length would overflow. */
- /* XXX: easier check with less code? */
- return DUK_RET_RANGE_ERROR;
- }
- if (offset_bytes > h_this->length) {
- /* Equality may be OK but >length not. Checking
- * this explicitly avoids some overflow cases
- * below.
- */
- return DUK_RET_RANGE_ERROR;
- }
- DUK_ASSERT(offset_bytes <= h_this->length);
-
- /* Fast path: source is a TypedArray (or any bufferobject). */
-
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- duk_hbufferobject *h_bufarg;
- duk_uint16_t comp_mask;
- duk_small_int_t no_overlap = 0;
- duk_uint_t src_length;
- duk_uint_t dst_length;
- duk_uint_t dst_length_elems;
- duk_uint8_t *p_src_base;
- duk_uint8_t *p_src_end;
- duk_uint8_t *p_src;
- duk_uint8_t *p_dst_base;
- duk_uint8_t *p_dst;
- duk_small_uint_t src_elem_size;
- duk_small_uint_t dst_elem_size;
-
- h_bufarg = (duk_hbufferobject *) h_obj;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufarg);
-
- if (h_bufarg->buf == NULL) {
- DUK_DDD(DUK_DDDPRINT("target neutered, skip copy"));
- return 0;
- }
-
- /* Nominal size check. */
- src_length = h_bufarg->length; /* bytes in source */
- dst_length_elems = (src_length >> h_bufarg->shift); /* elems in source and dest */
- dst_length = dst_length_elems << h_this->shift; /* bytes in dest */
- if ((dst_length >> h_this->shift) != dst_length_elems) {
- /* Byte length would overflow. */
- /* XXX: easier check with less code? */
- return DUK_RET_RANGE_ERROR;
- }
- DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld",
- (long) src_length, (long) dst_length));
- DUK_ASSERT(offset_bytes <= h_this->length);
- if (dst_length > h_this->length - offset_bytes) {
- /* Overflow not an issue because subtraction is used on the right
- * side and guaranteed to be >= 0.
- */
- DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
- return DUK_RET_RANGE_ERROR;
- }
- if (!DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
- DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore"));
- return 0;
- }
-
- p_src_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufarg);
- p_dst_base = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
-
- /* Check actual underlying buffers for validity and that they
- * cover the copy. No side effects are allowed after the check
- * so that the validity status doesn't change.
- */
- if (!DUK_HBUFFEROBJECT_VALID_SLICE(h_this) ||
- !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufarg)) {
- /* The condition could be more narrow and check for the
- * copy area only, but there's no need for fine grained
- * behavior when the underlying buffer is misconfigured.
- */
- DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy"));
- return 0;
- }
-
- /* We want to do a straight memory copy if possible: this is
- * an important operation because .set() is the TypedArray
- * way to copy chunks of memory. However, because set()
- * conceptually works in terms of elements, not all views are
- * compatible with direct byte copying.
- *
- * If we do manage a direct copy, the "overlap issue" handled
- * below can just be solved using memmove() because the source
- * and destination element sizes are necessarily equal.
- */
-
- DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
- comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type];
- if (comp_mask & (1 << h_bufarg->elem_type)) {
- DUK_ASSERT(src_length == dst_length);
-
- DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible"));
- DUK_MEMMOVE((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
- return 0;
- }
- DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
-
- /* We want to avoid making a copy to process set() but that's
- * not always possible: the source and the target may overlap
- * and because element sizes are different, the overlap cannot
- * always be handled with a memmove() or choosing the copy
- * direction in a certain way. For example, if source type is
- * uint8 and target type is uint32, the target area may exceed
- * the source area from both ends!
- *
- * Note that because external buffers may point to the same
- * memory areas, we must ultimately make this check using
- * pointers.
- *
- * NOTE: careful with side effects: any side effect may cause
- * a buffer resize (or external buffer pointer/length update)!
- */
-
- DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, "
- "p_dst_base=%p, dst_length=%ld",
- (void *) p_src_base, (long) src_length,
- (void *) p_dst_base, (long) dst_length));
-
- if (p_src_base >= p_dst_base + dst_length || /* source starts after dest ends */
- p_src_base + src_length <= p_dst_base) { /* source ends before dest starts */
- no_overlap = 1;
- }
-
- if (!no_overlap) {
- /* There's overlap: the desired end result is that
- * conceptually a copy is made to avoid "trampling"
- * of source data by destination writes. We make
- * an actual temporary copy to handle this case.
- */
- duk_uint8_t *p_src_copy;
-
- DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
- p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_length);
- DUK_ASSERT(p_src_copy != NULL);
- DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
-
- p_src_base = p_src_copy; /* use p_src_base from now on */
- }
- /* Value stack intentionally mixed size here. */
-
- DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, "
- "p_dst_base=%p, dst_length=%ld, valstack top=%ld",
- (void *) p_src_base, (long) src_length,
- (void *) p_dst_base, (long) dst_length,
- (long) duk_get_top(ctx)));
-
- /* Ready to make the copy. We must proceed element by element
- * and must avoid any side effects that might cause the buffer
- * validity check above to become invalid.
- *
- * Although we work through the value stack here, only plain
- * numbers are handled which should be side effect safe.
- */
-
- src_elem_size = 1 << h_bufarg->shift;
- dst_elem_size = 1 << h_this->shift;
- p_src = p_src_base;
- p_dst = p_dst_base;
- p_src_end = p_src_base + src_length;
-
- while (p_src != p_src_end) {
- DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
- "p_src=%p, p_src_end=%p, p_dst=%p",
- (void *) p_src, (void *) p_src_end, (void *) p_dst));
- /* A validated read() is always a number, so it's write coercion
- * is always side effect free an won't invalidate pointers etc.
- */
- duk_hbufferobject_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
- duk_hbufferobject_validated_write(ctx, h_this, p_dst, dst_elem_size);
- duk_pop(ctx);
- p_src += src_elem_size;
- p_dst += dst_elem_size;
- }
-
- return 0;
- } else {
- /* Slow path: quite slow, but we save space by using the property code
- * to write coerce target values. We don't need to worry about overlap
- * here because the source is not a TypedArray.
- *
- * We could use the bufferobject write coercion helper but since the
- * property read may have arbitrary side effects, full validity checks
- * would be needed for every element anyway.
- */
-
- n = (duk_uarridx_t) duk_get_length(ctx, 0);
- DUK_ASSERT(offset_bytes <= h_this->length);
- if ((n << h_this->shift) > h_this->length - offset_bytes) {
- /* Overflow not an issue because subtraction is used on the right
- * side and guaranteed to be >= 0.
- */
- DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
- return DUK_RET_RANGE_ERROR;
- }
-
- /* There's no need to check for buffer validity status for the
- * target here: the property access code will do that for each
- * element. Moreover, if we did check the validity here, side
- * effects from reading the source argument might invalidate
- * the results anyway.
- */
-
- DUK_ASSERT_TOP(ctx, 2);
- duk_push_this(ctx);
-
- for (i = 0; i < n; i++) {
- duk_get_prop_index(ctx, 0, i);
- duk_put_prop_index(ctx, 2, offset_elems + i);
- }
- }
-
- return 0;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.prototype.slice([start], [end])
- * ArrayBuffer.prototype.slice(begin, [end])
- * TypedArray.prototype.slice(begin, [end])
- *
- * The API calls are almost identical; negative indices are counted from end
- * of buffer, and final indices are clamped (allowing crossed indices). Main
- * differences:
- *
- * - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create
- * views, ArrayBuffer .slice() creates a copy
- *
- * - Resulting object has a different class and prototype depending on the
- * call (or 'this' argument)
- *
- * - TypedArray .subarray() arguments are element indices, not byte offsets
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic;
- duk_small_uint_t res_class_num;
- duk_hobject *res_proto;
- duk_hbufferobject *h_this;
- duk_hbufferobject *h_bufobj;
- duk_hbuffer *h_val;
- duk_int_t start_offset, end_offset;
- duk_uint_t slice_length;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /* [ start end ] */
-
- magic = duk_get_current_magic(ctx);
- h_this = duk__require_bufobj_this(ctx);
-
- /* Slice offsets are element (not byte) offsets, which only matters
- * for TypedArray views, Node.js Buffer and ArrayBuffer have shift
- * zero so byte and element offsets are the same. Negative indices
- * are counted from end of slice, crossed indices are allowed (and
- * result in zero length result), and final values are clamped
- * against the current slice. There's intentionally no check
- * against the underlying buffer here.
- */
-
- duk__clamp_startend_negidx_shifted(ctx, h_this, 0 /*idx_start*/, 1 /*idx_end*/, &start_offset, &end_offset);
- DUK_ASSERT(end_offset >= start_offset);
- slice_length = (duk_uint_t) (end_offset - start_offset);
-
- /* The resulting buffer object gets the same class and prototype as
- * the buffer in 'this', e.g. if the input is a Node.js Buffer the
- * result is a Node.js Buffer; if the input is a Float32Array, the
- * result is a Float32Array.
- *
- * For the class number this seems correct. The internal prototype
- * is not so clear: if 'this' is a bufferobject with a non-standard
- * prototype object, that value gets copied over into the result
- * (instead of using the standard prototype for that object type).
- */
-
- res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this);
- h_bufobj = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
- DUK_BIDX_OBJECT_PROTOTYPE); /* replaced */
- DUK_ASSERT(h_bufobj != NULL);
- res_proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_this); /* may be NULL */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_bufobj, res_proto);
-
- h_bufobj->length = slice_length;
- h_bufobj->shift = h_this->shift; /* inherit */
- h_bufobj->elem_type = h_this->elem_type; /* inherit */
- h_bufobj->is_view = magic & 0x01;
- DUK_ASSERT(h_bufobj->is_view == 0 || h_bufobj->is_view == 1);
-
- h_val = h_this->buf;
- if (h_val == NULL) {
- return DUK_RET_TYPE_ERROR;
- }
-
- if (magic & 0x02) {
- /* non-zero: make copy */
- duk_uint8_t *p_copy;
- duk_size_t copy_length;
-
- p_copy = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) slice_length);
- DUK_ASSERT(p_copy != NULL);
-
- /* Copy slice, respecting underlying buffer limits; remainder
- * is left as zero.
- */
- copy_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, slice_length);
- DUK_MEMCPY((void *) p_copy,
- (const void *) (DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
- copy_length);
-
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- DUK_ASSERT(h_bufobj->offset == 0);
-
- duk_pop(ctx); /* reachable so pop OK */
- } else {
- h_bufobj->buf = h_val;
- DUK_HBUFFER_INCREF(thr, h_val);
- h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset);
-
- /* Copy the .buffer property, needed for TypedArray.prototype.subarray().
- *
- * XXX: limit copy only for TypedArray classes specifically?
- */
-
- duk_push_this(ctx);
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_BUFFER)) {
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LC_BUFFER, DUK_PROPDESC_FLAGS_NONE);
- duk_pop(ctx);
- } else {
- duk_pop_2(ctx);
- }
- }
- /* unbalanced stack on purpose */
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.isEncoding()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
- const char *encoding;
-
- /* only accept lowercase 'utf8' now. */
-
- encoding = duk_to_string(ctx, 0);
- DUK_ASSERT(duk_is_string(ctx, 0)); /* guaranteed by duk_to_string() */
- duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0);
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.isBuffer()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
- duk_hthread *thr;
- duk_tval *tv;
- duk_hobject *h;
- duk_hobject *h_proto;
- duk_bool_t ret = 0;
-
- thr = (duk_hthread *) ctx;
-
- DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_OBJECT(tv)) {
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
- DUK_ASSERT(h_proto != NULL);
-
- h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
- if (h) {
- ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/);
- }
- }
-
- duk_push_boolean(ctx, ret);
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.byteLength()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
- const char *str;
- duk_size_t len;
-
- /* At the moment Buffer(<str>) will just use the string bytes as
- * is (ignoring encoding), so we return the string length here
- * unconditionally.
- */
-
- str = duk_to_lstring(ctx, 0, &len);
- DUK_UNREF(str);
- duk_push_size_t(ctx, len);
- return 1;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Node.js Buffer.concat()
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
- duk_hthread *thr;
- duk_hobject *h_arg;
- duk_int_t total_length = 0;
- duk_hbufferobject *h_bufobj;
- duk_hbufferobject *h_bufres;
- duk_hbuffer *h_val;
- duk_uint_t i, n;
- duk_uint8_t *p;
- duk_size_t space_left;
- duk_size_t copy_size;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- /* Node.js accepts only actual Arrays. */
- h_arg = duk_require_hobject(ctx, 0);
- if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
- return DUK_RET_TYPE_ERROR;
- }
-
- /* Compute result length and validate argument buffers. */
- n = (duk_uint_t) duk_get_length(ctx, 0);
- for (i = 0; i < n; i++) {
- /* Neutered checks not necessary here: neutered buffers have
- * zero 'length' so we'll effectively skip them.
- */
- DUK_ASSERT_TOP(ctx, 2); /* [ array totalLength ] */
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
- h_bufobj = duk__require_bufobj_value(ctx, 2);
- DUK_ASSERT(h_bufobj != NULL);
- total_length += h_bufobj->length;
- duk_pop(ctx);
- }
- if (n == 1) {
- /* For the case n==1 Node.js doesn't seem to type check
- * the sole member but we do it before returning it.
- * For this case only the original buffer object is
- * returned (not a copy).
- */
- duk_get_prop_index(ctx, 0, 0);
- return 1;
- }
-
- /* User totalLength overrides a computed length, but we'll check
- * every copy in the copy loop. Note that duk_to_uint() can
- * technically have arbitrary side effects so we need to recheck
- * the buffers in the copy loop.
- */
- if (!duk_is_undefined(ctx, 1) && n > 0) {
- /* For n == 0, Node.js ignores totalLength argument and
- * returns a zero length buffer.
- */
- total_length = duk_to_int(ctx, 1);
- }
- if (total_length < 0) {
- return DUK_RET_RANGE_ERROR;
- }
-
- h_bufres = duk_push_bufferobject_raw(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BUFFEROBJECT |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BUFFER),
- DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
- DUK_ASSERT(h_bufres != NULL);
-
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, total_length);
- DUK_ASSERT(p != NULL);
- space_left = total_length;
-
- for (i = 0; i < n; i++) {
- DUK_ASSERT_TOP(ctx, 4); /* [ array totalLength bufres buf ] */
-
- duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
- h_bufobj = duk__require_bufobj_value(ctx, 4);
- DUK_ASSERT(h_bufobj != NULL);
-
- copy_size = h_bufobj->length;
- if (copy_size > space_left) {
- copy_size = space_left;
- }
-
- if (h_bufobj->buf != NULL &&
- DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
- DUK_MEMCPY((void *) p,
- (const void *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_bufobj),
- copy_size);
- } else {
- /* Just skip, leaving zeroes in the result. */
- ;
- }
- p += copy_size;
- space_left -= copy_size;
-
- duk_pop(ctx);
- }
-
- h_val = duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_val != NULL);
-
- duk__set_bufobj_buffer(ctx, h_bufres, h_val);
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufres);
-
- duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */
-
- return 1; /* return h_bufres */
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-/*
- * Shared readfield and writefield methods
- *
- * The readfield/writefield methods need support for endianness and field
- * types. All offsets are byte based so no offset shifting is needed.
- */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* Format of magic, bits:
- * 0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused
- * 3: endianness: 0=little, 1=big
- * 4: signed: 1=yes, 0=no
- * 5: typedarray: 1=yes, 0=no
- */
-#define DUK__FLD_8BIT 0
-#define DUK__FLD_16BIT 1
-#define DUK__FLD_32BIT 2
-#define DUK__FLD_FLOAT 3
-#define DUK__FLD_DOUBLE 4
-#define DUK__FLD_VARINT 5
-#define DUK__FLD_BIGENDIAN (1 << 3)
-#define DUK__FLD_SIGNED (1 << 4)
-#define DUK__FLD_TYPEDARRAY (1 << 5)
-
-/* XXX: split into separate functions for each field type? */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
- duk_small_int_t magic_ftype;
- duk_small_int_t magic_bigendian;
- duk_small_int_t magic_signed;
- duk_small_int_t magic_typedarray;
- duk_small_int_t endswap;
- duk_hbufferobject *h_this;
- duk_bool_t no_assert;
- duk_int_t offset_signed;
- duk_uint_t offset;
- duk_uint_t buffer_length;
- duk_uint_t check_length;
- duk_uint8_t *buf;
- duk_double_union du;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- magic_ftype = magic & 0x0007;
- magic_bigendian = magic & 0x0008;
- magic_signed = magic & 0x0010;
- magic_typedarray = magic & 0x0020;
-
- h_this = duk__require_bufobj_this(ctx);
- DUK_ASSERT(h_this != NULL);
- buffer_length = h_this->length;
-
- /* [ offset noAssert ], when ftype != DUK__FLD_VARINT */
- /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
- /* [ offset littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
-
- /* Handle TypedArray vs. Node.js Buffer arg differences */
- if (magic_typedarray) {
- no_assert = 0;
-#if defined(DUK_USE_INTEGER_LE)
- endswap = !duk_to_boolean(ctx, 1); /* 1=little endian */
-#else
- endswap = duk_to_boolean(ctx, 1); /* 1=little endian */
-#endif
- } else {
- no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
-#if defined(DUK_USE_INTEGER_LE)
- endswap = magic_bigendian;
-#else
- endswap = !magic_bigendian;
-#endif
- }
-
- /* Offset is coerced first to signed integer range and then to unsigned.
- * This ensures we can add a small byte length (1-8) to the offset in
- * bound checks and not wrap.
- */
- offset_signed = duk_to_int(ctx, 0);
- offset = (duk_uint_t) offset_signed;
- if (offset_signed < 0) {
- goto fail_bounds;
- }
-
- DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, "
- "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
- "endswap=%d",
- (long) buffer_length, (long) offset, (int) no_assert,
- (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
- (int) (magic_signed >> 4), (int) endswap));
-
- /* Update 'buffer_length' to be the effective, safe limit which
- * takes into account the underlying buffer. This value will be
- * potentially invalidated by any side effect.
- */
- check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
- DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
- (long) buffer_length, (long) check_length));
-
- if (h_this->buf) {
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
- } else {
- /* Neutered. We could go into the switch-case safely with
- * buf == NULL because check_length == 0. To avoid scanbuild
- * warnings, fail directly instead.
- */
- DUK_ASSERT(check_length == 0);
- goto fail_neutered;
- }
- DUK_ASSERT(buf != NULL);
-
- switch (magic_ftype) {
- case DUK__FLD_8BIT: {
- duk_uint8_t tmp;
- if (offset + 1U > check_length) {
- goto fail_bounds;
- }
- tmp = buf[offset];
- if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int8_t) tmp));
- } else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
- }
- break;
- }
- case DUK__FLD_16BIT: {
- duk_uint16_t tmp;
- if (offset + 2U > check_length) {
- goto fail_bounds;
- }
- DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 2);
- tmp = du.us[0];
- if (endswap) {
- tmp = DUK_BSWAP16(tmp);
- }
- if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int16_t) tmp));
- } else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
- }
- break;
- }
- case DUK__FLD_32BIT: {
- duk_uint32_t tmp;
- if (offset + 4U > check_length) {
- goto fail_bounds;
- }
- DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
- tmp = du.ui[0];
- if (endswap) {
- tmp = DUK_BSWAP32(tmp);
- }
- if (magic_signed) {
- duk_push_int(ctx, (duk_int_t) ((duk_int32_t) tmp));
- } else {
- duk_push_uint(ctx, (duk_uint_t) tmp);
- }
- break;
- }
- case DUK__FLD_FLOAT: {
- duk_uint32_t tmp;
- if (offset + 4U > check_length) {
- goto fail_bounds;
- }
- DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
- if (endswap) {
- tmp = du.ui[0];
- tmp = DUK_BSWAP32(tmp);
- du.ui[0] = tmp;
- }
- duk_push_number(ctx, (duk_double_t) du.f[0]);
- break;
- }
- case DUK__FLD_DOUBLE: {
- if (offset + 8U > check_length) {
- goto fail_bounds;
- }
- DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 8);
- if (endswap) {
- DUK_DBLUNION_BSWAP64(&du);
- }
- duk_push_number(ctx, (duk_double_t) du.d);
- break;
- }
- case DUK__FLD_VARINT: {
- /* Node.js Buffer variable width integer field. We don't really
- * care about speed here, so aim for shortest algorithm.
- */
- duk_int_t field_bytelen;
- duk_int_t i, i_step, i_end;
-#if defined(DUK_USE_64BIT_OPS)
- duk_int64_t tmp;
- duk_small_uint_t shift_tmp;
-#else
- duk_double_t tmp;
- duk_small_int_t highbyte;
-#endif
- const duk_uint8_t *p;
-
- field_bytelen = duk_get_int(ctx, 1); /* avoid side effects! */
- if (field_bytelen < 1 || field_bytelen > 6) {
- goto fail_field_length;
- }
- if (offset + (duk_uint_t) field_bytelen > check_length) {
- goto fail_bounds;
- }
- p = (const duk_uint8_t *) (buf + offset);
-
- /* Slow gathering of value using either 64-bit arithmetic
- * or IEEE doubles if 64-bit types not available. Handling
- * of negative numbers is a bit non-obvious in both cases.
- */
-
- if (magic_bigendian) {
- /* Gather in big endian */
- i = 0;
- i_step = 1;
- i_end = field_bytelen; /* one i_step over */
- } else {
- /* Gather in little endian */
- i = field_bytelen - 1;
- i_step = -1;
- i_end = -1; /* one i_step over */
- }
-
-#if defined(DUK_USE_64BIT_OPS)
- tmp = 0;
- do {
- DUK_ASSERT(i >= 0 && i < field_bytelen);
- tmp = (tmp << 8) + (duk_int64_t) p[i];
- i += i_step;
- } while (i != i_end);
-
- if (magic_signed) {
- /* Shift to sign extend. */
- shift_tmp = 64 - (field_bytelen * 8);
- tmp = (tmp << shift_tmp) >> shift_tmp;
- }
-
- duk_push_i64(ctx, tmp);
-#else
- highbyte = p[i];
- if (magic_signed && (highbyte & 0x80) != 0) {
- /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */
- tmp = (duk_double_t) (highbyte - 256);
- } else {
- tmp = (duk_double_t) highbyte;
- }
- for (;;) {
- i += i_step;
- if (i == i_end) {
- break;
- }
- DUK_ASSERT(i >= 0 && i < field_bytelen);
- tmp = (tmp * 256.0) + (duk_double_t) p[i];
- }
-
- duk_push_number(ctx, tmp);
-#endif
- break;
- }
- default: { /* should never happen but default here */
- goto fail_bounds;
- }
- }
-
- return 1;
-
- fail_neutered:
- fail_field_length:
- fail_bounds:
- if (no_assert) {
- /* Node.js return value for noAssert out-of-bounds reads is
- * usually (but not always) NaN. Return NaN consistently.
- */
- duk_push_nan(ctx);
- return 1;
- }
-
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-/* XXX: split into separate functions for each field type? */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
- duk_hthread *thr;
- duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
- duk_small_int_t magic_ftype;
- duk_small_int_t magic_bigendian;
- duk_small_int_t magic_signed;
- duk_small_int_t magic_typedarray;
- duk_small_int_t endswap;
- duk_hbufferobject *h_this;
- duk_bool_t no_assert;
- duk_int_t offset_signed;
- duk_uint_t offset;
- duk_uint_t buffer_length;
- duk_uint_t check_length;
- duk_uint8_t *buf;
- duk_double_union du;
- duk_int_t nbytes = 0;
-
- thr = (duk_hthread *) ctx;
- DUK_UNREF(thr);
-
- magic_ftype = magic & 0x0007;
- magic_bigendian = magic & 0x0008;
- magic_signed = magic & 0x0010;
- magic_typedarray = magic & 0x0020;
- DUK_UNREF(magic_signed);
-
- h_this = duk__require_bufobj_this(ctx);
- DUK_ASSERT(h_this != NULL);
- buffer_length = h_this->length;
-
- /* [ value offset noAssert ], when ftype != DUK__FLD_VARINT */
- /* [ value offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
- /* [ offset value littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
-
- /* Handle TypedArray vs. Node.js Buffer arg differences */
- if (magic_typedarray) {
- no_assert = 0;
-#if defined(DUK_USE_INTEGER_LE)
- endswap = !duk_to_boolean(ctx, 2); /* 1=little endian */
-#else
- endswap = duk_to_boolean(ctx, 2); /* 1=little endian */
-#endif
- duk_swap(ctx, 0, 1); /* offset/value order different from Node.js */
- } else {
- no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
-#if defined(DUK_USE_INTEGER_LE)
- endswap = magic_bigendian;
-#else
- endswap = !magic_bigendian;
-#endif
- }
-
- /* Offset is coerced first to signed integer range and then to unsigned.
- * This ensures we can add a small byte length (1-8) to the offset in
- * bound checks and not wrap.
- */
- offset_signed = duk_to_int(ctx, 1);
- offset = (duk_uint_t) offset_signed;
-
- /* We need 'nbytes' even for a failed offset; return value must be
- * (offset + nbytes) even when write fails due to invalid offset.
- */
- if (magic_ftype != DUK__FLD_VARINT) {
- DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
- nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
- } else {
- nbytes = duk_get_int(ctx, 2);
- if (nbytes < 1 || nbytes > 6) {
- goto fail_field_length;
- }
- }
- DUK_ASSERT(nbytes >= 1 && nbytes <= 8);
-
- /* Now we can check offset validity. */
- if (offset_signed < 0) {
- goto fail_bounds;
- }
-
- DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
- "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
- "endswap=%d",
- duk_get_tval(ctx, 0), (long) buffer_length, (long) offset, (int) no_assert,
- (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
- (int) (magic_signed >> 4), (int) endswap));
-
- /* Coerce value to a number before computing check_length, so that
- * the field type specific coercion below can't have side effects
- * that would invalidate check_length.
- */
- duk_to_number(ctx, 0);
-
- /* Update 'buffer_length' to be the effective, safe limit which
- * takes into account the underlying buffer. This value will be
- * potentially invalidated by any side effect.
- */
- check_length = DUK_HBUFFEROBJECT_CLAMP_BYTELENGTH(h_this, buffer_length);
- DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
- (long) buffer_length, (long) check_length));
-
- if (h_this->buf) {
- buf = DUK_HBUFFEROBJECT_GET_SLICE_BASE(thr->heap, h_this);
- } else {
- /* Neutered. We could go into the switch-case safely with
- * buf == NULL because check_length == 0. To avoid scanbuild
- * warnings, fail directly instead.
- */
- DUK_ASSERT(check_length == 0);
- goto fail_neutered;
- }
- DUK_ASSERT(buf != NULL);
-
- switch (magic_ftype) {
- case DUK__FLD_8BIT: {
- if (offset + 1U > check_length) {
- goto fail_bounds;
- }
- /* sign doesn't matter when writing */
- buf[offset] = (duk_uint8_t) duk_to_uint32(ctx, 0);
- break;
- }
- case DUK__FLD_16BIT: {
- duk_uint16_t tmp;
- if (offset + 2U > check_length) {
- goto fail_bounds;
- }
- tmp = (duk_uint16_t) duk_to_uint32(ctx, 0);
- if (endswap) {
- tmp = DUK_BSWAP16(tmp);
- }
- du.us[0] = tmp;
- /* sign doesn't matter when writing */
- DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 2);
- break;
- }
- case DUK__FLD_32BIT: {
- duk_uint32_t tmp;
- if (offset + 4U > check_length) {
- goto fail_bounds;
- }
- tmp = (duk_uint32_t) duk_to_uint32(ctx, 0);
- if (endswap) {
- tmp = DUK_BSWAP32(tmp);
- }
- du.ui[0] = tmp;
- /* sign doesn't matter when writing */
- DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
- break;
- }
- case DUK__FLD_FLOAT: {
- duk_uint32_t tmp;
- if (offset + 4U > check_length) {
- goto fail_bounds;
- }
- du.f[0] = (duk_float_t) duk_to_number(ctx, 0);
- if (endswap) {
- tmp = du.ui[0];
- tmp = DUK_BSWAP32(tmp);
- du.ui[0] = tmp;
- }
- /* sign doesn't matter when writing */
- DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
- break;
- }
- case DUK__FLD_DOUBLE: {
- if (offset + 8U > check_length) {
- goto fail_bounds;
- }
- du.d = (duk_double_t) duk_to_number(ctx, 0);
- if (endswap) {
- DUK_DBLUNION_BSWAP64(&du);
- }
- /* sign doesn't matter when writing */
- DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 8);
- break;
- }
- case DUK__FLD_VARINT: {
- /* Node.js Buffer variable width integer field. We don't really
- * care about speed here, so aim for shortest algorithm.
- */
- duk_int_t field_bytelen;
- duk_int_t i, i_step, i_end;
-#if defined(DUK_USE_64BIT_OPS)
- duk_int64_t tmp;
-#else
- duk_double_t tmp;
-#endif
- duk_uint8_t *p;
-
- field_bytelen = (duk_int_t) nbytes;
- if (offset + (duk_uint_t) field_bytelen > check_length) {
- goto fail_bounds;
- }
-
- /* Slow writing of value using either 64-bit arithmetic
- * or IEEE doubles if 64-bit types not available. There's
- * no special sign handling when writing varints.
- */
-
- if (magic_bigendian) {
- /* Write in big endian */
- i = field_bytelen; /* one i_step added at top of loop */
- i_step = -1;
- i_end = 0;
- } else {
- /* Write in little endian */
- i = -1; /* one i_step added at top of loop */
- i_step = 1;
- i_end = field_bytelen - 1;
- }
-
- /* XXX: The duk_to_number() cast followed by integer coercion
- * is platform specific so NaN, +/- Infinity, and out-of-bounds
- * values result in platform specific output now.
- * See: test-bi-nodejs-buffer-proto-varint-special.js
- */
-
-#if defined(DUK_USE_64BIT_OPS)
- tmp = (duk_int64_t) duk_to_number(ctx, 0);
- p = (duk_uint8_t *) (buf + offset);
- do {
- i += i_step;
- DUK_ASSERT(i >= 0 && i < field_bytelen);
- p[i] = (duk_uint8_t) (tmp & 0xff);
- tmp = tmp >> 8; /* unnecessary shift for last byte */
- } while (i != i_end);
-#else
- tmp = duk_to_number(ctx, 0);
- p = (duk_uint8_t *) (buf + offset);
- do {
- i += i_step;
- tmp = DUK_FLOOR(tmp);
- DUK_ASSERT(i >= 0 && i < field_bytelen);
- p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0));
- tmp = tmp / 256.0; /* unnecessary div for last byte */
- } while (i != i_end);
-#endif
- break;
- }
- default: { /* should never happen but default here */
- goto fail_bounds;
- }
- }
-
- /* Node.js Buffer: return offset + #bytes written (i.e. next
- * write offset).
- */
- if (magic_typedarray) {
- /* For TypedArrays 'undefined' return value is specified
- * by ES6 (matches V8).
- */
- return 0;
- }
- duk_push_uint(ctx, offset + nbytes);
- return 1;
-
- fail_neutered:
- fail_field_length:
- fail_bounds:
- if (no_assert) {
- /* Node.js return value for failed writes is offset + #bytes
- * that would have been written.
- */
- /* XXX: for negative input offsets, 'offset' will be a large
- * positive value so the result here is confusing.
- */
- if (magic_typedarray) {
- return 0;
- }
- duk_push_uint(ctx, offset + nbytes);
- return 1;
- }
- return DUK_RET_RANGE_ERROR;
-}
-#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-
-#undef DUK__FLD_8BIT
-#undef DUK__FLD_16BIT
-#undef DUK__FLD_32BIT
-#undef DUK__FLD_FLOAT
-#undef DUK__FLD_DOUBLE
-#undef DUK__FLD_VARINT
-#undef DUK__FLD_BIGENDIAN
-#undef DUK__FLD_SIGNED
-#undef DUK__FLD_TYPEDARRAY
-#line 1 "duk_bi_date.c"
-/*
- * Date built-ins
- *
- * Unlike most built-ins, Date has some platform dependencies for getting
- * UTC time, converting between UTC and local time, and parsing and
- * formatting time values. These are all abstracted behind DUK_USE_xxx
- * config options. There are built-in platform specific providers for
- * POSIX and Windows, but external providers can also be used.
- *
- * See doc/datetime.rst.
- *
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Forward declarations
- */
-
-DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset);
-DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val);
-DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags);
-
-/*
- * Other file level defines
- */
-
-/* Debug macro to print all parts and dparts (used manually because of debug level). */
-#define DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts) do { \
- DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
- (long) (parts)[0], (long) (parts)[1], \
- (long) (parts)[2], (long) (parts)[3], \
- (long) (parts)[4], (long) (parts)[5], \
- (long) (parts)[6], (long) (parts)[7], \
- (double) (dparts)[0], (double) (dparts)[1], \
- (double) (dparts)[2], (double) (dparts)[3], \
- (double) (dparts)[4], (double) (dparts)[5], \
- (double) (dparts)[6], (double) (dparts)[7])); \
- } while (0)
-#define DUK__DPRINT_PARTS(parts) do { \
- DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \
- (long) (parts)[0], (long) (parts)[1], \
- (long) (parts)[2], (long) (parts)[3], \
- (long) (parts)[4], (long) (parts)[5], \
- (long) (parts)[6], (long) (parts)[7])); \
- } while (0)
-#define DUK__DPRINT_DPARTS(dparts) do { \
- DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
- (double) (dparts)[0], (double) (dparts)[1], \
- (double) (dparts)[2], (double) (dparts)[3], \
- (double) (dparts)[4], (double) (dparts)[5], \
- (double) (dparts)[6], (double) (dparts)[7])); \
- } while (0)
-
-/* Equivalent year for DST calculations outside [1970,2038[ range, see
- * E5 Section 15.9.1.8. Equivalent year has the same leap-year-ness and
- * starts with the same weekday on Jan 1.
- * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
- */
-#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
-DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
-#if 1
- /* This is based on V8 EquivalentYear() algorithm (see src/genequivyear.py):
- * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
- */
-
- /* non-leap year: sunday, monday, ... */
- DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031),
- DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011),
-
- /* leap year: sunday, monday, ... */
- DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020),
- DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028)
-#endif
-
-#if 0
- /* This is based on Rhino EquivalentYear() algorithm:
- * https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java
- */
-
- /* non-leap year: sunday, monday, ... */
- DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986),
- DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977),
-
- /* leap year: sunday, monday, ... */
- DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992),
- DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
-#endif
-};
-#undef DUK__YEAR
-
-/*
- * ISO 8601 subset parser.
- */
-
-/* Parser part count. */
-#define DUK__NUM_ISO8601_PARSER_PARTS 9
-
-/* Parser part indices. */
-#define DUK__PI_YEAR 0
-#define DUK__PI_MONTH 1
-#define DUK__PI_DAY 2
-#define DUK__PI_HOUR 3
-#define DUK__PI_MINUTE 4
-#define DUK__PI_SECOND 5
-#define DUK__PI_MILLISECOND 6
-#define DUK__PI_TZHOUR 7
-#define DUK__PI_TZMINUTE 8
-
-/* Parser part masks. */
-#define DUK__PM_YEAR (1 << DUK__PI_YEAR)
-#define DUK__PM_MONTH (1 << DUK__PI_MONTH)
-#define DUK__PM_DAY (1 << DUK__PI_DAY)
-#define DUK__PM_HOUR (1 << DUK__PI_HOUR)
-#define DUK__PM_MINUTE (1 << DUK__PI_MINUTE)
-#define DUK__PM_SECOND (1 << DUK__PI_SECOND)
-#define DUK__PM_MILLISECOND (1 << DUK__PI_MILLISECOND)
-#define DUK__PM_TZHOUR (1 << DUK__PI_TZHOUR)
-#define DUK__PM_TZMINUTE (1 << DUK__PI_TZMINUTE)
-
-/* Parser separator indices. */
-#define DUK__SI_PLUS 0
-#define DUK__SI_MINUS 1
-#define DUK__SI_T 2
-#define DUK__SI_SPACE 3
-#define DUK__SI_COLON 4
-#define DUK__SI_PERIOD 5
-#define DUK__SI_Z 6
-#define DUK__SI_NUL 7
-
-/* Parser separator masks. */
-#define DUK__SM_PLUS (1 << DUK__SI_PLUS)
-#define DUK__SM_MINUS (1 << DUK__SI_MINUS)
-#define DUK__SM_T (1 << DUK__SI_T)
-#define DUK__SM_SPACE (1 << DUK__SI_SPACE)
-#define DUK__SM_COLON (1 << DUK__SI_COLON)
-#define DUK__SM_PERIOD (1 << DUK__SI_PERIOD)
-#define DUK__SM_Z (1 << DUK__SI_Z)
-#define DUK__SM_NUL (1 << DUK__SI_NUL)
-
-/* Rule control flags. */
-#define DUK__CF_NEG (1 << 0) /* continue matching, set neg_tzoffset flag */
-#define DUK__CF_ACCEPT (1 << 1) /* accept string */
-#define DUK__CF_ACCEPT_NUL (1 << 2) /* accept string if next char is NUL (otherwise reject) */
-
-#define DUK__PACK_RULE(partmask,sepmask,nextpart,flags) \
- ((duk_uint32_t) (partmask) + \
- (((duk_uint32_t) (sepmask)) << 9) + \
- (((duk_uint32_t) (nextpart)) << 17) + \
- (((duk_uint32_t) (flags)) << 21))
-
-#define DUK__UNPACK_RULE(rule,var_nextidx,var_flags) do { \
- (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \
- (var_flags) = (duk_small_uint_t) ((rule) >> 21); \
- } while (0)
-
-#define DUK__RULE_MASK_PART_SEP 0x1ffffUL
-
-/* Matching separator index is used in the control table */
-DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = {
- DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, DUK_ASC_SPACE /*3*/,
- DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, DUK_ASC_NUL /*7*/
-};
-
-/* Rule table: first matching rule is used to determine what to do next. */
-DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
- DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0),
- DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0),
- DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0),
- DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0),
- DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0),
- DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0),
- DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0),
- DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_PLUS, DUK__PI_TZHOUR, 0),
- DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_MINUS, DUK__PI_TZHOUR, DUK__CF_NEG),
- DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND, DUK__SM_Z, 0, DUK__CF_ACCEPT_NUL),
- DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY | DUK__PM_HOUR /*Note1*/ | DUK__PM_MINUTE | DUK__PM_SECOND | DUK__PM_MILLISECOND | DUK__PM_TZHOUR /*Note2*/ | DUK__PM_TZMINUTE, DUK__SM_NUL, 0, DUK__CF_ACCEPT)
-
- /* Note1: the specification doesn't require matching a time form with
- * just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z".
- *
- * Note2: the specification doesn't require matching a timezone offset
- * with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02"
- */
-};
-
-DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const char *str) {
- duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
- duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
- duk_double_t d;
- const duk_uint8_t *p;
- duk_small_uint_t part_idx = 0;
- duk_int_t accum = 0;
- duk_small_uint_t ndigits = 0;
- duk_bool_t neg_year = 0;
- duk_bool_t neg_tzoffset = 0;
- duk_uint_fast8_t ch;
- duk_small_uint_t i;
-
- /* During parsing, month and day are one-based; set defaults here. */
- DUK_MEMZERO(parts, sizeof(parts));
- DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */
- parts[DUK_DATE_IDX_MONTH] = 1;
- parts[DUK_DATE_IDX_DAY] = 1;
-
- /* Special handling for year sign. */
- p = (const duk_uint8_t *) str;
- ch = p[0];
- if (ch == DUK_ASC_PLUS) {
- p++;
- } else if (ch == DUK_ASC_MINUS) {
- neg_year = 1;
- p++;
- }
-
- for (;;) {
- ch = *p++;
- DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')",
- (long) part_idx, (long) ch,
- (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : DUK_ASC_QUESTION)));
-
- if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) {
- if (ndigits >= 9) {
- DUK_DDD(DUK_DDDPRINT("too many digits -> reject"));
- goto reject;
- }
- if (part_idx == DUK__PI_MILLISECOND /*msec*/ && ndigits >= 3) {
- /* ignore millisecond fractions after 3 */
- } else {
- accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00;
- ndigits++;
- }
- } else {
- duk_uint_fast32_t match_val;
- duk_small_int_t sep_idx;
-
- if (ndigits <= 0) {
- goto reject;
- }
- if (part_idx == DUK__PI_MILLISECOND) {
- /* complete the millisecond field */
- while (ndigits < 3) {
- accum *= 10;
- ndigits++;
- }
- }
- parts[part_idx] = accum;
- DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld", (long) part_idx, (long) accum));
-
- accum = 0;
- ndigits = 0;
-
- for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) {
- if (duk__parse_iso8601_seps[i] == ch) {
- break;
- }
- }
- if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) {
- DUK_DDD(DUK_DDDPRINT("separator character doesn't match -> reject"));
- goto reject;
- }
-
- sep_idx = i;
- match_val = (1UL << part_idx) + (1UL << (sep_idx + 9)); /* match against rule part/sep bits */
-
- for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) {
- duk_uint_fast32_t rule = duk__parse_iso8601_control[i];
- duk_small_uint_t nextpart;
- duk_small_uint_t cflags;
-
- DUK_DDD(DUK_DDDPRINT("part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx",
- (long) part_idx, (long) sep_idx,
- (unsigned long) match_val, (unsigned long) rule));
-
- if ((rule & match_val) != match_val) {
- continue;
- }
-
- DUK__UNPACK_RULE(rule, nextpart, cflags);
-
- DUK_DDD(DUK_DDDPRINT("rule match -> part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, "
- "rule=0x%08lx -> nextpart=%ld, cflags=0x%02lx",
- (long) part_idx, (long) sep_idx,
- (unsigned long) match_val, (unsigned long) rule,
- (long) nextpart, (unsigned long) cflags));
-
- if (cflags & DUK__CF_NEG) {
- neg_tzoffset = 1;
- }
-
- if (cflags & DUK__CF_ACCEPT) {
- goto accept;
- }
-
- if (cflags & DUK__CF_ACCEPT_NUL) {
- DUK_ASSERT(*(p - 1) != (char) 0);
- if (*p == DUK_ASC_NUL) {
- goto accept;
- }
- goto reject;
- }
-
- part_idx = nextpart;
- break;
- } /* rule match */
-
- if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) {
- DUK_DDD(DUK_DDDPRINT("no rule matches -> reject"));
- goto reject;
- }
-
- if (ch == 0) {
- /* This shouldn't be necessary, but check just in case
- * to avoid any chance of overruns.
- */
- DUK_DDD(DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject"));
- goto reject;
- }
- } /* if-digit-else-ctrl */
- } /* char loop */
-
- /* We should never exit the loop above. */
- DUK_UNREACHABLE();
-
- reject:
- DUK_DDD(DUK_DDDPRINT("reject"));
- return 0;
-
- accept:
- DUK_DDD(DUK_DDDPRINT("accept"));
-
- /* Apply timezone offset to get the main parts in UTC */
- if (neg_year) {
- parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR];
- }
- if (neg_tzoffset) {
- parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR];
- parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE];
- } else {
- parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR];
- parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE];
- }
- parts[DUK__PI_MONTH] -= 1; /* zero-based month */
- parts[DUK__PI_DAY] -= 1; /* zero-based day */
-
- /* Use double parts, they tolerate unnormalized time.
- *
- * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR)
- * on purpose. It won't be actually used by duk_bi_date_get_timeval_from_dparts(),
- * but will make the value initialized just in case, and avoid any
- * potential for Valgrind issues.
- */
- for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
- DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld", (long) i, (long) parts[i]));
- dparts[i] = parts[i];
- }
-
- d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- duk_push_number(ctx, d);
- return 1;
-}
-
-/*
- * Date/time parsing helper.
- *
- * Parse a datetime string into a time value. We must first try to parse
- * the input according to the standard format in E5.1 Section 15.9.1.15.
- * If that fails, we can try to parse using custom parsing, which can
- * either be platform neutral (custom code) or platform specific (using
- * existing platform API calls).
- *
- * Note in particular that we must parse whatever toString(), toUTCString(),
- * and toISOString() can produce; see E5.1 Section 15.9.4.2.
- *
- * Returns 1 to allow tail calling.
- *
- * There is much room for improvement here with respect to supporting
- * alternative datetime formats. For instance, V8 parses '2012-01-01' as
- * UTC and '2012/01/01' as local time.
- */
-
-DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
- /* XXX: there is a small risk here: because the ISO 8601 parser is
- * very loose, it may end up parsing some datetime values which
- * would be better parsed with a platform specific parser.
- */
-
- DUK_ASSERT(str != NULL);
- DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
-
- if (duk__parse_string_iso8601_subset(ctx, str) != 0) {
- return 1;
- }
-
-#if defined(DUK_USE_DATE_PARSE_STRING)
- /* Contract, either:
- * - Push value on stack and return 1
- * - Don't push anything on stack and return 0
- */
-
- if (DUK_USE_DATE_PARSE_STRING(ctx, str) != 0) {
- return 1;
- }
-#else
- /* No platform-specific parsing, this is not an error. */
-#endif
-
- duk_push_nan(ctx);
- return 1;
-}
-
-/*
- * Calendar helpers
- *
- * Some helpers are used for getters and can operate on normalized values
- * which can be represented with 32-bit signed integers. Other helpers are
- * needed by setters and operate on un-normalized double values, must watch
- * out for non-finite numbers etc.
- */
-
-DUK_LOCAL duk_uint8_t duk__days_in_month[12] = {
- (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30,
- (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31,
- (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31
-};
-
-/* Maximum iteration count for computing UTC-to-local time offset when
- * creating an Ecmascript time value from local parts.
- */
-#define DUK__LOCAL_TZOFFSET_MAXITER 4
-
-/* Because 'day since epoch' can be negative and is used to compute weekday
- * using a modulo operation, add this multiple of 7 to avoid negative values
- * when year is below 1970 epoch. Ecmascript time values are restricted to
- * +/- 100 million days from epoch, so this adder fits nicely into 32 bits.
- * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin.
- */
-#define DUK__WEEKDAY_MOD_ADDER (20000000 * 7) /* 0x08583b00 */
-
-DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) {
- if ((year % 4) != 0) {
- return 0;
- }
- if ((year % 100) != 0) {
- return 1;
- }
- if ((year % 400) != 0) {
- return 0;
- }
- return 1;
-}
-
-DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) {
- return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS);
-}
-
-DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) {
- return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= DUK_DATE_MSEC_100M_DAYS_LEEWAY);
-}
-
-DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) {
- return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR);
-}
-
-DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) {
- if (!DUK_ISFINITE(x)) {
- return DUK_DOUBLE_NAN;
- }
-
- if (!duk_bi_date_timeval_in_valid_range(x)) {
- return DUK_DOUBLE_NAN;
- }
-
- x = duk_js_tointeger_number(x);
-
- /* Here we'd have the option to normalize -0 to +0. */
- return x;
-}
-
-/* Integer division which floors also negative values correctly. */
-DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) {
- DUK_ASSERT(b > 0);
- if (a >= 0) {
- return a / b;
- } else {
- /* e.g. a = -4, b = 5 --> -4 - 5 + 1 / 5 --> -8 / 5 --> -1
- * a = -5, b = 5 --> -5 - 5 + 1 / 5 --> -9 / 5 --> -1
- * a = -6, b = 5 --> -6 - 5 + 1 / 5 --> -10 / 5 --> -2
- */
- return (a - b + 1) / b;
- }
-}
-
-/* Compute day number of the first day of a given year. */
-DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) {
- /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative
- * values, but is incorrect for negative ones.
- */
- return 365 * (year - 1970)
- + duk__div_floor(year - 1969, 4)
- - duk__div_floor(year - 1901, 100)
- + duk__div_floor(year - 1601, 400);
-}
-
-/* Given a day number, determine year and day-within-year. */
-DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year) {
- duk_int_t year;
- duk_int_t diff_days;
-
- /* estimate year upwards (towards positive infinity), then back down;
- * two iterations should be enough
- */
-
- if (day >= 0) {
- year = 1970 + day / 365;
- } else {
- year = 1970 + day / 366;
- }
-
- for (;;) {
- diff_days = duk__day_from_year(year) - day;
- DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld", (long) year, (long) day, (long) diff_days));
- if (diff_days <= 0) {
- DUK_ASSERT(-diff_days < 366); /* fits into duk_small_int_t */
- *out_day_within_year = -diff_days;
- DUK_DDD(DUK_DDDPRINT("--> year=%ld, day-within-year=%ld",
- (long) year, (long) *out_day_within_year));
- DUK_ASSERT(*out_day_within_year >= 0);
- DUK_ASSERT(*out_day_within_year < (duk_bi_date_is_leap_year(year) ? 366 : 365));
- return year;
- }
-
- /* Note: this is very tricky; we must never 'overshoot' the
- * correction downwards.
- */
- year -= 1 + (diff_days - 1) / 366; /* conservative */
- }
-}
-
-/* Given a (year, month, day-within-month) triple, compute day number.
- * The input triple is un-normalized and may contain non-finite values.
- */
-DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day) {
- duk_int_t day_num;
- duk_bool_t is_leap;
- duk_small_int_t i, n;
-
- /* Assume that year, month, day are all coerced to whole numbers.
- * They may also be NaN or infinity, in which case this function
- * must return NaN or infinity to ensure time value becomes NaN.
- * If 'day' is NaN, the final return will end up returning a NaN,
- * so it doesn't need to be checked here.
- */
-
- if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) {
- return DUK_DOUBLE_NAN;
- }
-
- year += DUK_FLOOR(month / 12.0);
-
- month = DUK_FMOD(month, 12.0);
- if (month < 0.0) {
- /* handle negative values */
- month += 12.0;
- }
-
- /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but
- * does not normalize the day-of-month (nor check whether or not
- * it is finite) because it's not necessary for finding the day
- * number which matches the (year,month) pair.
- *
- * We assume that duk__day_from_year() is exact here.
- *
- * Without an explicit infinity / NaN check in the beginning,
- * day_num would be a bogus integer here.
- *
- * It's possible for 'year' to be out of integer range here.
- * If so, we need to return NaN without integer overflow.
- * This fixes test-bug-setyear-overflow.js.
- */
-
- if (!duk_bi_date_year_in_valid_range(year)) {
- DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid integer overflow: %lf", (double) year));
- return DUK_DOUBLE_NAN;
- }
- day_num = duk__day_from_year((duk_int_t) year);
- is_leap = duk_bi_date_is_leap_year((duk_int_t) year);
-
- n = (duk_small_int_t) month;
- for (i = 0; i < n; i++) {
- day_num += duk__days_in_month[i];
- if (i == 1 && is_leap) {
- day_num++;
- }
- }
-
- /* If 'day' is NaN, returns NaN. */
- return (duk_double_t) day_num + day;
-}
-
-/* Split time value into parts. The time value is assumed to be an internal
- * one, i.e. finite, no fractions. Possible local time adjustment has already
- * been applied when reading the time value.
- */
-DUK_INTERNAL void duk_bi_date_timeval_to_parts(duk_double_t d, duk_int_t *parts, duk_double_t *dparts, duk_small_uint_t flags) {
- duk_double_t d1, d2;
- duk_int_t t1, t2;
- duk_int_t day_since_epoch;
- duk_int_t year; /* does not fit into 16 bits */
- duk_small_int_t day_in_year;
- duk_small_int_t month;
- duk_small_int_t day;
- duk_small_int_t dim;
- duk_int_t jan1_since_epoch;
- duk_small_int_t jan1_weekday;
- duk_int_t equiv_year;
- duk_small_uint_t i;
- duk_bool_t is_leap;
- duk_small_int_t arridx;
-
- DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
- DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions in internal time */
-
- /* The timevalue must be in valid Ecmascript range, but since a local
- * time offset can be applied, we need to allow a +/- 24h leeway to
- * the value. In other words, although the UTC time is within the
- * Ecmascript range, the local part values can be just outside of it.
- */
- DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
- DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
-
- /* these computations are guaranteed to be exact for the valid
- * E5 time value range, assuming milliseconds without fractions.
- */
- d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
- if (d1 < 0.0) {
- /* deal with negative values */
- d1 += (duk_double_t) DUK_DATE_MSEC_DAY;
- }
- d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY));
- DUK_ASSERT(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1 == d);
- /* now expected to fit into a 32-bit integer */
- t1 = (duk_int_t) d1;
- t2 = (duk_int_t) d2;
- day_since_epoch = t2;
- DUK_ASSERT((duk_double_t) t1 == d1);
- DUK_ASSERT((duk_double_t) t2 == d2);
-
- /* t1 = milliseconds within day (fits 32 bit)
- * t2 = day number from epoch (fits 32 bit, may be negative)
- */
-
- parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
- parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60;
- parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60;
- parts[DUK_DATE_IDX_HOUR] = t1;
- DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999);
- DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59);
- DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59);
- DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23);
-
- DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld",
- (double) d, (double) d1, (double) d2, (long) t1, (long) t2,
- (long) parts[DUK_DATE_IDX_HOUR],
- (long) parts[DUK_DATE_IDX_MINUTE],
- (long) parts[DUK_DATE_IDX_SECOND],
- (long) parts[DUK_DATE_IDX_MILLISECOND]));
-
- /* This assert depends on the input parts representing time inside
- * the Ecmascript range.
- */
- DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0);
- parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
- DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6);
-
- year = duk__year_from_day(t2, &day_in_year);
- day = day_in_year;
- is_leap = duk_bi_date_is_leap_year(year);
- for (month = 0; month < 12; month++) {
- dim = duk__days_in_month[month];
- if (month == 1 && is_leap) {
- dim++;
- }
- DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld",
- (long) month, (long) dim, (long) day));
- if (day < dim) {
- break;
- }
- day -= dim;
- }
- DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month));
- DUK_ASSERT(month >= 0 && month <= 11);
- DUK_ASSERT(day >= 0 && day <= 31);
-
- /* Equivalent year mapping, used to avoid DST trouble when platform
- * may fail to provide reasonable DST answers for dates outside the
- * ordinary range (e.g. 1970-2038). An equivalent year has the same
- * leap-year-ness as the original year and begins on the same weekday
- * (Jan 1).
- *
- * The year 2038 is avoided because there seem to be problems with it
- * on some platforms. The year 1970 is also avoided as there were
- * practical problems with it; an equivalent year is used for it too,
- * which breaks some DST computations for 1970 right now, see e.g.
- * test-bi-date-tzoffset-brute-fi.js.
- */
- if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) {
- DUK_ASSERT(is_leap == 0 || is_leap == 1);
-
- jan1_since_epoch = day_since_epoch - day_in_year; /* day number for Jan 1 since epoch */
- DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0);
- jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
- DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6);
- arridx = jan1_weekday;
- if (is_leap) {
- arridx += 7;
- }
- DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t)));
-
- equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970;
- year = equiv_year;
- DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, "
- "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld",
- (long) year, (long) day_in_year, (long) day_since_epoch,
- (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year));
- }
-
- parts[DUK_DATE_IDX_YEAR] = year;
- parts[DUK_DATE_IDX_MONTH] = month;
- parts[DUK_DATE_IDX_DAY] = day;
-
- if (flags & DUK_DATE_FLAG_ONEBASED) {
- parts[DUK_DATE_IDX_MONTH]++; /* zero-based -> one-based */
- parts[DUK_DATE_IDX_DAY]++; /* -""- */
- }
-
- if (dparts != NULL) {
- for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
- dparts[i] = (duk_double_t) parts[i];
- }
- }
-}
-
-/* Compute time value from (double) parts. The parts can be either UTC
- * or local time; if local, they need to be (conceptually) converted into
- * UTC time. The parts may represent valid or invalid time, and may be
- * wildly out of range (but may cancel each other and still come out in
- * the valid Date range).
- */
-DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags) {
-#if defined(DUK_USE_PARANOID_DATE_COMPUTATION)
- /* See comments below on MakeTime why these are volatile. */
- volatile duk_double_t tmp_time;
- volatile duk_double_t tmp_day;
- volatile duk_double_t d;
-#else
- duk_double_t tmp_time;
- duk_double_t tmp_day;
- duk_double_t d;
-#endif
- duk_small_uint_t i;
- duk_int_t tzoff, tzoffprev1, tzoffprev2;
-
- /* Expects 'this' at top of stack on entry. */
-
- /* Coerce all finite parts with ToInteger(). ToInteger() must not
- * be called for NaN/Infinity because it will convert e.g. NaN to
- * zero. If ToInteger() has already been called, this has no side
- * effects and is idempotent.
- *
- * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind
- * issues if the value is uninitialized.
- */
- for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) {
- /* SCANBUILD: scan-build complains here about assigned value
- * being garbage or undefined. This is correct but operating
- * on undefined values has no ill effect and is ignored by the
- * caller in the case where this happens.
- */
- d = dparts[i];
- if (DUK_ISFINITE(d)) {
- dparts[i] = duk_js_tointeger_number(d);
- }
- }
-
- /* Use explicit steps in computation to try to ensure that
- * computation happens with intermediate results coerced to
- * double values (instead of using something more accurate).
- * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
- * rules (= Ecmascript '+' and '*' operators).
- *
- * Without 'volatile' even this approach fails on some platform
- * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu
- * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js
- * would fail because of some optimizations when computing tmp_time
- * (MakeTime below). Adding 'volatile' to tmp_time solved this
- * particular problem (annoyingly, also adding debug prints or
- * running the executable under valgrind hides it).
- */
-
- /* MakeTime */
- tmp_time = 0.0;
- tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR);
- tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE);
- tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND);
- tmp_time += dparts[DUK_DATE_IDX_MILLISECOND];
-
- /* MakeDay */
- tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]);
-
- /* MakeDate */
- d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time;
-
- DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf",
- (double) tmp_time, (double) tmp_day, (double) d));
-
- /* Optional UTC conversion. */
- if (flags & DUK_DATE_FLAG_LOCALTIME) {
- /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a
- * time value computed from UTC parts. At this point we only
- * have 'd' which is a time value computed from local parts, so
- * it is off by the UTC-to-local time offset which we don't know
- * yet. The current solution for computing the UTC-to-local
- * time offset is to iterate a few times and detect a fixed
- * point or a two-cycle loop (or a sanity iteration limit),
- * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js.
- *
- * E5.1 Section 15.9.1.9:
- * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
- *
- * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0.
- */
-
-#if 0
- /* Old solution: don't iterate, incorrect */
- tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
- DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", (long) tzoff));
- d -= tzoff * 1000L;
- DUK_UNREF(tzoffprev1);
- DUK_UNREF(tzoffprev2);
-#endif
-
- /* Iteration solution */
- tzoff = 0;
- tzoffprev1 = 999999999L; /* invalid value which never matches */
- for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) {
- tzoffprev2 = tzoffprev1;
- tzoffprev1 = tzoff;
- tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L);
- DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld",
- (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
- if (tzoff == tzoffprev1) {
- DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
- (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
- break;
- } else if (tzoff == tzoffprev2) {
- /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js.
- * In these cases, favor a higher tzoffset to get a consistent
- * result which is independent of iteration count. Not sure if
- * this is a generically correct solution.
- */
- DUK_DDD(DUK_DDDPRINT("tzoffset iteration two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
- (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
- if (tzoffprev1 > tzoff) {
- tzoff = tzoffprev1;
- }
- break;
- }
- }
- DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld", (long) tzoff));
- d -= tzoff * 1000L;
- }
-
- /* TimeClip(), which also handles Infinity -> NaN conversion */
- d = duk__timeclip(d);
-
- return d;
-}
-
-/*
- * API oriented helpers
- */
-
-/* Push 'this' binding, check that it is a Date object; then push the
- * internal time value. At the end, stack is: [ ... this timeval ].
- * Returns the time value. Local time adjustment is done if requested.
- */
-DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
- duk_double_t d;
- duk_int_t tzoffset = 0;
-
- duk_push_this(ctx);
- h = duk_get_hobject(ctx, -1); /* XXX: getter with class check, useful in built-ins */
- if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
- DUK_ERROR_TYPE(thr, "expected Date");
- }
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- d = duk_to_number(ctx, -1);
- duk_pop(ctx);
-
- if (DUK_ISNAN(d)) {
- if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
- d = 0.0;
- }
- if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) {
- DUK_ERROR_RANGE(thr, "Invalid Date");
- }
- }
- /* if no NaN handling flag, may still be NaN here, but not Inf */
- DUK_ASSERT(!DUK_ISINF(d));
-
- if (flags & DUK_DATE_FLAG_LOCALTIME) {
- /* Note: DST adjustment is determined using UTC time.
- * If 'd' is NaN, tzoffset will be 0.
- */
- tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); /* seconds */
- d += tzoffset * 1000L;
- }
- if (out_tzoffset) {
- *out_tzoffset = tzoffset;
- }
-
- /* [ ... this ] */
- return d;
-}
-
-DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags) {
- return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
-}
-
-/* Set timeval to 'this' from dparts, push the new time value onto the
- * value stack and return 1 (caller can then tail call us). Expects
- * the value stack to contain 'this' on the stack top.
- */
-DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags) {
- duk_double_t d;
-
- /* [ ... this ] */
-
- d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
- duk_push_number(ctx, d); /* -> [ ... this timeval_new ] */
- duk_dup_top(ctx); /* -> [ ... this timeval_new timeval_new ] */
- duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE);
-
- /* stack top: new time value, return 1 to allow tail calls */
- return 1;
-}
-
-/* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */
-DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags, duk_uint8_t *out_buf) {
- char yearstr[8]; /* "-123456\0" */
- char tzstr[8]; /* "+11:22\0" */
- char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE;
-
- DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
- DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
- DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && parts[DUK_DATE_IDX_YEAR] <= 999999);
-
- /* Note: %06d for positive value, %07d for negative value to include
- * sign and 6 digits.
- */
- DUK_SNPRINTF(yearstr,
- sizeof(yearstr),
- (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] <= 9999) ? "%04ld" :
- ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : "%07ld"),
- (long) parts[DUK_DATE_IDX_YEAR]);
- yearstr[sizeof(yearstr) - 1] = (char) 0;
-
- if (flags & DUK_DATE_FLAG_LOCALTIME) {
- /* tzoffset seconds are dropped; 16 bits suffice for
- * time offset in minutes
- */
- if (tzoffset >= 0) {
- duk_small_int_t tmp = tzoffset / 60;
- DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
- } else {
- duk_small_int_t tmp = -tzoffset / 60;
- DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
- }
- tzstr[sizeof(tzstr) - 1] = (char) 0;
- } else {
- tzstr[0] = DUK_ASC_UC_Z;
- tzstr[1] = (char) 0;
- }
-
- /* Unlike year, the other parts fit into 16 bits so %d format
- * is portable.
- */
- if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
- DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s",
- (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep,
- (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
- (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr);
- } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
- DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d",
- (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]);
- } else {
- DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
- DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s",
- (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
- (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND],
- (const char *) tzstr);
- }
-}
-
-/* Helper for string conversion calls: check 'this' binding, get the
- * internal time value, and format date and/or time in a few formats.
- * Return value allows tail calls.
- */
-DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t flags) {
- duk_double_t d;
- duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
- duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */
- duk_bool_t rc;
- duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE];
-
- DUK_UNREF(rc); /* unreferenced with some options */
-
- d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
- if (DUK_ISNAN(d)) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
- return 1;
- }
- DUK_ASSERT(DUK_ISFINITE(d));
-
- /* formatters always get one-based month/day-of-month */
- duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED);
- DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
- DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
-
- if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) {
- /* try locale specific formatter; if it refuses to format the
- * string, fall back to an ISO 8601 formatted value in local
- * time.
- */
-#if defined(DUK_USE_DATE_FORMAT_STRING)
- /* Contract, either:
- * - Push string to value stack and return 1
- * - Don't push anything and return 0
- */
-
- rc = DUK_USE_DATE_FORMAT_STRING(ctx, parts, tzoffset, flags);
- if (rc != 0) {
- return 1;
- }
-#else
- /* No locale specific formatter; this is OK, we fall back
- * to ISO 8601.
- */
-#endif
- }
-
- /* Different calling convention than above used because the helper
- * is shared.
- */
- duk__format_parts_iso8601(parts, tzoffset, flags, buf);
- duk_push_string(ctx, (const char *) buf);
- return 1;
-}
-
-/* Helper for component getter calls: check 'this' binding, get the
- * internal time value, split it into parts (either as UTC time or
- * local time), push a specified component as a return value to the
- * value stack and return 1 (caller can then tail call us).
- */
-DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flags_and_idx) {
- duk_double_t d;
- duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
- duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
-
- DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */
- DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
-
- d = duk__push_this_get_timeval(ctx, flags_and_idx);
- if (DUK_ISNAN(d)) {
- duk_push_nan(ctx);
- return 1;
- }
- DUK_ASSERT(DUK_ISFINITE(d));
-
- duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx); /* no need to mask idx portion */
-
- /* Setter APIs detect special year numbers (0...99) and apply a +1900
- * only in certain cases. The legacy getYear() getter applies -1900
- * unconditionally.
- */
- duk_push_int(ctx, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
- return 1;
-}
-
-/* Helper for component setter calls: check 'this' binding, get the
- * internal time value, split it into parts (either as UTC time or
- * local time), modify one or more components as specified, recompute
- * the time value, set it as the internal value. Finally, push the
- * new time value as a return value to the value stack and return 1
- * (caller can then tail call us).
- */
-DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flags_and_maxnargs) {
- duk_double_t d;
- duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
- duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
- duk_idx_t nargs;
- duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
- duk_small_uint_t idx_first, idx;
- duk_small_uint_t i;
-
- nargs = duk_get_top(ctx);
- d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
- DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
-
- if (DUK_ISFINITE(d)) {
- duk_bi_date_timeval_to_parts(d, parts, dparts, flags_and_maxnargs);
- } else {
- /* NaN timevalue: we need to coerce the arguments, but
- * the resulting internal timestamp needs to remain NaN.
- * This works but is not pretty: parts and dparts will
- * be partially uninitialized, but we only write to them.
- */
- }
-
- /*
- * Determining which datetime components to overwrite based on
- * stack arguments is a bit complicated, but important to factor
- * out from setters themselves for compactness.
- *
- * If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type:
- *
- * 1 -> millisecond
- * 2 -> second, [millisecond]
- * 3 -> minute, [second], [millisecond]
- * 4 -> hour, [minute], [second], [millisecond]
- *
- * Else:
- *
- * 1 -> date
- * 2 -> month, [date]
- * 3 -> year, [month], [date]
- *
- * By comparing nargs and maxnargs (and flags) we know which
- * components to override. We rely on part index ordering.
- */
-
- if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) {
- DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4);
- idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1);
- } else {
- DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3);
- idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1);
- }
- DUK_ASSERT_DISABLE(idx_first >= 0); /* unsigned */
- DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS);
-
- for (i = 0; i < maxnargs; i++) {
- if ((duk_idx_t) i >= nargs) {
- /* no argument given -> leave components untouched */
- break;
- }
- idx = idx_first + i;
- DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
- DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
-
- if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
- duk__twodigit_year_fixup(ctx, (duk_idx_t) i);
- }
-
- dparts[idx] = duk_to_number(ctx, i);
-
- if (idx == DUK_DATE_IDX_DAY) {
- /* Day-of-month is one-based in the API, but zero-based
- * internally, so fix here. Note that month is zero-based
- * both in the API and internally.
- */
- /* SCANBUILD: complains about use of uninitialized values.
- * The complaint is correct, but operating in undefined
- * values here is intentional in some cases and the caller
- * ignores the results.
- */
- dparts[idx] -= 1.0;
- }
- }
-
- /* Leaves new timevalue on stack top and returns 1, which is correct
- * for part setters.
- */
- if (DUK_ISFINITE(d)) {
- return duk__set_this_timeval_from_dparts(ctx, dparts, flags_and_maxnargs);
- } else {
- /* Internal timevalue is already NaN, so don't touch it. */
- duk_push_nan(ctx);
- return 1;
- }
-}
-
-/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
- * 1900 and replace value at idx_val.
- */
-DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
- duk_double_t d;
-
- /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
- * might not generate better code due to casting.
- */
-
- /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
- duk_to_number(ctx, idx_val);
- if (duk_is_nan(ctx, idx_val)) {
- return;
- }
- duk_dup(ctx, idx_val);
- duk_to_int(ctx, -1);
- d = duk_get_number(ctx, -1); /* get as double to handle huge numbers correctly */
- if (d >= 0.0 && d <= 99.0) {
- d += 1900.0;
- duk_push_number(ctx, d);
- duk_replace(ctx, idx_val);
- }
- duk_pop(ctx);
-}
-
-/* Set datetime parts from stack arguments, defaulting any missing values.
- * Day-of-week is not set; it is not required when setting the time value.
- */
-DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts, duk_idx_t nargs) {
- duk_double_t d;
- duk_small_uint_t i;
- duk_small_uint_t idx;
-
- /* Causes a ToNumber() coercion, but doesn't break coercion order since
- * year is coerced first anyway.
- */
- duk__twodigit_year_fixup(ctx, 0);
-
- /* There are at most 7 args, but we use 8 here so that also
- * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
- * for any Valgrind gripes later.
- */
- for (i = 0; i < 8; i++) {
- /* Note: rely on index ordering */
- idx = DUK_DATE_IDX_YEAR + i;
- if ((duk_idx_t) i < nargs) {
- d = duk_to_number(ctx, (duk_idx_t) i);
- if (idx == DUK_DATE_IDX_DAY) {
- /* Convert day from one-based to zero-based (internal). This may
- * cause the day part to be negative, which is OK.
- */
- d -= 1.0;
- }
- } else {
- /* All components default to 0 except day-of-month which defaults
- * to 1. However, because our internal day-of-month is zero-based,
- * it also defaults to zero here.
- */
- d = 0.0;
- }
- dparts[idx] = d;
- }
-
- DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf",
- (double) dparts[0], (double) dparts[1],
- (double) dparts[2], (double) dparts[3],
- (double) dparts[4], (double) dparts[5],
- (double) dparts[6], (double) dparts[7]));
-}
-
-/*
- * Helper to format a time value into caller buffer, used by logging.
- * 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long.
- */
-
-DUK_INTERNAL void duk_bi_date_format_timeval(duk_double_t timeval, duk_uint8_t *out_buf) {
- duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
-
- duk_bi_date_timeval_to_parts(timeval,
- parts,
- NULL,
- DUK_DATE_FLAG_ONEBASED);
-
- duk__format_parts_iso8601(parts,
- 0 /*tzoffset*/,
- DUK_DATE_FLAG_TOSTRING_DATE |
- DUK_DATE_FLAG_TOSTRING_TIME |
- DUK_DATE_FLAG_SEP_T /*flags*/,
- out_buf);
-}
-
-/*
- * Indirect magic value lookup for Date methods.
- *
- * Date methods don't put their control flags into the function magic value
- * because they wouldn't fit into a LIGHTFUNC's magic field. Instead, the
- * magic value is set to an index pointing to the array of control flags
- * below.
- *
- * This must be kept in strict sync with genbuiltins.py!
- */
-
-static duk_uint16_t duk__date_magics[] = {
- /* 0: toString */
- DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
-
- /* 1: toDateString */
- DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME,
-
- /* 2: toTimeString */
- DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
-
- /* 3: toLocaleString */
- DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
-
- /* 4: toLocaleDateString */
- DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
-
- /* 5: toLocaleTimeString */
- DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
-
- /* 6: toUTCString */
- DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME,
-
- /* 7: toISOString */
- DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T,
-
- /* 8: getFullYear */
- DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 9: getUTCFullYear */
- 0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 10: getMonth */
- DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 11: getUTCMonth */
- 0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 12: getDate */
- DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 13: getUTCDate */
- DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 14: getDay */
- DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 15: getUTCDay */
- 0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 16: getHours */
- DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 17: getUTCHours */
- 0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 18: getMinutes */
- DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 19: getUTCMinutes */
- 0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 20: getSeconds */
- DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 21: getUTCSeconds */
- 0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 22: getMilliseconds */
- DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 23: getUTCMilliseconds */
- 0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 24: setMilliseconds */
- DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 25: setUTCMilliseconds */
- DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 26: setSeconds */
- DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 27: setUTCSeconds */
- DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 28: setMinutes */
- DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 29: setUTCMinutes */
- DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 30: setHours */
- DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 31: setUTCHours */
- DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 32: setDate */
- DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 33: setUTCDate */
- 0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 34: setMonth */
- DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 35: setUTCMonth */
- 0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 36: setFullYear */
- DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 37: setUTCFullYear */
- DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 38: getYear */
- DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
-
- /* 39: setYear */
- DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
-};
-
-DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
- duk_small_int_t magicidx = (duk_small_uint_t) duk_get_current_magic(ctx);
- DUK_ASSERT(magicidx >= 0 && magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
- return (duk_small_uint_t) duk__date_magics[magicidx];
-}
-
-/*
- * Constructor calls
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
- duk_idx_t nargs = duk_get_top(ctx);
- duk_bool_t is_cons = duk_is_constructor_call(ctx);
- duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
- duk_double_t d;
-
- DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
-
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
- DUK_BIDX_DATE_PROTOTYPE);
-
- /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
- * is mutable.
- */
-
- if (nargs == 0 || !is_cons) {
- d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx));
- duk_push_number(ctx, d);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
- if (!is_cons) {
- /* called as a normal function: return new Date().toString() */
- duk_to_string(ctx, -1);
- }
- return 1;
- } else if (nargs == 1) {
- duk_to_primitive(ctx, 0, DUK_HINT_NONE);
- if (duk_is_string(ctx, 0)) {
- duk__parse_string(ctx, duk_to_string(ctx, 0));
- duk_replace(ctx, 0); /* may be NaN */
- }
- d = duk__timeclip(duk_to_number(ctx, 0));
- duk_push_number(ctx, d);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
- return 1;
- }
-
- duk__set_parts_from_args(ctx, dparts, nargs);
-
- /* Parts are in local time, convert when setting. */
-
- (void) duk__set_this_timeval_from_dparts(ctx, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
- duk_pop(ctx); /* -> [ ... this ] */
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx) {
- return duk__parse_string(ctx, duk_to_string(ctx, 0));
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
- duk_idx_t nargs = duk_get_top(ctx);
- duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
- duk_double_t d;
-
- /* Behavior for nargs < 2 is implementation dependent: currently we'll
- * set a NaN time value (matching V8 behavior) in this case.
- */
-
- if (nargs < 2) {
- duk_push_nan(ctx);
- } else {
- duk__set_parts_from_args(ctx, dparts, nargs);
- d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- duk_push_number(ctx, d);
- }
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
- duk_double_t d;
-
- d = DUK_USE_DATE_GET_NOW(ctx);
- DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */
- duk_push_number(ctx, d);
- return 1;
-}
-
-/*
- * String/JSON conversions
- *
- * Human readable conversions are now basically ISO 8601 with a space
- * (instead of 'T') as the date/time separator. This is a good baseline
- * and is platform independent.
- *
- * A shared native helper to provide many conversions. Magic value contains
- * a set of flags. The helper provides:
- *
- * toString()
- * toDateString()
- * toTimeString()
- * toLocaleString()
- * toLocaleDateString()
- * toLocaleTimeString()
- * toUTCString()
- * toISOString()
- *
- * Notes:
- *
- * - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
- * required to be the same Ecmascript function object (!), so it is
- * omitted from here.
- *
- * - Date.prototype.toUTCString(): E5.1 specification does not require a
- * specific format, but result should be human readable. The
- * specification suggests using ISO 8601 format with a space (instead
- * of 'T') separator if a more human readable format is not available.
- *
- * - Date.prototype.toISOString(): unlike other conversion functions,
- * toISOString() requires a RangeError for invalid date values.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx) {
- duk_small_uint_t flags = duk__date_get_indirect_magic(ctx);
- return duk__to_string_helper(ctx, flags);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx) {
- /* This native function is also used for Date.prototype.getTime()
- * as their behavior is identical.
- */
-
- duk_double_t d = duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ this ] */
- DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
- duk_push_number(ctx, d);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
- /* Note: toJSON() is a generic function which works even if 'this'
- * is not a Date. The sole argument is ignored.
- */
-
- duk_push_this(ctx);
- duk_to_object(ctx, -1);
-
- duk_dup_top(ctx);
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
- if (duk_is_number(ctx, -1)) {
- duk_double_t d = duk_get_number(ctx, -1);
- if (!DUK_ISFINITE(d)) {
- duk_push_null(ctx);
- return 1;
- }
- }
- duk_pop(ctx);
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
- duk_dup(ctx, -2); /* -> [ O toIsoString O ] */
- duk_call_method(ctx, 0);
- return 1;
-}
-
-/*
- * Getters.
- *
- * Implementing getters is quite easy. The internal time value is either
- * NaN, or represents milliseconds (without fractions) from Jan 1, 1970.
- * The internal time value can be converted to integer parts, and each
- * part will be normalized and will fit into a 32-bit signed integer.
- *
- * A shared native helper to provide all getters. Magic value contains
- * a set of flags and also packs the date component index argument. The
- * helper provides:
- *
- * getFullYear()
- * getUTCFullYear()
- * getMonth()
- * getUTCMonth()
- * getDate()
- * getUTCDate()
- * getDay()
- * getUTCDay()
- * getHours()
- * getUTCHours()
- * getMinutes()
- * getUTCMinutes()
- * getSeconds()
- * getUTCSeconds()
- * getMilliseconds()
- * getUTCMilliseconds()
- * getYear()
- *
- * Notes:
- *
- * - Date.prototype.getDate(): 'date' means day-of-month, and is
- * zero-based in internal calculations but public API expects it to
- * be one-based.
- *
- * - Date.prototype.getTime() and Date.prototype.valueOf() have identical
- * behavior. They have separate function objects, but share the same C
- * function (duk_bi_date_prototype_value_of).
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx) {
- duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(ctx);
- return duk__get_part_helper(ctx, flags_and_idx);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx) {
- /*
- * Return (t - LocalTime(t)) in minutes:
- *
- * t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t))
- * = -(LocalTZA + DaylightSavingTA(t))
- *
- * where DaylightSavingTA() is checked for time 't'.
- *
- * Note that the sign of the result is opposite to common usage,
- * e.g. for EE(S)T which normally is +2h or +3h from UTC, this
- * function returns -120 or -180.
- *
- */
-
- duk_double_t d;
- duk_int_t tzoffset;
-
- /* Note: DST adjustment is determined using UTC time. */
- d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
- DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
- if (DUK_ISNAN(d)) {
- duk_push_nan(ctx);
- } else {
- DUK_ASSERT(DUK_ISFINITE(d));
- tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
- duk_push_int(ctx, -tzoffset / 60);
- }
- return 1;
-}
-
-/*
- * Setters.
- *
- * Setters are a bit more complicated than getters. Component setters
- * break down the current time value into its (normalized) component
- * parts, replace one or more components with -unnormalized- new values,
- * and the components are then converted back into a time value. As an
- * example of using unnormalized values:
- *
- * var d = new Date(1234567890);
- *
- * is equivalent to:
- *
- * var d = new Date(0);
- * d.setUTCMilliseconds(1234567890);
- *
- * A shared native helper to provide almost all setters. Magic value
- * contains a set of flags and also packs the "maxnargs" argument. The
- * helper provides:
- *
- * setMilliseconds()
- * setUTCMilliseconds()
- * setSeconds()
- * setUTCSeconds()
- * setMinutes()
- * setUTCMinutes()
- * setHours()
- * setUTCHours()
- * setDate()
- * setUTCDate()
- * setMonth()
- * setUTCMonth()
- * setFullYear()
- * setUTCFullYear()
- * setYear()
- *
- * Notes:
- *
- * - Date.prototype.setYear() (Section B addition): special year check
- * is omitted. NaN / Infinity will just flow through and ultimately
- * result in a NaN internal time value.
- *
- * - Date.prototype.setYear() does not have optional arguments for
- * setting month and day-in-month (like setFullYear()), but we indicate
- * 'maxnargs' to be 3 to get the year written to the correct component
- * index in duk__set_part_helper(). The function has nargs == 1, so only
- * the year will be set regardless of actual argument count.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx) {
- duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(ctx);
- return duk__set_part_helper(ctx, flags_and_maxnargs);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
- duk_double_t d;
-
- (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval this ] */
- d = duk__timeclip(duk_to_number(ctx, 0));
- duk_push_number(ctx, d);
- duk_dup_top(ctx);
- duk_put_prop_stridx(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
-
- return 1;
-}
-#line 1 "duk_bi_date_unix.c"
-/*
- * Unix-like Date providers
- *
- * Generally useful Unix / POSIX / ANSI Date providers.
- */
-
-/* include removed: duk_internal.h */
-
-/* The necessary #includes are in place in duk_config.h. */
-
-/* Buffer sizes for some UNIX calls. Larger than strictly necessary
- * to avoid Valgrind errors.
- */
-#define DUK__STRPTIME_BUF_SIZE 64
-#define DUK__STRFTIME_BUF_SIZE 64
-
-#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
-/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- struct timeval tv;
- duk_double_t d;
-
- if (gettimeofday(&tv, NULL) != 0) {
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- }
-
- d = ((duk_double_t) tv.tv_sec) * 1000.0 +
- ((duk_double_t) (tv.tv_usec / 1000));
- DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions */
-
- return d;
-}
-#endif /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
-
-#if defined(DUK_USE_DATE_NOW_TIME)
-/* Not a very good provider: only full seconds are available. */
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) {
- time_t t;
-
- DUK_UNREF(ctx);
- t = time(NULL);
- return ((duk_double_t) t) * 1000.0;
-}
-#endif /* DUK_USE_DATE_NOW_TIME */
-
-#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R)
-/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
-DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
- time_t t, t1, t2;
- duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
- duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
- struct tm tms[2];
-#ifdef DUK_USE_DATE_TZO_GMTIME
- struct tm *tm_ptr;
-#endif
-
- /* For NaN/inf, the return value doesn't matter. */
- if (!DUK_ISFINITE(d)) {
- return 0;
- }
-
- /* If not within Ecmascript range, some integer time calculations
- * won't work correctly (and some asserts will fail), so bail out
- * if so. This fixes test-bug-date-insane-setyear.js. There is
- * a +/- 24h leeway in this range check to avoid a test262 corner
- * case documented in test-bug-date-timeval-edges.js.
- */
- if (!duk_bi_date_timeval_in_leeway_range(d)) {
- DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows"));
- return 0;
- }
-
- /*
- * This is a bit tricky to implement portably. The result depends
- * on the timestamp (specifically, DST depends on the timestamp).
- * If e.g. UNIX APIs are used, they'll have portability issues with
- * very small and very large years.
- *
- * Current approach:
- *
- * - Stay within portable UNIX limits by using equivalent year mapping.
- * Avoid year 1970 and 2038 as some conversions start to fail, at
- * least on some platforms. Avoiding 1970 means that there are
- * currently DST discrepancies for 1970.
- *
- * - Create a UTC and local time breakdowns from 't'. Then create
- * a time_t using gmtime() and localtime() and compute the time
- * difference between the two.
- *
- * Equivalent year mapping (E5 Section 15.9.1.8):
- *
- * If the host environment provides functionality for determining
- * daylight saving time, the implementation of ECMAScript is free
- * to map the year in question to an equivalent year (same
- * leap-year-ness and same starting week day for the year) for which
- * the host environment provides daylight saving time information.
- * The only restriction is that all equivalent years should produce
- * the same result.
- *
- * This approach is quite reasonable but not entirely correct, e.g.
- * the specification also states (E5 Section 15.9.1.8):
- *
- * The implementation of ECMAScript should not try to determine
- * whether the exact time was subject to daylight saving time, but
- * just whether daylight saving time would have been in effect if
- * the _current daylight saving time algorithm_ had been used at the
- * time. This avoids complications such as taking into account the
- * years that the locale observed daylight saving time year round.
- *
- * Since we rely on the platform APIs for conversions between local
- * time and UTC, we can't guarantee the above. Rather, if the platform
- * has historical DST rules they will be applied. This seems to be the
- * general preferred direction in Ecmascript standardization (or at least
- * implementations) anyway, and even the equivalent year mapping should
- * be disabled if the platform is known to handle DST properly for the
- * full Ecmascript range.
- *
- * The following has useful discussion and links:
- *
- * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
- */
-
- duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/);
- DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038);
-
- d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
- DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0); /* unsigned 31-bit range */
- t = (time_t) (d / 1000.0);
- DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t));
-
- DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2);
-
-#if defined(DUK_USE_DATE_TZO_GMTIME_R)
- (void) gmtime_r(&t, &tms[0]);
- (void) localtime_r(&t, &tms[1]);
-#elif defined(DUK_USE_DATE_TZO_GMTIME)
- tm_ptr = gmtime(&t);
- DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
- tm_ptr = localtime(&t);
- DUK_MEMCPY((void *) &tms[1], tm_ptr, sizeof(struct tm));
-#else
-#error internal error
-#endif
- DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
- "wday:%ld,yday:%ld,isdst:%ld}",
- (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour,
- (long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year,
- (long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst));
- DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
- "wday:%ld,yday:%ld,isdst:%ld}",
- (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour,
- (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year,
- (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst));
-
- /* tm_isdst is both an input and an output to mktime(), use 0 to
- * avoid DST handling in mktime():
- * - https://github.com/svaarala/duktape/issues/406
- * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
- */
- tms[0].tm_isdst = 0;
- tms[1].tm_isdst = 0;
- t1 = mktime(&tms[0]); /* UTC */
- t2 = mktime(&tms[1]); /* local */
- if (t1 == (time_t) -1 || t2 == (time_t) -1) {
- /* This check used to be for (t < 0) but on some platforms
- * time_t is unsigned and apparently the proper way to detect
- * an mktime() error return is the cast above. See e.g.:
- * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
- */
- goto error;
- }
- DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
-
- /* Compute final offset in seconds, positive if local time ahead of
- * UTC (returned value is UTC-to-local offset).
- *
- * difftime() returns a double, so coercion to int generates quite
- * a lot of code. Direct subtraction is not portable, however.
- * XXX: allow direct subtraction on known platforms.
- */
-#if 0
- return (duk_int_t) (t2 - t1);
-#endif
- return (duk_int_t) difftime(t2, t1);
-
- error:
- /* XXX: return something more useful, so that caller can throw? */
- DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
- return 0;
-}
-#endif /* DUK_USE_DATE_TZO_GMTIME */
-
-#if defined(DUK_USE_DATE_PRS_STRPTIME)
-DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str) {
- struct tm tm;
- time_t t;
- char buf[DUK__STRPTIME_BUF_SIZE];
-
- /* copy to buffer with spare to avoid Valgrind gripes from strptime */
- DUK_ASSERT(str != NULL);
- DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */
- DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
- buf[sizeof(buf) - 1] = (char) 0;
-
- DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
-
- DUK_MEMZERO(&tm, sizeof(tm));
- if (strptime((const char *) buf, "%c", &tm) != NULL) {
- DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
- "wday:%ld,yday:%ld,isdst:%ld}",
- (long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour,
- (long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year,
- (long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst));
- tm.tm_isdst = -1; /* negative: dst info not available */
-
- t = mktime(&tm);
- DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
- if (t >= 0) {
- duk_push_number(ctx, ((duk_double_t) t) * 1000.0);
- return 1;
- }
- }
-
- return 0;
-}
-#endif /* DUK_USE_DATE_PRS_STRPTIME */
-
-#if defined(DUK_USE_DATE_PRS_GETDATE)
-DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str) {
- struct tm tm;
- duk_small_int_t rc;
- time_t t;
-
- /* For this to work, DATEMSK must be set, so this is not very
- * convenient for an embeddable interpreter.
- */
-
- DUK_MEMZERO(&tm, sizeof(struct tm));
- rc = (duk_small_int_t) getdate_r(str, &tm);
- DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
-
- if (rc == 0) {
- t = mktime(&tm);
- DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
- if (t >= 0) {
- duk_push_number(ctx, (duk_double_t) t);
- return 1;
- }
- }
-
- return 0;
-}
-#endif /* DUK_USE_DATE_PRS_GETDATE */
-
-#if defined(DUK_USE_DATE_FMT_STRFTIME)
-DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
- char buf[DUK__STRFTIME_BUF_SIZE];
- struct tm tm;
- const char *fmt;
-
- DUK_UNREF(tzoffset);
-
- /* If the platform doesn't support the entire Ecmascript range, we need
- * to return 0 so that the caller can fall back to the default formatter.
- *
- * For now, assume that if time_t is 8 bytes or more, the whole Ecmascript
- * range is supported. For smaller time_t values (4 bytes in practice),
- * assumes that the signed 32-bit range is supported.
- *
- * XXX: detect this more correctly per platform. The size of time_t is
- * probably not an accurate guarantee of strftime() supporting or not
- * supporting a large time range (the full Ecmascript range).
- */
- if (sizeof(time_t) < 8 &&
- (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
- /* be paranoid for 32-bit time values (even avoiding negative ones) */
- return 0;
- }
-
- DUK_MEMZERO(&tm, sizeof(tm));
- tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
- tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
- tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
- tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */
- tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */
- tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900;
- tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
- tm.tm_isdst = 0;
-
- DUK_MEMZERO(buf, sizeof(buf));
- if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
- fmt = "%c";
- } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
- fmt = "%x";
- } else {
- DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
- fmt = "%X";
- }
- (void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
- DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
-
- duk_push_string(ctx, buf);
- return 1;
-}
-#endif /* DUK_USE_DATE_FMT_STRFTIME */
-
-#undef DUK__STRPTIME_BUF_SIZE
-#undef DUK__STRFTIME_BUF_SIZE
-#line 1 "duk_bi_date_windows.c"
-/*
- * Windows Date providers
- *
- * Platform specific links:
- *
- * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
- */
-
-/* include removed: duk_internal.h */
-
-/* The necessary #includes are in place in duk_config.h. */
-
-#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
-/* Shared Windows helpers. */
-DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
- FILETIME ft;
- if (SystemTimeToFileTime(st, &ft) == 0) {
- DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
- res->QuadPart = 0;
- } else {
- res->LowPart = ft.dwLowDateTime;
- res->HighPart = ft.dwHighDateTime;
- }
-}
-DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
- DUK_MEMZERO((void *) st, sizeof(*st));
- st->wYear = 1970;
- st->wMonth = 1;
- st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
- st->wDay = 1;
- DUK_ASSERT(st->wHour == 0);
- DUK_ASSERT(st->wMinute == 0);
- DUK_ASSERT(st->wSecond == 0);
- DUK_ASSERT(st->wMilliseconds == 0);
-}
-#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
-
-#ifdef DUK_USE_DATE_NOW_WINDOWS
-DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
- /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
- * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
- */
- SYSTEMTIME st1, st2;
- ULARGE_INTEGER tmp1, tmp2;
-
- DUK_UNREF(ctx);
-
- GetSystemTime(&st1);
- duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
-
- duk__set_systime_jan1970(&st2);
- duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
-
- /* Difference is in 100ns units, convert to milliseconds w/o fractions */
- return (duk_double_t) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
-}
-#endif /* DUK_USE_DATE_NOW_WINDOWS */
-
-
-#if defined(DUK_USE_DATE_TZO_WINDOWS)
-DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
- SYSTEMTIME st1;
- SYSTEMTIME st2;
- SYSTEMTIME st3;
- ULARGE_INTEGER tmp1;
- ULARGE_INTEGER tmp2;
- ULARGE_INTEGER tmp3;
- FILETIME ft1;
-
- /* XXX: handling of timestamps outside Windows supported range.
- * How does Windows deal with dates before 1600? Does windows
- * support all Ecmascript years (like -200000 and +200000)?
- * Should equivalent year mapping be used here too? If so, use
- * a shared helper (currently integrated into timeval-to-parts).
- */
-
- /* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
- * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
- */
-
- duk__set_systime_jan1970(&st1);
- duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
- tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */
- tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */
-
- ft1.dwLowDateTime = tmp2.LowPart;
- ft1.dwHighDateTime = tmp2.HighPart;
- FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
- if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
- DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
- return 0;
- }
- duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
-
- /* Positive if local time ahead of UTC. */
- return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */
-}
-#endif /* DUK_USE_DATE_TZO_WINDOWS */
-#line 1 "duk_bi_duktape.c"
-/*
- * Duktape built-ins
- *
- * Size optimization note: it might seem that vararg multipurpose functions
- * like fin(), enc(), and dec() are not very size optimal, but using a single
- * user-visible Ecmascript function saves a lot of run-time footprint; each
- * Function instance takes >100 bytes. Using a shared native helper and a
- * 'magic' value won't save much if there are multiple Function instances
- * anyway.
- */
-
-/* include removed: duk_internal.h */
-
-/* Raw helper to extract internal information / statistics about a value.
- * The return values are version specific and must not expose anything
- * that would lead to security issues (e.g. exposing compiled function
- * 'data' buffer might be an issue). Currently only counts and sizes and
- * such are given so there should not be a security impact.
- */
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv;
- duk_heaphdr *h;
- duk_int_t i, n;
-
- DUK_UNREF(thr);
-
- /* result array */
- duk_push_array(ctx); /* -> [ val arr ] */
-
- /* type tag (public) */
- duk_push_int(ctx, duk_get_type(ctx, 0));
-
- /* address */
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL); /* because arg count is 1 */
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- h = DUK_TVAL_GET_HEAPHDR(tv);
- duk_push_pointer(ctx, (void *) h);
- } else {
- /* internal type tag */
- duk_push_int(ctx, (duk_int_t) DUK_TVAL_GET_TAG(tv));
- goto done;
- }
- DUK_ASSERT(h != NULL);
-
- /* refcount */
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk_push_size_t(ctx, DUK_HEAPHDR_GET_REFCOUNT(h));
-#else
- duk_push_undefined(ctx);
-#endif
-
- /* heaphdr size and additional allocation size, followed by
- * type specific stuff (with varying value count)
- */
- switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
- case DUK_HTYPE_STRING: {
- duk_hstring *h_str = (duk_hstring *) h;
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1));
- break;
- }
- case DUK_HTYPE_OBJECT: {
- duk_hobject *h_obj = (duk_hobject *) h;
- duk_small_uint_t hdr_size;
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hcompiledfunction);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hnativefunction);
- } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
- hdr_size = (duk_small_uint_t) sizeof(duk_hthread);
- } else {
- hdr_size = (duk_small_uint_t) sizeof(duk_hobject);
- }
- duk_push_uint(ctx, (duk_uint_t) hdr_size);
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
- /* Note: e_next indicates the number of gc-reachable entries
- * in the entry part, and also indicates the index where the
- * next new property would be inserted. It does *not* indicate
- * the number of non-NULL keys present in the object. That
- * value could be counted separately but requires a pass through
- * the key list.
- */
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
- duk_push_uint(ctx, (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
- duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, (duk_hcompiledfunction *) h_obj);
- if (h_data) {
- duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_data));
- } else {
- duk_push_uint(ctx, 0);
- }
- }
- break;
- }
- case DUK_HTYPE_BUFFER: {
- duk_hbuffer *h_buf = (duk_hbuffer *) h;
- if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
- if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_external)));
- } else {
- /* When alloc_size == 0 the second allocation may not
- * actually exist.
- */
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_dynamic)));
- }
- duk_push_uint(ctx, (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf)));
- } else {
- duk_push_uint(ctx, (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf) + 1));
- }
- break;
-
- }
- }
-
- done:
- /* set values into ret array */
- /* XXX: primitive to make array from valstack slice */
- n = duk_get_top(ctx);
- for (i = 2; i < n; i++) {
- duk_dup(ctx, i);
- duk_put_prop_index(ctx, 1, i - 2);
- }
- duk_dup(ctx, 1);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_activation *act;
- duk_uint_fast32_t pc;
- duk_uint_fast32_t line;
- duk_int_t level;
-
- /* -1 = top callstack entry, callstack[callstack_top - 1]
- * -callstack_top = bottom callstack entry, callstack[0]
- */
- level = duk_to_int(ctx, 0);
- if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
- return 0;
- }
- DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
- act = thr->callstack + thr->callstack_top + level;
-
- duk_push_object(ctx);
-
- duk_push_tval(ctx, &act->tv_func);
-
- /* Relevant PC is just before current one because PC is
- * post-incremented. This should match what error augment
- * code does.
- */
- pc = duk_hthread_get_act_prev_pc(thr, act);
- duk_push_uint(ctx, (duk_uint_t) pc);
-
-#if defined(DUK_USE_PC2LINE)
- line = duk_hobject_pc2line_query(ctx, -2, pc);
-#else
- line = 0;
-#endif
- duk_push_uint(ctx, (duk_uint_t) line);
-
- /* Providing access to e.g. act->lex_env would be dangerous: these
- * internal structures must never be accessible to the application.
- * Duktape relies on them having consistent data, and this consistency
- * is only asserted for, not checked for.
- */
-
- /* [ level obj func pc line ] */
-
- /* XXX: version specific array format instead? */
- duk_xdef_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER);
- duk_xdef_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_uint_t flags;
- duk_bool_t rc;
-
- flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
- rc = duk_heap_mark_and_sweep(thr->heap, flags);
-
- /* XXX: Not sure what the best return value would be in the API.
- * Return a boolean for now. Note that rc == 0 is success (true).
- */
- duk_push_boolean(ctx, !rc);
- return 1;
-#else
- DUK_UNREF(ctx);
- return 0;
-#endif
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
- (void) duk_require_hobject(ctx, 0);
- if (duk_get_top(ctx) >= 2) {
- /* Set: currently a finalizer is disabled by setting it to
- * undefined; this does not remove the property at the moment.
- * The value could be type checked to be either a function
- * or something else; if something else, the property could
- * be deleted.
- */
- duk_set_top(ctx, 2);
- (void) duk_put_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
- return 0;
- } else {
- /* Get. */
- DUK_ASSERT(duk_get_top(ctx) == 1);
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_FINALIZER);
- return 1;
- }
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_str;
-
- DUK_UNREF(thr);
-
- /* Vararg function: must be careful to check/require arguments.
- * The JSON helpers accept invalid indices and treat them like
- * non-existent optional parameters.
- */
-
- h_str = duk_require_hstring(ctx, 0);
- duk_require_valid_index(ctx, 1);
-
- if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
- duk_set_top(ctx, 2);
- duk_hex_encode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
- } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
- duk_set_top(ctx, 2);
- duk_base64_encode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
-#ifdef DUK_USE_JX
- } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
- duk_bi_json_stringify_helper(ctx,
- 1 /*idx_value*/,
- 2 /*idx_replacer*/,
- 3 /*idx_space*/,
- DUK_JSON_FLAG_EXT_CUSTOM |
- DUK_JSON_FLAG_ASCII_ONLY |
- DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
-#endif
-#ifdef DUK_USE_JC
- } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
- duk_bi_json_stringify_helper(ctx,
- 1 /*idx_value*/,
- 2 /*idx_replacer*/,
- 3 /*idx_space*/,
- DUK_JSON_FLAG_EXT_COMPATIBLE |
- DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
-#endif
- } else {
- return DUK_RET_TYPE_ERROR;
- }
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_str;
-
- DUK_UNREF(thr);
-
- /* Vararg function: must be careful to check/require arguments.
- * The JSON helpers accept invalid indices and treat them like
- * non-existent optional parameters.
- */
-
- h_str = duk_require_hstring(ctx, 0);
- duk_require_valid_index(ctx, 1);
-
- if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
- duk_set_top(ctx, 2);
- duk_hex_decode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
- } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
- duk_set_top(ctx, 2);
- duk_base64_decode(ctx, 1);
- DUK_ASSERT_TOP(ctx, 2);
-#ifdef DUK_USE_JX
- } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
- duk_bi_json_parse_helper(ctx,
- 1 /*idx_value*/,
- 2 /*idx_replacer*/,
- DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
-#endif
-#ifdef DUK_USE_JC
- } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
- duk_bi_json_parse_helper(ctx,
- 1 /*idx_value*/,
- 2 /*idx_replacer*/,
- DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
-#endif
- } else {
- return DUK_RET_TYPE_ERROR;
- }
- return 1;
-}
-
-/*
- * Compact an object
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 1);
- duk_compact(ctx, 0);
- return 1; /* return the argument object */
-}
-#line 1 "duk_bi_error.c"
-/*
- * Error built-ins
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
- /* Behavior for constructor and non-constructor call is
- * the same except for augmenting the created error. When
- * called as a constructor, the caller (duk_new()) will handle
- * augmentation; when called as normal function, we need to do
- * it here.
- */
-
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_int_t bidx_prototype = duk_get_current_magic(ctx);
-
- /* same for both error and each subclass like TypeError */
- duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
-
- DUK_UNREF(thr);
-
- duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
-
- /* If message is undefined, the own property 'message' is not set at
- * all to save property space. An empty message is inherited anyway.
- */
- if (!duk_is_undefined(ctx, 0)) {
- duk_to_string(ctx, 0);
- duk_dup(ctx, 0); /* [ message error message ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
- }
-
- /* Augment the error if called as a normal function. __FILE__ and __LINE__
- * are not desirable in this case.
- */
-
-#ifdef DUK_USE_AUGMENT_ERROR_CREATE
- if (!duk_is_constructor_call(ctx)) {
- duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
- }
-#endif
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
- /* XXX: optimize with more direct internal access */
-
- duk_push_this(ctx);
- (void) duk_require_hobject_or_lfunc_coerce(ctx, -1);
-
- /* [ ... this ] */
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_string(ctx, "Error");
- } else {
- duk_to_string(ctx, -1);
- }
-
- /* [ ... this name ] */
-
- /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
- * accident or are they actually needed? The first ToString()
- * could conceivably return 'undefined'.
- */
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_push_string(ctx, "");
- } else {
- duk_to_string(ctx, -1);
- }
-
- /* [ ... this name message ] */
-
- if (duk_get_length(ctx, -2) == 0) {
- /* name is empty -> return message */
- return 1;
- }
- if (duk_get_length(ctx, -1) == 0) {
- /* message is empty -> return name */
- duk_pop(ctx);
- return 1;
- }
- duk_push_string(ctx, ": ");
- duk_insert(ctx, -2); /* ... name ': ' message */
- duk_concat(ctx, 3);
-
- return 1;
-}
-
-#if defined(DUK_USE_TRACEBACKS)
-
-/*
- * Traceback handling
- *
- * The unified helper decodes the traceback and produces various requested
- * outputs. It should be optimized for size, and may leave garbage on stack,
- * only the topmost return value matters. For instance, traceback separator
- * and decoded strings are pushed even when looking for filename only.
- *
- * NOTE: although _Tracedata is an internal property, user code can currently
- * write to the array (or replace it with something other than an array).
- * The code below must tolerate arbitrary _Tracedata. It can throw errors
- * etc, but cannot cause a segfault or memory unsafe behavior.
- */
-
-/* constants arbitrary, chosen for small loads */
-#define DUK__OUTPUT_TYPE_TRACEBACK (-1)
-#define DUK__OUTPUT_TYPE_FILENAME 0
-#define DUK__OUTPUT_TYPE_LINENUMBER 1
-
-DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t idx_td;
- duk_small_int_t i; /* traceback depth fits into 16 bits */
- duk_small_int_t t; /* stack type fits into 16 bits */
- duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */
- const char *str_tailcall = " tailcall";
- const char *str_strict = " strict";
- const char *str_construct = " construct";
- const char *str_prevyield = " preventsyield";
- const char *str_directeval = " directeval";
- const char *str_empty = "";
-
- DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */
- DUK_UNREF(thr);
-
- duk_push_this(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
- idx_td = duk_get_top_index(ctx);
-
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE);
- duk_push_this(ctx);
-
- /* [ ... this tracedata sep this ] */
-
- /* XXX: skip null filename? */
-
- if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
- /* Current tracedata contains 2 entries per callstack entry. */
- for (i = 0; ; i += 2) {
- duk_int_t pc;
- duk_int_t line;
- duk_int_t flags;
- duk_double_t d;
- const char *funcname;
- const char *filename;
- duk_hobject *h_func;
- duk_hstring *h_name;
-
- duk_require_stack(ctx, 5);
- duk_get_prop_index(ctx, idx_td, i);
- duk_get_prop_index(ctx, idx_td, i + 1);
- d = duk_to_number(ctx, -1);
- pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
- flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
- t = (duk_small_int_t) duk_get_type(ctx, -2);
-
- if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
- /*
- * Ecmascript/native function call or lightfunc call
- */
-
- count_func++;
-
- /* [ ... v1(func) v2(pc+flags) ] */
-
- h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
- duk_get_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME);
-
-#if defined(DUK_USE_PC2LINE)
- line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
-#else
- line = 0;
-#endif
-
- /* [ ... v1 v2 name filename ] */
-
- /* When looking for .fileName/.lineNumber, blame first
- * function which has a .fileName.
- */
- if (duk_is_string(ctx, -1)) {
- if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
- return 1;
- } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, line);
- return 1;
- }
- }
-
- /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
- /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
- h_name = duk_get_hstring(ctx, -2); /* may be NULL */
- funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
- "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
- filename = duk_get_string(ctx, -1);
- filename = filename ? filename : "";
- DUK_ASSERT(funcname != NULL);
- DUK_ASSERT(filename != NULL);
-
- if (h_func == NULL) {
- duk_push_sprintf(ctx, "at %s light%s%s%s%s%s",
- (const char *) funcname,
- (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
- } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h_func)) {
- duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s",
- (const char *) funcname,
- (const char *) filename,
- (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
- } else {
- duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s",
- (const char *) funcname,
- (const char *) filename,
- (long) line,
- (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
- (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
- }
- duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
- duk_pop_n(ctx, 3); /* -> [ ... str ] */
- } else if (t == DUK_TYPE_STRING) {
- /*
- * __FILE__ / __LINE__ entry, here 'pc' is line number directly.
- * Sometimes __FILE__ / __LINE__ is reported as the source for
- * the error (fileName, lineNumber), sometimes not.
- */
-
- /* [ ... v1(filename) v2(line+flags) ] */
-
- /* When looking for .fileName/.lineNumber, blame compilation
- * or C call site unless flagged not to do so.
- */
- if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
- if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
- duk_pop(ctx);
- return 1;
- } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
- duk_push_int(ctx, pc);
- return 1;
- }
- }
-
- duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal",
- (const char *) duk_get_string(ctx, -2), (long) pc);
- duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
- duk_pop(ctx); /* -> [ ... str ] */
- } else {
- /* unknown, ignore */
- duk_pop_2(ctx);
- break;
- }
- }
-
- if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
- /* Possibly truncated; there is no explicit truncation
- * marker so this is the best we can do.
- */
-
- duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
- }
- }
-
- /* [ ... this tracedata sep this str1 ... strN ] */
-
- if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
- return 0;
- } else {
- /* The 'this' after 'sep' will get ToString() coerced by
- * duk_join() automatically. We don't want to do that
- * coercion when providing .fileName or .lineNumber (GH-254).
- */
- duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
- return 1;
- }
-}
-
-/* XXX: Output type could be encoded into native function 'magic' value to
- * save space. For setters the stridx could be encoded into 'magic'.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
-}
-
-#undef DUK__OUTPUT_TYPE_TRACEBACK
-#undef DUK__OUTPUT_TYPE_FILENAME
-#undef DUK__OUTPUT_TYPE_LINENUMBER
-
-#else /* DUK_USE_TRACEBACKS */
-
-/*
- * Traceback handling when tracebacks disabled.
- *
- * The fileName / lineNumber stubs are now necessary because built-in
- * data will include the accessor properties in Error.prototype. If those
- * are removed for builds without tracebacks, these can also be removed.
- * 'stack' should still be present and produce a ToString() equivalent:
- * this is useful for user code which prints a stacktrace and expects to
- * see something useful. A normal stacktrace also begins with a ToString()
- * of the error so this makes sense.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
- /* XXX: remove this native function and map 'stack' accessor
- * to the toString() implementation directly.
- */
- return duk_bi_error_prototype_to_string(ctx);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
- DUK_UNREF(ctx);
- return 0;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
- DUK_UNREF(ctx);
- return 0;
-}
-
-#endif /* DUK_USE_TRACEBACKS */
-
-DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
- /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
- * user code called Object.defineProperty() to create an overriding
- * own property. This allows user code to overwrite .fileName etc
- * intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
- * See https://github.com/svaarala/duktape/issues/387.
- */
-
- DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
-
- duk_push_this(ctx);
- duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
- duk_dup(ctx, 0);
-
- /* [ ... obj key value ] */
-
- DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
- duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
-
- duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
- DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
- DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
- DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
- return 0;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_STACK);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) {
- return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER);
-}
-#line 1 "duk_bi_function.c"
-/*
- * Function built-ins
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_sourcecode;
- duk_idx_t nargs;
- duk_idx_t i;
- duk_small_uint_t comp_flags;
- duk_hcompiledfunction *func;
- duk_hobject *outer_lex_env;
- duk_hobject *outer_var_env;
-
- /* normal and constructor calls have identical semantics */
-
- nargs = duk_get_top(ctx);
- for (i = 0; i < nargs; i++) {
- duk_to_string(ctx, i);
- }
-
- if (nargs == 0) {
- duk_push_string(ctx, "");
- duk_push_string(ctx, "");
- } else if (nargs == 1) {
- /* XXX: cover this with the generic >1 case? */
- duk_push_string(ctx, "");
- } else {
- duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
- duk_push_string(ctx, ",");
- duk_insert(ctx, 1);
- duk_join(ctx, nargs - 1);
- }
-
- /* [ body formals ], formals is comma separated list that needs to be parsed */
-
- DUK_ASSERT_TOP(ctx, 2);
-
- /* XXX: this placeholder is not always correct, but use for now.
- * It will fail in corner cases; see test-dev-func-cons-args.js.
- */
- duk_push_string(ctx, "function(");
- duk_dup(ctx, 1);
- duk_push_string(ctx, "){");
- duk_dup(ctx, 0);
- duk_push_string(ctx, "}");
- duk_concat(ctx, 5);
-
- /* [ body formals source ] */
-
- DUK_ASSERT_TOP(ctx, 3);
-
- /* strictness is not inherited, intentional */
- comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
-
- duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
- h_sourcecode = duk_require_hstring(ctx, -2);
- duk_js_compile(thr,
- (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
- (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
- comp_flags);
- func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
-
- /* [ body formals source template ] */
-
- /* only outer_lex_env matters, as functions always get a new
- * variable declaration environment.
- */
-
- outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
-
- duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/);
-
- /* [ body formals source template closure ] */
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
- /* ignore arguments, return undefined (E5 Section 15.3.4) */
- DUK_UNREF(ctx);
- return 0;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
- duk_tval *tv;
-
- /*
- * E5 Section 15.3.4.2 places few requirements on the output of
- * this function:
- *
- * - The result is an implementation dependent representation
- * of the function; in particular
- *
- * - The result must follow the syntax of a FunctionDeclaration.
- * In particular, the function must have a name (even in the
- * case of an anonymous function or a function with an empty
- * name).
- *
- * - Note in particular that the output does NOT need to compile
- * into anything useful.
- */
-
-
- /* XXX: faster internal way to get this */
- duk_push_this(ctx);
- tv = duk_get_tval(ctx, -1);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
- const char *func_name;
-
- /* Function name: missing/undefined is mapped to empty string,
- * otherwise coerce to string.
- */
- /* XXX: currently no handling for non-allowed identifier characters,
- * e.g. a '{' in the function name.
- */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME);
- if (duk_is_undefined(ctx, -1)) {
- func_name = "";
- } else {
- func_name = duk_to_string(ctx, -1);
- DUK_ASSERT(func_name != NULL);
- }
-
- /* Indicate function type in the function body using a dummy
- * directive.
- */
- if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"ecmascript\"}", (const char *) func_name);
- } else if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"native\"}", (const char *) func_name);
- } else if (DUK_HOBJECT_HAS_BOUND(obj)) {
- duk_push_sprintf(ctx, "function %s() {\"bound\"}", (const char *) func_name);
- } else {
- goto type_error;
- }
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
- duk_push_lightfunc_tostring(ctx, tv);
- } else {
- goto type_error;
- }
-
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
- duk_idx_t len;
- duk_idx_t i;
-
- DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */
-
- duk_push_this(ctx);
- if (!duk_is_callable(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("func is not callable"));
- goto type_error;
- }
- duk_insert(ctx, 0);
- DUK_ASSERT_TOP(ctx, 3);
-
- DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
-
- /* [ func thisArg argArray ] */
-
- if (duk_is_null_or_undefined(ctx, 2)) {
- DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
- len = 0;
- } else if (!duk_is_object(ctx, 2)) {
- goto type_error;
- } else {
- DUK_DDD(DUK_DDDPRINT("argArray is an object"));
-
- /* XXX: make this an internal helper */
- duk_get_prop_stridx(ctx, 2, DUK_STRIDX_LENGTH);
- len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */
- duk_pop(ctx);
-
- duk_require_stack(ctx, len);
-
- DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
- for (i = 0; i < len; i++) {
- duk_get_prop_index(ctx, 2, i);
- }
- }
- duk_remove(ctx, 2);
- DUK_ASSERT_TOP(ctx, 2 + len);
-
- /* [ func thisArg arg1 ... argN ] */
-
- DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (long) len));
- duk_call_method(ctx, len);
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
- duk_idx_t nargs;
-
- /* Step 1 is not necessary because duk_call_method() will take
- * care of it.
- */
-
- /* vararg function, thisArg needs special handling */
- nargs = duk_get_top(ctx); /* = 1 + arg count */
- if (nargs == 0) {
- duk_push_undefined(ctx);
- nargs++;
- }
- DUK_ASSERT(nargs >= 1);
-
- /* [ thisArg arg1 ... argN ] */
-
- duk_push_this(ctx); /* 'func' in the algorithm */
- duk_insert(ctx, 0);
-
- /* [ func thisArg arg1 ... argN ] */
-
- DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (long) (nargs - 1),
- (long) duk_get_top(ctx)));
- duk_call_method(ctx, nargs - 1);
- return 1;
-}
-
-/* XXX: the implementation now assumes "chained" bound functions,
- * whereas "collapsed" bound functions (where there is ever only
- * one bound function which directly points to a non-bound, final
- * function) would require a "collapsing" implementation which
- * merges argument lists etc here.
- */
-DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
- duk_hobject *h_bound;
- duk_hobject *h_target;
- duk_idx_t nargs;
- duk_idx_t i;
-
- /* vararg function, careful arg handling (e.g. thisArg may not be present) */
- nargs = duk_get_top(ctx); /* = 1 + arg count */
- if (nargs == 0) {
- duk_push_undefined(ctx);
- nargs++;
- }
- DUK_ASSERT(nargs >= 1);
-
- duk_push_this(ctx);
- if (!duk_is_callable(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("func is not callable"));
- goto type_error;
- }
-
- /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
- DUK_ASSERT_TOP(ctx, nargs + 1);
-
- /* create bound function object */
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_BOUND |
- DUK_HOBJECT_FLAG_CONSTRUCTABLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
- DUK_BIDX_FUNCTION_PROTOTYPE);
- h_bound = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_bound != NULL);
-
- /* [ thisArg arg1 ... argN func boundFunc ] */
- duk_dup(ctx, -2); /* func */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
-
- duk_dup(ctx, 0); /* thisArg */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
-
- duk_push_array(ctx);
-
- /* [ thisArg arg1 ... argN func boundFunc argArray ] */
-
- for (i = 0; i < nargs - 1; i++) {
- duk_dup(ctx, 1 + i);
- duk_put_prop_index(ctx, -2, i);
- }
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
-
- /* [ thisArg arg1 ... argN func boundFunc ] */
-
- /* bound function 'length' property is interesting */
- h_target = duk_get_hobject(ctx, -2);
- if (h_target == NULL || /* lightfunc */
- DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
- /* For lightfuncs, simply read the virtual property. */
- duk_int_t tmp;
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH);
- tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */
- duk_pop(ctx);
- duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
- } else {
- duk_push_int(ctx, 0);
- }
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE); /* attrs in E5 Section 15.3.5.1 */
-
- /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
- duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
-
- /* these non-standard properties are copied for convenience */
- /* XXX: 'copy properties' API call? */
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_WC);
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC);
-
- /* The 'strict' flag is copied to get the special [[Get]] of E5.1
- * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
- * function. Not sure if this is correct, because the specification
- * is a bit ambiguous on this point but it would make sense.
- */
- if (h_target == NULL) {
- /* Lightfuncs are always strict. */
- DUK_HOBJECT_SET_STRICT(h_bound);
- } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
- DUK_HOBJECT_SET_STRICT(h_bound);
- }
- DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
-
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-#line 1 "duk_bi_global.c"
-/*
- * Global object built-ins
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Encoding/decoding helpers
- */
-
-/* XXX: Could add fast path (for each transform callback) with direct byte
- * lookups (no shifting) and no explicit check for x < 0x80 before table
- * lookup.
- */
-
-/* Macros for creating and checking bitmasks for character encoding.
- * Bit number is a bit counterintuitive, but minimizes code size.
- */
-#define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \
- ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
- ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \
- ))
-#define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07)))
-
-/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
-DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = {
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
- DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
- DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
-};
-
-/* E5.1 Section 15.1.3.4: uriUnescaped */
-DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = {
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
- DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
- DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
- DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
-};
-
-/* E5.1 Section 15.1.3.1: uriReserved + '#' */
-DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = {
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
- DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
- DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
-};
-
-/* E5.1 Section 15.1.3.2: empty */
-DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
-};
-
-#ifdef DUK_USE_SECTION_B
-/* E5.1 Section B.2.2, step 7. */
-DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
- DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
- DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
- DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */
-};
-#endif /* DUK_USE_SECTION_B */
-
-#undef DUK__MKBITS
-
-typedef struct {
- duk_hthread *thr;
- duk_hstring *h_str;
- duk_bufwriter_ctx bw;
- const duk_uint8_t *p;
- const duk_uint8_t *p_start;
- const duk_uint8_t *p_end;
-} duk__transform_context;
-
-typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp);
-
-/* XXX: refactor and share with other code */
-DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) {
- duk_small_int_t ch;
- duk_small_int_t t = 0;
-
- while (n > 0) {
- t = t * 16;
- ch = (duk_small_int_t) duk_hex_dectab[*p++];
- if (DUK_LIKELY(ch >= 0)) {
- t += ch;
- } else {
- return -1;
- }
- n--;
- }
- return t;
-}
-
-DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk__transform_context tfm_ctx_alloc;
- duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
- duk_codepoint_t cp;
-
- tfm_ctx->thr = thr;
-
- tfm_ctx->h_str = duk_to_hstring(ctx, 0);
- DUK_ASSERT(tfm_ctx->h_str != NULL);
-
- DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
-
- tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str);
- tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str);
- tfm_ctx->p = tfm_ctx->p_start;
-
- while (tfm_ctx->p < tfm_ctx->p_end) {
- cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end);
- callback(tfm_ctx, udata, cp);
- }
-
- DUK_BW_COMPACT(thr, &tfm_ctx->bw);
-
- duk_to_string(ctx, -1);
- return 1;
-}
-
-DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
- duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
- duk_small_int_t len;
- duk_codepoint_t cp1, cp2;
- duk_small_int_t i, t;
- const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata;
-
- /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
- * Codepoint range is restricted so this is a slightly too large
- * but doesn't matter.
- */
- DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH);
-
- if (cp < 0) {
- goto uri_error;
- } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) {
- DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
- return;
- } else if (cp >= 0xdc00L && cp <= 0xdfffL) {
- goto uri_error;
- } else if (cp >= 0xd800L && cp <= 0xdbffL) {
- /* Needs lookahead */
- if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) {
- goto uri_error;
- }
- if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) {
- goto uri_error;
- }
- cp1 = cp;
- cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L;
- } else if (cp > 0x10ffffL) {
- /* Although we can allow non-BMP characters (they'll decode
- * back into surrogate pairs), we don't allow extended UTF-8
- * characters; they would encode to URIs which won't decode
- * back because of strict UTF-8 checks in URI decoding.
- * (However, we could just as well allow them here.)
- */
- goto uri_error;
- } else {
- /* Non-BMP characters within valid UTF-8 range: encode as is.
- * They'll decode back into surrogate pairs if the escaped
- * output is decoded.
- */
- ;
- }
-
- len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
- for (i = 0; i < len; i++) {
- t = (int) xutf8_buf[i];
- DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
- &tfm_ctx->bw,
- DUK_ASC_PERCENT,
- (duk_uint8_t) duk_uc_nybbles[t >> 4],
- (duk_uint8_t) duk_uc_nybbles[t & 0x0f]);
- }
-
- return;
-
- uri_error:
- DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
-}
-
-DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
- const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata;
- duk_small_uint_t utf8_blen;
- duk_codepoint_t min_cp;
- duk_small_int_t t; /* must be signed */
- duk_small_uint_t i;
-
- /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH,
- * percent escape path writes max two times CESU-8 encoded BMP length.
- */
- DUK_BW_ENSURE(tfm_ctx->thr,
- &tfm_ctx->bw,
- (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ?
- DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH));
-
- if (cp == (duk_codepoint_t) '%') {
- const duk_uint8_t *p = tfm_ctx->p;
- duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
-
- DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left));
-
- if (left < 2) {
- goto uri_error;
- }
-
- t = duk__decode_hex_escape(p, 2);
- DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t));
- if (t < 0) {
- goto uri_error;
- }
-
- if (t < 0x80) {
- if (DUK__CHECK_BITMASK(reserved_table, t)) {
- /* decode '%xx' to '%xx' if decoded char in reserved set */
- DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start);
- DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
- &tfm_ctx->bw,
- DUK_ASC_PERCENT,
- p[0],
- p[1]);
- } else {
- DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t);
- }
- tfm_ctx->p += 2;
- return;
- }
-
- /* Decode UTF-8 codepoint from a sequence of hex escapes. The
- * first byte of the sequence has been decoded to 't'.
- *
- * Note that UTF-8 validation must be strict according to the
- * specification: E5.1 Section 15.1.3, decode algorithm step
- * 4.d.vii.8. URIError from non-shortest encodings is also
- * specifically noted in the spec.
- */
-
- DUK_ASSERT(t >= 0x80);
- if (t < 0xc0) {
- /* continuation byte */
- goto uri_error;
- } else if (t < 0xe0) {
- /* 110x xxxx; 2 bytes */
- utf8_blen = 2;
- min_cp = 0x80L;
- cp = t & 0x1f;
- } else if (t < 0xf0) {
- /* 1110 xxxx; 3 bytes */
- utf8_blen = 3;
- min_cp = 0x800L;
- cp = t & 0x0f;
- } else if (t < 0xf8) {
- /* 1111 0xxx; 4 bytes */
- utf8_blen = 4;
- min_cp = 0x10000L;
- cp = t & 0x07;
- } else {
- /* extended utf-8 not allowed for URIs */
- goto uri_error;
- }
-
- if (left < utf8_blen * 3 - 1) {
- /* '%xx%xx...%xx', p points to char after first '%' */
- goto uri_error;
- }
-
- p += 3;
- for (i = 1; i < utf8_blen; i++) {
- /* p points to digit part ('%xy', p points to 'x') */
- t = duk__decode_hex_escape(p, 2);
- DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx",
- (long) i, (long) utf8_blen, (long) cp, (unsigned long) t));
- if (t < 0) {
- goto uri_error;
- }
- if ((t & 0xc0) != 0x80) {
- goto uri_error;
- }
- cp = (cp << 6) + (t & 0x3f);
- p += 3;
- }
- p--; /* p overshoots */
- tfm_ctx->p = p;
-
- DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp, (long) min_cp));
-
- if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) {
- goto uri_error;
- }
-
- /* The E5.1 algorithm checks whether or not a decoded codepoint
- * is below 0x80 and perhaps may be in the "reserved" set.
- * This seems pointless because the single byte UTF-8 case is
- * handled separately, and non-shortest encodings are rejected.
- * So, 'cp' cannot be below 0x80 here, and thus cannot be in
- * the reserved set.
- */
-
- /* utf-8 validation ensures these */
- DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL);
-
- if (cp >= 0x10000L) {
- cp -= 0x10000L;
- DUK_ASSERT(cp < 0x100000L);
-
- DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
- DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffUL) + 0xdc00L));
- } else {
- DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
- }
- } else {
- DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
- }
- return;
-
- uri_error:
- DUK_ERROR(tfm_ctx->thr, DUK_ERR_URI_ERROR, "invalid input");
-}
-
-#ifdef DUK_USE_SECTION_B
-DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
- DUK_UNREF(udata);
-
- DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6);
-
- if (cp < 0) {
- goto esc_error;
- } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) {
- DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
- } else if (cp < 0x100L) {
- DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
- &tfm_ctx->bw,
- (duk_uint8_t) DUK_ASC_PERCENT,
- (duk_uint8_t) duk_uc_nybbles[cp >> 4],
- (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
- } else if (cp < 0x10000L) {
- DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr,
- &tfm_ctx->bw,
- (duk_uint8_t) DUK_ASC_PERCENT,
- (duk_uint8_t) DUK_ASC_LC_U,
- (duk_uint8_t) duk_uc_nybbles[cp >> 12],
- (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f],
- (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f],
- (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
- } else {
- /* Characters outside BMP cannot be escape()'d. We could
- * encode them as surrogate pairs (for codepoints inside
- * valid UTF-8 range, but not extended UTF-8). Because
- * escape() and unescape() are legacy functions, we don't.
- */
- goto esc_error;
- }
-
- return;
-
- esc_error:
- DUK_ERROR_TYPE(tfm_ctx->thr, "invalid input");
-}
-
-DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
- duk_small_int_t t;
-
- DUK_UNREF(udata);
-
- if (cp == (duk_codepoint_t) '%') {
- const duk_uint8_t *p = tfm_ctx->p;
- duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
-
- if (left >= 5 && p[0] == 'u' &&
- ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) {
- cp = (duk_codepoint_t) t;
- tfm_ctx->p += 5;
- } else if (left >= 2 &&
- ((t = duk__decode_hex_escape(p, 2)) >= 0)) {
- cp = (duk_codepoint_t) t;
- tfm_ctx->p += 2;
- }
- }
-
- DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
-}
-#endif /* DUK_USE_SECTION_B */
-
-/*
- * Eval
- *
- * Eval needs to handle both a "direct eval" and an "indirect eval".
- * Direct eval handling needs access to the caller's activation so that its
- * lexical environment can be accessed. A direct eval is only possible from
- * Ecmascript code; an indirect eval call is possible also from C code.
- * When an indirect eval call is made from C code, there may not be a
- * calling activation at all which needs careful handling.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h;
- duk_activation *act_caller;
- duk_activation *act_eval;
- duk_activation *act;
- duk_hcompiledfunction *func;
- duk_hobject *outer_lex_env;
- duk_hobject *outer_var_env;
- duk_bool_t this_to_global = 1;
- duk_small_uint_t comp_flags;
- duk_int_t level = -2;
-
- 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 */
-
- /*
- * callstack_top - 1 --> this function
- * callstack_top - 2 --> caller (may not exist)
- *
- * If called directly from C, callstack_top might be 1. If calling
- * activation doesn't exist, call must be indirect.
- */
-
- h = duk_get_hstring(ctx, 0);
- if (!h) {
- return 1; /* return arg as-is */
- }
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- /* NOTE: level is used only by the debugger and should never be present
- * for an Ecmascript eval().
- */
- DUK_ASSERT(level == -2); /* by default, use caller's environment */
- if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) {
- level = duk_get_int(ctx, 1);
- }
- DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
-#endif
-
- /* [ source ] */
-
- comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
- act_eval = thr->callstack + thr->callstack_top - 1; /* this function */
- if (thr->callstack_top >= (duk_size_t) -level) {
- /* Have a calling activation, check for direct eval (otherwise
- * assume indirect eval.
- */
- act_caller = thr->callstack + thr->callstack_top + level; /* caller */
- if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
- (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
- /* Only direct eval inherits strictness from calling code
- * (E5.1 Section 10.1.1).
- */
- comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
- }
- } else {
- DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
- }
- act_caller = NULL; /* avoid dereference after potential callstack realloc */
- act_eval = NULL;
-
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
- duk_js_compile(thr,
- (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
- (duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
- comp_flags);
- func = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) func));
-
- /* [ source template ] */
-
- /* E5 Section 10.4.2 */
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1; /* this function */
- if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
- DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top + level; /* caller */
- if (act->lex_env == NULL) {
- DUK_ASSERT(act->var_env == NULL);
- DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
-
- /* this may have side effects, so re-lookup act */
- duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack + thr->callstack_top + level;
- }
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
-
- this_to_global = 0;
-
- if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
- duk_hobject *new_env;
- duk_hobject *act_lex_env;
-
- DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
- "var_env and lex_env to a fresh env, "
- "this_binding to caller's this_binding"));
-
- act = thr->callstack + thr->callstack_top + level; /* caller */
- act_lex_env = act->lex_env;
- act = NULL; /* invalidated */
-
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- act_lex_env);
- new_env = duk_require_hobject(ctx, -1);
- DUK_ASSERT(new_env != NULL);
- DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO",
- (duk_heaphdr *) new_env));
-
- outer_lex_env = new_env;
- outer_var_env = new_env;
-
- duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
-
- /* compiler's responsibility */
- DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
- } else {
- DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> "
- "var_env and lex_env to caller's envs, "
- "this_binding to caller's this_binding"));
-
- outer_lex_env = act->lex_env;
- outer_var_env = act->var_env;
-
- /* compiler's responsibility */
- DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
- }
- } else {
- DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
- "global object, this_binding to global object"));
-
- this_to_global = 1;
- outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- }
- act = NULL;
-
- /* Eval code doesn't need an automatic .prototype object. */
- duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
-
- /* [ source template closure ] */
-
- if (this_to_global) {
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
- duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
- } else {
- duk_tval *tv;
- DUK_ASSERT(thr->callstack_top >= 2);
- act = thr->callstack + thr->callstack_top + level; /* caller */
- tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */
- DUK_ASSERT(tv >= thr->valstack);
- duk_push_tval(ctx, tv);
- }
-
- DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
- (duk_heaphdr *) outer_lex_env,
- (duk_heaphdr *) outer_var_env,
- duk_get_tval(ctx, -1)));
-
- /* [ source template closure this ] */
-
- duk_call_method(ctx, 0);
-
- /* [ source template result ] */
-
- return 1;
-}
-
-/*
- * Parsing of ints and floats
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
- duk_int32_t radix;
- duk_small_uint_t s2n_flags;
-
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, 0);
-
- radix = duk_to_int32(ctx, 1);
-
- s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
- DUK_S2N_FLAG_ALLOW_GARBAGE |
- DUK_S2N_FLAG_ALLOW_PLUS |
- DUK_S2N_FLAG_ALLOW_MINUS |
- DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
- DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
-
- /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT.
- *
- * Don't autodetect octals (from leading zeroes), require user code to
- * provide an explicit radix 8 for parsing octal. See write-up from Mozilla:
- * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation
- */
-
- if (radix != 0) {
- if (radix < 2 || radix > 36) {
- goto ret_nan;
- }
- if (radix != 16) {
- s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
- }
- } else {
- radix = 10;
- }
-
- duk_dup(ctx, 0);
- duk_numconv_parse(ctx, radix, s2n_flags);
- return 1;
-
- ret_nan:
- duk_push_nan(ctx);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
- duk_small_uint_t s2n_flags;
- duk_int32_t radix;
-
- DUK_ASSERT_TOP(ctx, 1);
- duk_to_string(ctx, 0);
-
- radix = 10;
-
- /* XXX: check flags */
- s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
- DUK_S2N_FLAG_ALLOW_EXP |
- DUK_S2N_FLAG_ALLOW_GARBAGE |
- DUK_S2N_FLAG_ALLOW_PLUS |
- DUK_S2N_FLAG_ALLOW_MINUS |
- DUK_S2N_FLAG_ALLOW_INF |
- DUK_S2N_FLAG_ALLOW_FRAC |
- DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
- DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
- DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
-
- duk_numconv_parse(ctx, radix, s2n_flags);
- return 1;
-}
-
-/*
- * Number checkers
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) {
- duk_double_t d = duk_to_number(ctx, 0);
- duk_push_boolean(ctx, DUK_ISNAN(d));
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
- duk_double_t d = duk_to_number(ctx, 0);
- duk_push_boolean(ctx, DUK_ISFINITE(d));
- return 1;
-}
-
-/*
- * URI handling
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
-}
-
-#ifdef DUK_USE_SECTION_B
-DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
- return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL);
-}
-#else /* DUK_USE_SECTION_B */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_SECTION_B */
-
-#if defined(DUK_USE_BROWSER_LIKE) && (defined(DUK_USE_FILE_IO) || defined(DUK_USE_DEBUGGER_SUPPORT))
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_int_t magic;
- duk_idx_t nargs;
- const duk_uint8_t *buf;
- duk_size_t sz_buf;
- const char nl = (const char) DUK_ASC_LF;
-#ifndef DUK_USE_PREFER_SIZE
- duk_uint8_t buf_stack[256];
-#endif
-#ifdef DUK_USE_FILE_IO
- duk_file *f_out;
-#endif
-
- DUK_UNREF(thr);
-
- magic = duk_get_current_magic(ctx);
- DUK_UNREF(magic);
-
- nargs = duk_get_top(ctx);
-
- /* If argument count is 1 and first argument is a buffer, write the buffer
- * as raw data into the file without a newline; this allows exact control
- * over stdout/stderr without an additional entrypoint (useful for now).
- *
- * Otherwise current print/alert semantics are to ToString() coerce
- * arguments, join them with a single space, and append a newline.
- */
-
- if (nargs == 1 && duk_is_buffer(ctx, 0)) {
- buf = (const duk_uint8_t *) duk_get_buffer(ctx, 0, &sz_buf);
- DUK_ASSERT(buf != NULL);
- } else if (nargs > 0) {
-#ifdef DUK_USE_PREFER_SIZE
- /* Compact but lots of churn. */
- duk_push_hstring_stridx(thr, DUK_STRIDX_SPACE);
- duk_insert(ctx, 0);
- duk_join(ctx, nargs);
- duk_push_string(thr, "\n");
- duk_concat(ctx, 2);
- buf = (const duk_uint8_t *) duk_get_lstring(ctx, -1, &sz_buf);
- DUK_ASSERT(buf != NULL);
-#else /* DUK_USE_PREFER_SIZE */
- /* Higher footprint, less churn. */
- duk_idx_t i;
- duk_size_t sz_str;
- const duk_uint8_t *p_str;
- duk_uint8_t *p;
-
- sz_buf = (duk_size_t) nargs; /* spaces (nargs - 1) + newline */
- for (i = 0; i < nargs; i++) {
- (void) duk_to_lstring(ctx, i, &sz_str);
- sz_buf += sz_str;
- }
-
- if (sz_buf <= sizeof(buf_stack)) {
- p = (duk_uint8_t *) buf_stack;
- } else {
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sz_buf);
- DUK_ASSERT(p != NULL);
- }
-
- buf = (const duk_uint8_t *) p;
- for (i = 0; i < nargs; i++) {
- p_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &sz_str);
- DUK_ASSERT(p_str != NULL);
- DUK_MEMCPY((void *) p, (const void *) p_str, sz_str);
- p += sz_str;
- *p++ = (duk_uint8_t) (i == nargs - 1 ? DUK_ASC_LF : DUK_ASC_SPACE);
- }
- DUK_ASSERT((const duk_uint8_t *) p == buf + sz_buf);
-#endif /* DUK_USE_PREFER_SIZE */
- } else {
- buf = (const duk_uint8_t *) &nl;
- sz_buf = 1;
- }
-
- /* 'buf' contains the string to write, 'sz_buf' contains the length
- * (which may be zero).
- */
- DUK_ASSERT(buf != NULL);
-
- if (sz_buf == 0) {
- return 0;
- }
-
-#ifdef DUK_USE_FILE_IO
- f_out = (magic ? DUK_STDERR : DUK_STDOUT);
- DUK_FWRITE((const void *) buf, 1, (size_t) sz_buf, f_out);
- DUK_FFLUSH(f_out);
-#endif
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_PRINTALERT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- duk_debug_write_notify(thr, magic ? DUK_DBG_CMD_ALERT : DUK_DBG_CMD_PRINT);
- duk_debug_write_string(thr, (const char *) buf, sz_buf);
- duk_debug_write_eom(thr);
- }
-#endif
- return 0;
-}
-#elif defined(DUK_USE_BROWSER_LIKE) /* print provider */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- DUK_UNREF(ctx);
- return 0;
-}
-#else /* print provider */
-DUK_INTERNAL duk_ret_t duk_bi_global_object_print_helper(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* print provider */
-
-/*
- * CommonJS require() and modules support
- */
-
-#if defined(DUK_USE_COMMONJS_MODULES)
-DUK_LOCAL void duk__bi_global_resolve_module_id(duk_context *ctx, const char *req_id, const char *mod_id) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uint8_t buf[DUK_BI_COMMONJS_MODULE_ID_LIMIT];
- duk_uint8_t *p;
- duk_uint8_t *q;
- duk_uint8_t *q_last; /* last component */
- duk_int_t int_rc;
-
- DUK_ASSERT(req_id != NULL);
- /* mod_id may be NULL */
-
- /*
- * A few notes on the algorithm:
- *
- * - Terms are not allowed to begin with a period unless the term
- * is either '.' or '..'. This simplifies implementation (and
- * is within CommonJS modules specification).
- *
- * - There are few output bound checks here. This is on purpose:
- * the resolution input is length checked and the output is never
- * longer than the input. The resolved output is written directly
- * over the input because it's never longer than the input at any
- * point in the algorithm.
- *
- * - Non-ASCII characters are processed as individual bytes and
- * need no special treatment. However, U+0000 terminates the
- * algorithm; this is not an issue because U+0000 is not a
- * desirable term character anyway.
- */
-
- /*
- * Set up the resolution input which is the requested ID directly
- * (if absolute or no current module path) or with current module
- * ID prepended (if relative and current module path exists).
- *
- * Suppose current module is 'foo/bar' and relative path is './quux'.
- * The 'bar' component must be replaced so the initial input here is
- * 'foo/bar/.././quux'.
- */
-
- if (mod_id != NULL && req_id[0] == '.') {
- int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s/../%s", mod_id, req_id);
- } else {
- int_rc = DUK_SNPRINTF((char *) buf, sizeof(buf), "%s", req_id);
- }
- if (int_rc >= (duk_int_t) sizeof(buf) || int_rc < 0) {
- /* Potentially truncated, NUL not guaranteed in any case.
- * The (int_rc < 0) case should not occur in practice.
- */
- DUK_DD(DUK_DDPRINT("resolve error: temporary working module ID doesn't fit into resolve buffer"));
- goto resolve_error;
- }
- DUK_ASSERT(DUK_STRLEN((const char *) buf) < sizeof(buf)); /* at most sizeof(buf) - 1 */
-
- DUK_DDD(DUK_DDDPRINT("input module id: '%s'", (const char *) buf));
-
- /*
- * Resolution loop. At the top of the loop we're expecting a valid
- * term: '.', '..', or a non-empty identifier not starting with a period.
- */
-
- p = buf;
- q = buf;
- for (;;) {
- duk_uint_fast8_t c;
-
- /* Here 'p' always points to the start of a term.
- *
- * We can also unconditionally reset q_last here: if this is
- * the last (non-empty) term q_last will have the right value
- * on loop exit.
- */
-
- DUK_ASSERT(p >= q); /* output is never longer than input during resolution */
-
- DUK_DDD(DUK_DDDPRINT("resolve loop top: p -> '%s', q=%p, buf=%p",
- (const char *) p, (void *) q, (void *) buf));
-
- q_last = q;
-
- c = *p++;
- if (DUK_UNLIKELY(c == 0)) {
- DUK_DD(DUK_DDPRINT("resolve error: requested ID must end with a non-empty term"));
- goto resolve_error;
- } else if (DUK_UNLIKELY(c == '.')) {
- c = *p++;
- if (c == '/') {
- /* Term was '.' and is eaten entirely (including dup slashes). */
- goto eat_dup_slashes;
- }
- if (c == '.' && *p == '/') {
- /* Term was '..', backtrack resolved name by one component.
- * q[-1] = previous slash (or beyond start of buffer)
- * q[-2] = last char of previous component (or beyond start of buffer)
- */
- p++; /* eat (first) input slash */
- DUK_ASSERT(q >= buf);
- if (q == buf) {
- DUK_DD(DUK_DDPRINT("resolve error: term was '..' but nothing to backtrack"));
- goto resolve_error;
- }
- DUK_ASSERT(*(q - 1) == '/');
- q--; /* backtrack to last output slash (dups already eliminated) */
- for (;;) {
- /* Backtrack to previous slash or start of buffer. */
- DUK_ASSERT(q >= buf);
- if (q == buf) {
- break;
- }
- if (*(q - 1) == '/') {
- break;
- }
- q--;
- }
- goto eat_dup_slashes;
- }
- DUK_DD(DUK_DDPRINT("resolve error: term begins with '.' but is not '.' or '..' (not allowed now)"));
- goto resolve_error;
- } else if (DUK_UNLIKELY(c == '/')) {
- /* e.g. require('/foo'), empty terms not allowed */
- DUK_DD(DUK_DDPRINT("resolve error: empty term (not allowed now)"));
- goto resolve_error;
- } else {
- for (;;) {
- /* Copy term name until end or '/'. */
- *q++ = c;
- c = *p++;
- if (DUK_UNLIKELY(c == 0)) {
- /* This was the last term, and q_last was
- * updated to match this term at loop top.
- */
- goto loop_done;
- } else if (DUK_UNLIKELY(c == '/')) {
- *q++ = '/';
- break;
- } else {
- /* write on next loop */
- }
- }
- }
-
- eat_dup_slashes:
- for (;;) {
- /* eat dup slashes */
- c = *p;
- if (DUK_LIKELY(c != '/')) {
- break;
- }
- p++;
- }
- }
- loop_done:
- /* Output #1: resolved absolute name */
- DUK_ASSERT(q >= buf);
- duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
-
- /* Output #2: last component name */
- DUK_ASSERT(q >= q_last);
- DUK_ASSERT(q_last >= buf);
- duk_push_lstring(ctx, (const char *) q_last, (size_t) (q - q_last));
-
- DUK_DD(DUK_DDPRINT("after resolving module name: buf=%p, q_last=%p, q=%p",
- (void *) buf, (void *) q_last, (void *) q));
- return;
-
- resolve_error:
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "cannot resolve module id: %s", (const char *) req_id);
-}
-#endif /* DUK_USE_COMMONJS_MODULES */
-
-#if defined(DUK_USE_COMMONJS_MODULES)
-/* Stack indices for better readability */
-#define DUK__IDX_REQUESTED_ID 0 /* Module id requested */
-#define DUK__IDX_REQUIRE 1 /* Current require() function */
-#define DUK__IDX_REQUIRE_ID 2 /* The base ID of the current require() function, resolution base */
-#define DUK__IDX_RESOLVED_ID 3 /* Resolved, normalized absolute module ID */
-#define DUK__IDX_LASTCOMP 4 /* Last component name in resolved path */
-#define DUK__IDX_DUKTAPE 5 /* Duktape object */
-#define DUK__IDX_MODLOADED 6 /* Duktape.modLoaded[] module cache */
-#define DUK__IDX_UNDEFINED 7 /* 'undefined', artifact of lookup */
-#define DUK__IDX_FRESH_REQUIRE 8 /* New require() function for module, updated resolution base */
-#define DUK__IDX_EXPORTS 9 /* Default exports table */
-#define DUK__IDX_MODULE 10 /* Module object containing module.exports, etc */
-
-DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
- const char *str_req_id; /* requested identifier */
- const char *str_mod_id; /* require.id of current module */
- duk_int_t pcall_rc;
-
- /* NOTE: we try to minimize code size by avoiding unnecessary pops,
- * so the stack looks a bit cluttered in this function. DUK_ASSERT_TOP()
- * assertions are used to ensure stack configuration is correct at each
- * step.
- */
-
- /*
- * Resolve module identifier into canonical absolute form.
- */
-
- str_req_id = duk_require_string(ctx, DUK__IDX_REQUESTED_ID);
- duk_push_current_function(ctx);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ID);
- str_mod_id = duk_get_string(ctx, DUK__IDX_REQUIRE_ID); /* ignore non-strings */
- DUK_DDD(DUK_DDDPRINT("resolve module id: requested=%!T, currentmodule=%!T",
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID)));
- duk__bi_global_resolve_module_id(ctx, str_req_id, str_mod_id);
- str_req_id = NULL;
- str_mod_id = NULL;
- DUK_DDD(DUK_DDDPRINT("resolved module id: requested=%!T, currentmodule=%!T, result=%!T, lastcomp=%!T",
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
-
- /* [ requested_id require require.id resolved_id last_comp ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_LASTCOMP + 1);
-
- /*
- * Cached module check.
- *
- * If module has been loaded or its loading has already begun without
- * finishing, return the same cached value ('exports'). The value is
- * registered when module load starts so that circular references can
- * be supported to some extent.
- */
-
- duk_push_hobject_bidx(ctx, DUK_BIDX_DUKTAPE);
- duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_LOADED); /* Duktape.modLoaded */
- (void) duk_require_hobject(ctx, DUK__IDX_MODLOADED);
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODLOADED + 1);
-
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- if (duk_get_prop(ctx, DUK__IDX_MODLOADED)) {
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded Duktape.modLoaded[id] ] */
- DUK_DD(DUK_DDPRINT("module already loaded: %!T",
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID)));
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_EXPORTS); /* return module.exports */
- return 1;
- }
- DUK_ASSERT_TOP(ctx, DUK__IDX_UNDEFINED + 1);
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined ] */
-
- /*
- * Module not loaded (and loading not started previously).
- *
- * Create a new require() function with 'id' set to resolved ID
- * of module being loaded. Also create 'exports' and 'module'
- * tables but don't register exports to the loaded table yet.
- * We don't want to do that unless the user module search callbacks
- * succeeds in finding the module.
- */
-
- DUK_D(DUK_DPRINT("loading module %!T, resolution base %!T, requested ID %!T -> resolved ID %!T, last component %!T",
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_REQUIRE_ID),
- duk_get_tval(ctx, DUK__IDX_REQUESTED_ID),
- duk_get_tval(ctx, DUK__IDX_RESOLVED_ID),
- duk_get_tval(ctx, DUK__IDX_LASTCOMP)));
-
- /* Fresh require: require.id is left configurable (but not writable)
- * so that is not easy to accidentally tweak it, but it can still be
- * done with Object.defineProperty().
- *
- * XXX: require.id could also be just made non-configurable, as there
- * is no practical reason to touch it.
- */
- duk_push_c_function(ctx, duk_bi_global_object_require, 1 /*nargs*/);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_REQUIRE);
- duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_xdef_prop_stridx(ctx, DUK__IDX_FRESH_REQUIRE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_C); /* a fresh require() with require.id = resolved target module id */
-
- /* Module table:
- * - module.exports: initial exports table (may be replaced by user)
- * - module.id is non-writable and non-configurable, as the CommonJS
- * spec suggests this if possible
- * - module.filename: not set, defaults to resolved ID if not explicitly
- * set by modSearch() (note capitalization, not .fileName, matches Node.js)
- * - module.name: not set, defaults to last component of resolved ID if
- * not explicitly set by modSearch()
- */
- duk_push_object(ctx); /* exports */
- duk_push_object(ctx); /* module */
- duk_dup(ctx, DUK__IDX_EXPORTS);
- duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS, DUK_PROPDESC_FLAGS_WC); /* module.exports = exports */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID); /* resolved id: require(id) must return this same module */
- duk_xdef_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_ID, DUK_PROPDESC_FLAGS_NONE); /* module.id = resolved_id */
- duk_compact(ctx, DUK__IDX_MODULE); /* module table remains registered to modLoaded, minimize its size */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 1);
-
- DUK_DD(DUK_DDPRINT("module table created: %!T", duk_get_tval(ctx, DUK__IDX_MODULE)));
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module ] */
-
- /* Register the module table early to modLoaded[] so that we can
- * support circular references even in modSearch(). If an error
- * is thrown, we'll delete the reference.
- */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_dup(ctx, DUK__IDX_MODULE);
- duk_put_prop(ctx, DUK__IDX_MODLOADED); /* Duktape.modLoaded[resolved_id] = module */
-
- /*
- * Call user provided module search function and build the wrapped
- * module source code (if necessary). The module search function
- * can be used to implement pure Ecmacsript, pure C, and mixed
- * Ecmascript/C modules.
- *
- * The module search function can operate on the exports table directly
- * (e.g. DLL code can register values to it). It can also return a
- * string which is interpreted as module source code (if a non-string
- * is returned the module is assumed to be a pure C one). If a module
- * cannot be found, an error must be thrown by the user callback.
- *
- * Because Duktape.modLoaded[] already contains the module being
- * loaded, circular references for C modules should also work
- * (although expected to be quite rare).
- */
-
- duk_push_string(ctx, "(function(require,exports,module){");
-
- /* Duktape.modSearch(resolved_id, fresh_require, exports, module). */
- duk_get_prop_stridx(ctx, DUK__IDX_DUKTAPE, DUK_STRIDX_MOD_SEARCH); /* Duktape.modSearch */
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_dup(ctx, DUK__IDX_FRESH_REQUIRE);
- duk_dup(ctx, DUK__IDX_EXPORTS);
- duk_dup(ctx, DUK__IDX_MODULE); /* [ ... Duktape.modSearch resolved_id last_comp fresh_require exports module ] */
- pcall_rc = duk_pcall(ctx, 4 /*nargs*/); /* -> [ ... source ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 3);
-
- if (pcall_rc != DUK_EXEC_SUCCESS) {
- /* Delete entry in Duktape.modLoaded[] and rethrow. */
- goto delete_rethrow;
- }
-
- /* If user callback did not return source code, module loading
- * is finished (user callback initialized exports table directly).
- */
- if (!duk_is_string(ctx, -1)) {
- /* User callback did not return source code, so module loading
- * is finished: just update modLoaded with final module.exports
- * and we're done.
- */
- goto return_exports;
- }
-
- /* Finish the wrapped module source. Force module.filename as the
- * function .fileName so it gets set for functions defined within a
- * module. This also ensures loggers created within the module get
- * the module ID (or overridden filename) as their default logger name.
- * (Note capitalization: .filename matches Node.js while .fileName is
- * used elsewhere in Duktape.)
- */
- duk_push_string(ctx, "})");
- duk_concat(ctx, 3);
- if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_FILENAME)) {
- /* module.filename for .fileName, default to resolved ID if
- * not present.
- */
- duk_pop(ctx);
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- }
- duk_eval_raw(ctx, NULL, 0, DUK_COMPILE_EVAL);
-
- /* Module has now evaluated to a wrapped module function. Force its
- * .name to match module.name (defaults to last component of resolved
- * ID) so that it is shown in stack traces too. Note that we must not
- * introduce an actual name binding into the function scope (which is
- * usually the case with a named function) because it would affect the
- * scope seen by the module and shadow accesses to globals of the same name.
- * This is now done by compiling the function as anonymous and then forcing
- * its .name without setting a "has name binding" flag.
- */
-
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NAME);
- if (!duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_NAME)) {
- /* module.name for .name, default to last component if
- * not present.
- */
- duk_pop(ctx);
- duk_dup(ctx, DUK__IDX_LASTCOMP);
- }
- duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_FORCE);
-
- /*
- * Call the wrapped module function.
- *
- * Use a protected call so that we can update Duktape.modLoaded[resolved_id]
- * even if the module throws an error.
- */
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
-
- duk_dup(ctx, DUK__IDX_EXPORTS); /* exports (this binding) */
- duk_dup(ctx, DUK__IDX_FRESH_REQUIRE); /* fresh require (argument) */
- duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS); /* relookup exports from module.exports in case it was changed by modSearch */
- duk_dup(ctx, DUK__IDX_MODULE); /* module (argument) */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 6);
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module mod_func exports fresh_require exports module ] */
-
- pcall_rc = duk_pcall_method(ctx, 3 /*nargs*/);
- if (pcall_rc != DUK_EXEC_SUCCESS) {
- /* Module loading failed. Node.js will forget the module
- * registration so that another require() will try to load
- * the module again. Mimic that behavior.
- */
- goto delete_rethrow;
- }
-
- /* [ requested_id require require.id resolved_id last_comp Duktape Duktape.modLoaded undefined fresh_require exports module result(ignored) ] */
- DUK_ASSERT_TOP(ctx, DUK__IDX_MODULE + 2);
-
- /* fall through */
-
- return_exports:
- duk_get_prop_stridx(ctx, DUK__IDX_MODULE, DUK_STRIDX_EXPORTS);
- duk_compact(ctx, -1); /* compact the exports table */
- return 1; /* return module.exports */
-
- delete_rethrow:
- duk_dup(ctx, DUK__IDX_RESOLVED_ID);
- duk_del_prop(ctx, DUK__IDX_MODLOADED); /* delete Duktape.modLoaded[resolved_id] */
- duk_throw(ctx); /* rethrow original error */
- return 0; /* not reachable */
-}
-
-#undef DUK__IDX_REQUESTED_ID
-#undef DUK__IDX_REQUIRE
-#undef DUK__IDX_REQUIRE_ID
-#undef DUK__IDX_RESOLVED_ID
-#undef DUK__IDX_LASTCOMP
-#undef DUK__IDX_DUKTAPE
-#undef DUK__IDX_MODLOADED
-#undef DUK__IDX_UNDEFINED
-#undef DUK__IDX_FRESH_REQUIRE
-#undef DUK__IDX_EXPORTS
-#undef DUK__IDX_MODULE
-#else
-DUK_INTERNAL duk_ret_t duk_bi_global_object_require(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_COMMONJS_MODULES */
-#line 1 "duk_bi_json.c"
-/*
- * JSON built-ins.
- *
- * See doc/json.rst.
- *
- * Codepoints are handled as duk_uint_fast32_t to ensure that the full
- * unsigned 32-bit range is supported. This matters to e.g. JX.
- *
- * Input parsing doesn't do an explicit end-of-input check at all. This is
- * safe: input string data is always NUL-terminated (0x00) and valid JSON
- * inputs never contain plain NUL characters, so that as long as syntax checks
- * are correct, we'll never read past the NUL. This approach reduces code size
- * and improves parsing performance, but it's critical that syntax checks are
- * indeed correct!
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Local defines and forward declarations.
- */
-
-#define DUK__JSON_DECSTR_BUFSIZE 128
-#define DUK__JSON_DECSTR_CHUNKSIZE 64
-#define DUK__JSON_ENCSTR_CHUNKSIZE 64
-#define DUK__JSON_STRINGIFY_BUFSIZE 128
-#define DUK__JSON_MAX_ESC_LEN 10 /* '\Udeadbeef' */
-
-DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
-DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
-DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx);
-#ifdef DUK_USE_JX
-DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
-#endif
-DUK_LOCAL_DECL void duk__dec_number(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_object(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_array(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx);
-
-DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch);
-DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2);
-DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h);
-#if defined(DUK_USE_FASTINT)
-DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p);
-#endif
-DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx);
-DUK_LOCAL_DECL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q);
-DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k);
-DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
-DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
-DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
-DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx);
-DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx);
-DUK_LOCAL_DECL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
-DUK_LOCAL_DECL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv);
-DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx);
-#if defined(DUK_USE_FASTINT)
-DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
-#endif
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
-DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
-DUK_LOCAL_DECL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj);
-#endif
-DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth);
-
-/*
- * Helper tables
- */
-
-#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
-DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = {
- /* 0x00 ... 0x7f: as is
- * 0x80: escape generically
- * 0x81: slow path
- * 0xa0 ... 0xff: backslash + one char
- */
-
- 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80,
- 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
- 0x20, 0x21, 0xa2, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0xdc, 0x5d, 0x5e, 0x5f,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81
-};
-#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
-DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = {
- DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
- DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
- DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL,
- DUK_ASC_LC_F, DUK_ASC_LC_R
-};
-#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
-
-#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
-DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = {
- /* 0x00: slow path
- * other: as is
- */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x00, 0x5d, 0x5e, 0x5f,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
- 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
- 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
- 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
- 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
- 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
- 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
-};
-#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
-
-#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
-DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = {
- /* 0x00: finish (non-white)
- * 0x01: continue
- */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
-
-#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
-DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = {
- /* 0x00: finish (not part of number)
- * 0x01: continue
- */
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
-
-/*
- * Parsing implementation.
- *
- * JSON lexer is now separate from duk_lexer.c because there are numerous
- * small differences making it difficult to share the lexer.
- *
- * The parser here works with raw bytes directly; this works because all
- * JSON delimiters are ASCII characters. Invalid xUTF-8 encoded values
- * inside strings will be passed on without normalization; this is not a
- * compliance concern because compliant inputs will always be valid
- * CESU-8 encodings.
- */
-
-DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) {
- /* Shared handler to minimize parser size. Cause will be
- * hidden, unfortunately, but we'll have an offset which
- * is often quite enough.
- */
- DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON,
- (long) (js_ctx->p - js_ctx->p_start));
-}
-
-DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
- const duk_uint8_t *p;
- duk_uint8_t t;
-
- p = js_ctx->p;
- for (;;) {
- DUK_ASSERT(p <= js_ctx->p_end);
- t = *p;
-
-#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
- /* This fast path is pretty marginal in practice.
- * XXX: candidate for removal.
- */
- DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00); /* end-of-input breaks */
- if (duk__json_eatwhite_lookup[t] == 0) {
- break;
- }
-#else /* DUK_USE_JSON_EATWHITE_FASTPATH */
- if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) {
- /* NUL also comes here. Comparison order matters, 0x20
- * is most common whitespace.
- */
- break;
- }
-#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
- p++;
- }
- js_ctx->p = p;
-}
-
-DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) {
- DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
- return *js_ctx->p;
-}
-
-DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) {
- DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
- return *js_ctx->p++;
-}
-
-DUK_LOCAL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
- duk__dec_eat_white(js_ctx);
- return duk__dec_get(js_ctx);
-}
-
-/* For JX, expressing the whole unsigned 32-bit range matters. */
-DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) {
- duk_small_uint_t i;
- duk_uint_fast32_t res = 0;
- duk_uint8_t x;
- duk_small_int_t t;
-
- for (i = 0; i < n; i++) {
- /* XXX: share helper from lexer; duk_lexer.c / hexval(). */
-
- x = duk__dec_get(js_ctx);
- DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld",
- (long) i, (long) n, (long) res, (long) x));
-
- /* x == 0x00 (EOF) causes syntax_error */
- DUK_ASSERT(duk_hex_dectab[0] == -1);
- t = duk_hex_dectab[x & 0xff];
- if (DUK_LIKELY(t >= 0)) {
- res = (res * 16) + t;
- } else {
- /* catches EOF and invalid digits */
- goto syntax_error;
- }
- }
-
- DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld", (long) res));
- return res;
-
- syntax_error:
- duk__dec_syntax_error(js_ctx);
- DUK_UNREACHABLE();
- return 0;
-}
-
-DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
- duk_hstring *h;
- const duk_uint8_t *p;
- duk_uint8_t x, y;
-
- /* First character has already been eaten and checked by the caller.
- * We can scan until a NUL in stridx string because no built-in strings
- * have internal NULs.
- */
-
- DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
- DUK_ASSERT(h != NULL);
-
- p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1;
- DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */
-
- for (;;) {
- x = *p;
- if (x == 0) {
- break;
- }
- y = duk__dec_get(js_ctx);
- if (x != y) {
- /* Catches EOF of JSON input. */
- goto syntax_error;
- }
- p++;
- }
-
- return;
-
- syntax_error:
- duk__dec_syntax_error(js_ctx);
- DUK_UNREACHABLE();
-}
-
-DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) {
- duk_uint_fast32_t cp;
-
- /* EOF (-1) will be cast to an unsigned value first
- * and then re-cast for the switch. In any case, it
- * will match the default case (syntax error).
- */
- cp = (duk_uint_fast32_t) duk__dec_get(js_ctx);
- switch ((int) cp) {
- case DUK_ASC_BACKSLASH: break;
- case DUK_ASC_DOUBLEQUOTE: break;
- case DUK_ASC_SLASH: break;
- case DUK_ASC_LC_T: cp = 0x09; break;
- case DUK_ASC_LC_N: cp = 0x0a; break;
- case DUK_ASC_LC_R: cp = 0x0d; break;
- case DUK_ASC_LC_F: cp = 0x0c; break;
- case DUK_ASC_LC_B: cp = 0x08; break;
- case DUK_ASC_LC_U: {
- cp = duk__dec_decode_hex_escape(js_ctx, 4);
- break;
- }
-#ifdef DUK_USE_JX
- case DUK_ASC_UC_U: {
- if (js_ctx->flag_ext_custom) {
- cp = duk__dec_decode_hex_escape(js_ctx, 8);
- } else {
- return 1; /* syntax error */
- }
- break;
- }
- case DUK_ASC_LC_X: {
- if (js_ctx->flag_ext_custom) {
- cp = duk__dec_decode_hex_escape(js_ctx, 2);
- } else {
- return 1; /* syntax error */
- }
- break;
- }
-#endif /* DUK_USE_JX */
- default:
- /* catches EOF (0x00) */
- return 1; /* syntax error */
- }
-
- DUK_RAW_WRITE_XUTF8(*ext_p, cp);
-
- return 0;
-}
-
-DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
- duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_bufwriter_ctx bw_alloc;
- duk_bufwriter_ctx *bw;
- duk_uint8_t *q;
-
- /* '"' was eaten by caller */
-
- /* Note that we currently parse -bytes-, not codepoints.
- * All non-ASCII extended UTF-8 will encode to bytes >= 0x80,
- * so they'll simply pass through (valid UTF-8 or not).
- */
-
- bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE);
- q = DUK_BW_GET_PTR(js_ctx->thr, bw);
-
-#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
- for (;;) {
- duk_small_uint_t safe;
- duk_uint8_t b, x;
- const duk_uint8_t *p;
-
- /* Select a safe loop count where no output checks are
- * needed assuming we won't encounter escapes. Input
- * bound checks are not necessary as a NUL (guaranteed)
- * will cause a SyntaxError before we read out of bounds.
- */
-
- safe = DUK__JSON_DECSTR_CHUNKSIZE;
-
- /* Ensure space for 1:1 output plus one escape. */
- q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q);
-
- p = js_ctx->p; /* temp copy, write back for next loop */
- for (;;) {
- if (safe == 0) {
- js_ctx->p = p;
- break;
- }
- safe--;
-
- /* End of input (NUL) goes through slow path and causes SyntaxError. */
- DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00);
-
- b = *p++;
- x = (duk_small_int_t) duk__json_decstr_lookup[b];
- if (DUK_LIKELY(x != 0)) {
- /* Fast path, decode as is. */
- *q++ = b;
- } else if (b == DUK_ASC_DOUBLEQUOTE) {
- js_ctx->p = p;
- goto found_quote;
- } else if (b == DUK_ASC_BACKSLASH) {
- /* We've ensured space for one escaped input; then
- * bail out and recheck (this makes escape handling
- * quite slow but it's uncommon).
- */
- js_ctx->p = p;
- if (duk__dec_string_escape(js_ctx, &q) != 0) {
- goto syntax_error;
- }
- break;
- } else {
- js_ctx->p = p;
- goto syntax_error;
- }
- }
- }
- found_quote:
-#else /* DUK_USE_JSON_DECSTRING_FASTPATH */
- for (;;) {
- duk_uint8_t x;
-
- q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q);
-
- x = duk__dec_get(js_ctx);
-
- if (x == DUK_ASC_DOUBLEQUOTE) {
- break;
- } else if (x == DUK_ASC_BACKSLASH) {
- if (duk__dec_string_escape(js_ctx, &q) != 0) {
- goto syntax_error;
- }
- } else if (x < 0x20) {
- /* catches EOF (NUL) */
- goto syntax_error;
- } else {
- *q++ = (duk_uint8_t) x;
- }
- }
-#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
-
- DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
- duk_to_string(ctx, -1);
-
- /* [ ... str ] */
-
- return;
-
- syntax_error:
- duk__dec_syntax_error(js_ctx);
- DUK_UNREACHABLE();
-}
-
-#ifdef DUK_USE_JX
-/* Decode a plain string consisting entirely of identifier characters.
- * Used to parse plain keys (e.g. "foo: 123").
- */
-DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
- duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- const duk_uint8_t *p;
- duk_small_int_t x;
-
- /* Caller has already eaten the first char so backtrack one byte. */
-
- js_ctx->p--; /* safe */
- p = js_ctx->p;
-
- /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of
- * parsing (which is correct except if there are non-shortest encodings).
- * There is also no need to check explicitly for end of input buffer as
- * the input is NUL padded and NUL will exit the parsing loop.
- *
- * Because no unescaping takes place, we can just scan to the end of the
- * plain string and intern from the input buffer.
- */
-
- for (;;) {
- x = *p;
-
- /* There is no need to check the first character specially here
- * (i.e. reject digits): the caller only accepts valid initial
- * characters and won't call us if the first character is a digit.
- * This also ensures that the plain string won't be empty.
- */
-
- if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) {
- break;
- }
- p++;
- }
-
- duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
- js_ctx->p = p;
-
- /* [ ... str ] */
-}
-#endif /* DUK_USE_JX */
-
-#ifdef DUK_USE_JX
-DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
- duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- const duk_uint8_t *p;
- duk_small_int_t x;
- void *voidptr;
-
- /* Caller has already eaten the first character ('(') which we don't need. */
-
- p = js_ctx->p;
-
- for (;;) {
- x = *p;
-
- /* Assume that the native representation never contains a closing
- * parenthesis.
- */
-
- if (x == DUK_ASC_RPAREN) {
- break;
- } else if (x <= 0) {
- /* NUL term or -1 (EOF), NUL check would suffice */
- goto syntax_error;
- }
- p++;
- }
-
- /* There is no need to NUL delimit the sscanf() call: trailing garbage is
- * ignored and there is always a NUL terminator which will force an error
- * if no error is encountered before it. It's possible that the scan
- * would scan further than between [js_ctx->p,p[ though and we'd advance
- * by less than the scanned value.
- *
- * Because pointers are platform specific, a failure to scan a pointer
- * results in a null pointer which is a better placeholder than a missing
- * value or an error.
- */
-
- voidptr = NULL;
- (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
- duk_push_pointer(ctx, voidptr);
- js_ctx->p = p + 1; /* skip ')' */
-
- /* [ ... ptr ] */
-
- return;
-
- syntax_error:
- duk__dec_syntax_error(js_ctx);
- DUK_UNREACHABLE();
-}
-#endif /* DUK_USE_JX */
-
-#ifdef DUK_USE_JX
-DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
- duk_hthread *thr = js_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- const duk_uint8_t *p;
- duk_uint8_t *buf;
- duk_size_t src_len;
- duk_small_int_t x;
-
- /* Caller has already eaten the first character ('|') which we don't need. */
-
- p = js_ctx->p;
-
- /* XXX: Would be nice to share the fast path loop from duk_hex_decode()
- * and avoid creating a temporary buffer. However, there are some
- * differences which prevent trivial sharing:
- *
- * - Pipe char detection
- * - EOF detection
- * - Unknown length of input and output
- *
- * The best approach here would be a bufwriter and a reasonaly sized
- * safe inner loop (e.g. 64 output bytes at a time).
- */
-
- for (;;) {
- x = *p;
-
- /* This loop intentionally does not ensure characters are valid
- * ([0-9a-fA-F]) because the hex decode call below will do that.
- */
- if (x == DUK_ASC_PIPE) {
- break;
- } else if (x <= 0) {
- /* NUL term or -1 (EOF), NUL check would suffice */
- goto syntax_error;
- }
- p++;
- }
-
- src_len = (duk_size_t) (p - js_ctx->p);
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, src_len);
- DUK_ASSERT(buf != NULL);
- DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
- duk_hex_decode(ctx, -1);
-
- js_ctx->p = p + 1; /* skip '|' */
-
- /* [ ... buf ] */
-
- return;
-
- syntax_error:
- duk__dec_syntax_error(js_ctx);
- DUK_UNREACHABLE();
-}
-#endif /* DUK_USE_JX */
-
-/* Parse a number, other than NaN or +/- Infinity */
-DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- const duk_uint8_t *p_start;
- const duk_uint8_t *p;
- duk_uint8_t x;
- duk_small_uint_t s2n_flags;
-
- DUK_DDD(DUK_DDDPRINT("parse_number"));
-
- p_start = js_ctx->p;
-
- /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a
- * string for strict number parsing.
- */
-
- p = js_ctx->p;
- for (;;) {
- x = *p;
-
- DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld",
- (const void *) p_start, (const void *) p,
- (const void *) js_ctx->p_end, (long) x));
-
-#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
- /* This fast path is pretty marginal in practice.
- * XXX: candidate for removal.
- */
- DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00); /* end-of-input breaks */
- if (duk__json_decnumber_lookup[x] == 0) {
- break;
- }
-#else /* DUK_USE_JSON_DECNUMBER_FASTPATH */
- if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
- (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E ||
- x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) {
- /* Plus sign must be accepted for positive exponents
- * (e.g. '1.5e+2'). This clause catches NULs.
- */
- break;
- }
-#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
- p++; /* safe, because matched (NUL causes a break) */
- }
- js_ctx->p = p;
-
- DUK_ASSERT(js_ctx->p > p_start);
- duk_push_lstring(ctx, (const char *) p_start, (duk_size_t) (p - p_start));
-
- s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
- DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */
- DUK_S2N_FLAG_ALLOW_FRAC;
-
- DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
- if (duk_is_nan(ctx, -1)) {
- duk__dec_syntax_error(js_ctx);
- }
- DUK_ASSERT(duk_is_number(ctx, -1));
- DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* [ ... num ] */
-}
-
-DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK);
-
- /* c recursion check */
-
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
- DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
- if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONDEC_RECLIMIT);
- }
- js_ctx->recursion_depth++;
-}
-
-DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
- /* c recursion check */
-
- DUK_ASSERT(js_ctx->recursion_depth > 0);
- DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
- js_ctx->recursion_depth--;
-}
-
-DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_int_t key_count; /* XXX: a "first" flag would suffice */
- duk_uint8_t x;
-
- DUK_DDD(DUK_DDDPRINT("parse_object"));
-
- duk__dec_objarr_entry(js_ctx);
-
- duk_push_object(ctx);
-
- /* Initial '{' has been checked and eaten by caller. */
-
- key_count = 0;
- for (;;) {
- x = duk__dec_get_nonwhite(js_ctx);
-
- DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) x, (long) key_count));
-
- /* handle comma and closing brace */
-
- if (x == DUK_ASC_COMMA && key_count > 0) {
- /* accept comma, expect new value */
- x = duk__dec_get_nonwhite(js_ctx);
- } else if (x == DUK_ASC_RCURLY) {
- /* eat closing brace */
- break;
- } else if (key_count == 0) {
- /* accept anything, expect first value (EOF will be
- * caught by key parsing below.
- */
- ;
- } else {
- /* catches EOF (NUL) and initial comma */
- goto syntax_error;
- }
-
- /* parse key and value */
-
- if (x == DUK_ASC_DOUBLEQUOTE) {
- duk__dec_string(js_ctx);
-#ifdef DUK_USE_JX
- } else if (js_ctx->flag_ext_custom &&
- duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
- duk__dec_plain_string(js_ctx);
-#endif
- } else {
- goto syntax_error;
- }
-
- /* [ ... obj key ] */
-
- x = duk__dec_get_nonwhite(js_ctx);
- if (x != DUK_ASC_COLON) {
- goto syntax_error;
- }
-
- duk__dec_value(js_ctx);
-
- /* [ ... obj key val ] */
-
- duk_xdef_prop_wec(ctx, -3);
-
- /* [ ... obj ] */
-
- key_count++;
- }
-
- /* [ ... obj ] */
-
- DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk__dec_objarr_exit(js_ctx);
- return;
-
- syntax_error:
- duk__dec_syntax_error(js_ctx);
- DUK_UNREACHABLE();
-}
-
-DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_uarridx_t arr_idx;
- duk_uint8_t x;
-
- DUK_DDD(DUK_DDDPRINT("parse_array"));
-
- duk__dec_objarr_entry(js_ctx);
-
- duk_push_array(ctx);
-
- /* Initial '[' has been checked and eaten by caller. */
-
- arr_idx = 0;
- for (;;) {
- x = duk__dec_get_nonwhite(js_ctx);
-
- DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) x, (long) arr_idx));
-
- /* handle comma and closing bracket */
-
- if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) {
- /* accept comma, expect new value */
- ;
- } else if (x == DUK_ASC_RBRACKET) {
- /* eat closing bracket */
- break;
- } else if (arr_idx == 0) {
- /* accept anything, expect first value (EOF will be
- * caught by duk__dec_value() below.
- */
- js_ctx->p--; /* backtrack (safe) */
- } else {
- /* catches EOF (NUL) and initial comma */
- goto syntax_error;
- }
-
- /* parse value */
-
- duk__dec_value(js_ctx);
-
- /* [ ... arr val ] */
-
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
- }
-
- /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to
- * set the values.
- */
-
- duk_set_length(ctx, -1, arr_idx);
-
- /* [ ... arr ] */
-
- DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk__dec_objarr_exit(js_ctx);
- return;
-
- syntax_error:
- duk__dec_syntax_error(js_ctx);
- DUK_UNREACHABLE();
-}
-
-DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_uint8_t x;
-
- x = duk__dec_get_nonwhite(js_ctx);
-
- DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x));
-
- /* Note: duk__dec_req_stridx() backtracks one char */
-
- if (x == DUK_ASC_DOUBLEQUOTE) {
- duk__dec_string(js_ctx);
- } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
-#ifdef DUK_USE_JX
- if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
- duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */
- duk_push_number(ctx, -DUK_DOUBLE_INFINITY);
- } else {
-#else
- { /* unconditional block */
-#endif
- /* We already ate 'x', so backup one byte. */
- js_ctx->p--; /* safe */
- duk__dec_number(js_ctx);
- }
- } else if (x == DUK_ASC_LC_T) {
- duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
- duk_push_true(ctx);
- } else if (x == DUK_ASC_LC_F) {
- duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
- duk_push_false(ctx);
- } else if (x == DUK_ASC_LC_N) {
- duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
- duk_push_null(ctx);
-#ifdef DUK_USE_JX
- } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
- duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
- duk_push_undefined(ctx);
- } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
- duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
- duk_push_nan(ctx);
- } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
- duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
- duk_push_number(ctx, DUK_DOUBLE_INFINITY);
- } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
- duk__dec_pointer(js_ctx);
- } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
- duk__dec_buffer(js_ctx);
-#endif
- } else if (x == DUK_ASC_LCURLY) {
- duk__dec_object(js_ctx);
- } else if (x == DUK_ASC_LBRACKET) {
- duk__dec_array(js_ctx);
- } else {
- /* catches EOF (NUL) */
- goto syntax_error;
- }
-
- duk__dec_eat_white(js_ctx);
-
- /* [ ... val ] */
- return;
-
- syntax_error:
- duk__dec_syntax_error(js_ctx);
- DUK_UNREACHABLE();
-}
-
-/* Recursive value reviver, implements the Walk() algorithm. No C recursion
- * check is done here because the initial parsing step will already ensure
- * there is a reasonable limit on C recursion depth and hence object depth.
- */
-DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hobject *h;
- duk_uarridx_t i, arr_len;
-
- DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
- (long) duk_get_top(ctx),
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk_dup_top(ctx);
- duk_get_prop(ctx, -3); /* -> [ ... holder name val ] */
-
- h = duk_get_hobject(ctx, -1);
- if (h != NULL) {
- if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
- arr_len = (duk_uarridx_t) duk_get_length(ctx, -1);
- for (i = 0; i < arr_len; i++) {
- /* [ ... holder name val ] */
-
- DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
- (long) duk_get_top(ctx), (long) i, (long) arr_len,
- (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* XXX: push_uint_string / push_u32_string */
- duk_dup_top(ctx);
- duk_push_uint(ctx, (duk_uint_t) i);
- duk_to_string(ctx, -1); /* -> [ ... holder name val val ToString(i) ] */
- duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */
-
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_del_prop_index(ctx, -1, i);
- } else {
- /* XXX: duk_xdef_prop_index_wec() would be more appropriate
- * here but it currently makes some assumptions that might
- * not hold (e.g. that previous property is not an accessor).
- */
- duk_put_prop_index(ctx, -2, i);
- }
- }
- } else {
- /* [ ... holder name val ] */
- duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
- while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
- DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -5),
- (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3),
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* [ ... holder name val enum obj_key ] */
- duk_dup(ctx, -3);
- duk_dup(ctx, -2);
-
- /* [ ... holder name val enum obj_key val obj_key ] */
- duk__dec_reviver_walk(js_ctx);
-
- /* [ ... holder name val enum obj_key new_elem ] */
- if (duk_is_undefined(ctx, -1)) {
- duk_pop(ctx);
- duk_del_prop(ctx, -3);
- } else {
- /* XXX: duk_xdef_prop_index_wec() would be more appropriate
- * here but it currently makes some assumptions that might
- * not hold (e.g. that previous property is not an accessor).
- *
- * Using duk_put_prop() works incorrectly with '__proto__'
- * if the own property with that name has been deleted. This
- * does not happen normally, but a clever reviver can trigger
- * that, see complex reviver case in: test-bug-json-parse-__proto__.js.
- */
- duk_put_prop(ctx, -4);
- }
- }
- duk_pop(ctx); /* pop enum */
- }
- }
-
- /* [ ... holder name val ] */
-
- duk_dup(ctx, js_ctx->idx_reviver);
- duk_insert(ctx, -4); /* -> [ ... reviver holder name val ] */
- duk_call_method(ctx, 2); /* -> [ ... res ] */
-
- DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -1)));
-}
-
-/*
- * Stringify implementation.
- */
-
-#define DUK__EMIT_1(js_ctx,ch) duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch))
-#define DUK__EMIT_2(js_ctx,ch1,ch2) duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2))
-#define DUK__EMIT_HSTR(js_ctx,h) duk__emit_hstring((js_ctx), (h))
-#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
-#define DUK__EMIT_CSTR(js_ctx,p) duk__emit_cstring((js_ctx), (p))
-#endif
-#define DUK__EMIT_STRIDX(js_ctx,i) duk__emit_stridx((js_ctx), (i))
-#define DUK__UNEMIT_1(js_ctx) duk__unemit_1((js_ctx))
-
-DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) {
- DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch);
-}
-
-DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) {
- DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2);
-}
-
-DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) {
- DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
-}
-
-#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) {
- DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str);
-}
-#endif
-
-DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) {
- duk_hstring *h;
-
- DUK_ASSERT_DISABLE(stridx >= 0); /* unsigned */
- DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS);
- h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
- DUK_ASSERT(h != NULL);
-
- DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
-}
-
-DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) {
- DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1);
- DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1);
-}
-
-#define DUK__MKESC(nybbles,esc1,esc2) \
- (((duk_uint_fast32_t) (nybbles)) << 16) | \
- (((duk_uint_fast32_t) (esc1)) << 8) | \
- ((duk_uint_fast32_t) (esc2))
-
-DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) {
- duk_uint_fast32_t tmp;
- duk_small_uint_t dig;
-
- DUK_UNREF(js_ctx);
-
- /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */
-
- /* Select appropriate escape format automatically, and set 'tmp' to a
- * value encoding both the escape format character and the nybble count:
- *
- * (nybble_count << 16) | (escape_char1) | (escape_char2)
- */
-
-#ifdef DUK_USE_JX
- if (DUK_LIKELY(cp < 0x100UL)) {
- if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) {
- tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
- } else {
- tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
- }
- } else
-#endif
- if (DUK_LIKELY(cp < 0x10000UL)) {
- tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
- } else {
-#ifdef DUK_USE_JX
- if (DUK_LIKELY(js_ctx->flag_ext_custom)) {
- tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
- } else
-#endif
- {
- /* In compatible mode and standard JSON mode, output
- * something useful for non-BMP characters. This won't
- * roundtrip but will still be more or less readable and
- * more useful than an error.
- */
- tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS);
- }
- }
-
- *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff);
- *q++ = (duk_uint8_t) (tmp & 0xff);
-
- tmp = tmp >> 16;
- while (tmp > 0) {
- tmp--;
- dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f);
- *q++ = duk_lc_digits[dig];
- }
-
- return q;
-}
-
-DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
- const duk_int8_t *p, *p_start, *p_end; /* Note: intentionally signed. */
- duk_size_t k_len;
- duk_codepoint_t cp;
-
- DUK_ASSERT(k != NULL);
-
- /* Accept ASCII strings which conform to identifier requirements
- * as being emitted without key quotes. Since we only accept ASCII
- * there's no need for actual decoding: 'p' is intentionally signed
- * so that bytes >= 0x80 extend to negative values and are rejected
- * as invalid identifier codepoints.
- */
-
- if (js_ctx->flag_avoid_key_quotes) {
- k_len = DUK_HSTRING_GET_BYTELEN(k);
- p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k);
- p_end = p_start + k_len;
- p = p_start;
-
- if (p == p_end) {
- /* Zero length string is not accepted without quotes */
- goto quote_normally;
- }
- cp = (duk_codepoint_t) (*p++);
- if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) {
- goto quote_normally;
- }
- while (p < p_end) {
- cp = (duk_codepoint_t) (*p++);
- if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) {
- goto quote_normally;
- }
- }
-
- /* This seems faster than emitting bytes one at a time and
- * then potentially rewinding.
- */
- DUK__EMIT_HSTR(js_ctx, k);
- return;
- }
-
- quote_normally:
- duk__enc_quote_string(js_ctx, k);
-}
-
-/* The Quote(value) operation: quote a string.
- *
- * Stack policy: [ ] -> [ ].
- */
-
-DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
- duk_hthread *thr = js_ctx->thr;
- const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp;
- duk_uint8_t *q;
- duk_ucodepoint_t cp; /* typed for duk_unicode_decode_xutf8() */
-
- DUK_DDD(DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str));
-
- DUK_ASSERT(h_str != NULL);
- p_start = DUK_HSTRING_GET_DATA(h_str);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str);
- p = p_start;
-
- DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
-
- /* Encode string in small chunks, estimating the maximum expansion so that
- * there's no need to ensure space while processing the chunk.
- */
-
- while (p < p_end) {
- duk_size_t left, now, space;
-
- left = (duk_size_t) (p_end - p);
- now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ?
- DUK__JSON_ENCSTR_CHUNKSIZE : left);
-
- /* Maximum expansion per input byte is 6:
- * - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6).
- * - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3).
- * - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5).
- */
- space = now * 6;
- q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
-
- p_now = p + now;
-
- while (p < p_now) {
-#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
- duk_uint8_t b;
-
- b = duk__json_quotestr_lookup[*p++];
- if (DUK_LIKELY(b < 0x80)) {
- /* Most input bytes go through here. */
- *q++ = b;
- } else if (b >= 0xa0) {
- *q++ = DUK_ASC_BACKSLASH;
- *q++ = (duk_uint8_t) (b - 0x80);
- } else if (b == 0x80) {
- cp = (duk_ucodepoint_t) (*(p - 1));
- q = duk__emit_esc_auto_fast(js_ctx, cp, q);
- } else if (b == 0x7f && js_ctx->flag_ascii_only) {
- /* 0x7F is special */
- DUK_ASSERT(b == 0x81);
- cp = (duk_ucodepoint_t) 0x7f;
- q = duk__emit_esc_auto_fast(js_ctx, cp, q);
- } else {
- DUK_ASSERT(b == 0x81);
- p--;
-
- /* slow path is shared */
-#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
- cp = *p;
-
- if (DUK_LIKELY(cp <= 0x7f)) {
- /* ascii fast path: avoid decoding utf-8 */
- p++;
- if (cp == 0x22 || cp == 0x5c) {
- /* double quote or backslash */
- *q++ = DUK_ASC_BACKSLASH;
- *q++ = (duk_uint8_t) cp;
- } else if (cp < 0x20) {
- duk_uint_fast8_t esc_char;
-
- /* This approach is a bit shorter than a straight
- * if-else-ladder and also a bit faster.
- */
- if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) &&
- (esc_char = duk__json_quotestr_esc[cp]) != 0) {
- *q++ = DUK_ASC_BACKSLASH;
- *q++ = (duk_uint8_t) esc_char;
- } else {
- q = duk__emit_esc_auto_fast(js_ctx, cp, q);
- }
- } else if (cp == 0x7f && js_ctx->flag_ascii_only) {
- q = duk__emit_esc_auto_fast(js_ctx, cp, q);
- } else {
- /* any other printable -> as is */
- *q++ = (duk_uint8_t) cp;
- }
- } else {
- /* slow path is shared */
-#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
-
- /* slow path decode */
-
- /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly
- * and go forward one byte. This is of course very lossy, but allows some kind
- * of output to be produced even for internal strings which don't conform to
- * XUTF-8. All standard Ecmascript strings are always CESU-8, so this behavior
- * does not violate the Ecmascript specification. The behavior is applied to
- * all modes, including Ecmascript standard JSON. Because the current XUTF-8
- * decoding is not very strict, this behavior only really affects initial bytes
- * and truncated codepoints.
- *
- * Another alternative would be to scan forwards to start of next codepoint
- * (or end of input) and emit just one replacement codepoint.
- */
-
- p_tmp = p;
- if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
- /* Decode failed. */
- cp = *p_tmp;
- p = p_tmp + 1;
- }
-
-#ifdef DUK_USE_NONSTD_JSON_ESC_U2028_U2029
- if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) {
-#else
- if (js_ctx->flag_ascii_only) {
-#endif
- q = duk__emit_esc_auto_fast(js_ctx, cp, q);
- } else {
- /* as is */
- DUK_RAW_WRITE_XUTF8(q, cp);
- }
- }
- }
-
- DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
- }
-
- DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
-}
-
-/* Encode a double (checked by caller) from stack top. Stack top may be
- * replaced by serialized string but is not popped (caller does that).
- */
-DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
- duk_hthread *thr;
- duk_context *ctx;
- duk_tval *tv;
- duk_double_t d;
- duk_small_int_t c;
- duk_small_int_t s;
- duk_small_uint_t stridx;
- duk_small_uint_t n2s_flags;
- duk_hstring *h_str;
-
- DUK_ASSERT(js_ctx != NULL);
- thr = js_ctx->thr;
- DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
-
- /* Caller must ensure 'tv' is indeed a double and not a fastint! */
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
- d = DUK_TVAL_GET_DOUBLE(tv);
-
- c = (duk_small_int_t) DUK_FPCLASSIFY(d);
- s = (duk_small_int_t) DUK_SIGNBIT(d);
- DUK_UNREF(s);
-
- if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) {
- DUK_ASSERT(DUK_ISFINITE(d));
-
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- /* Negative zero needs special handling in JX/JC because
- * it would otherwise serialize to '0', not '-0'.
- */
- if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
- (js_ctx->flag_ext_custom_or_compatible))) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */
- } else
-#endif /* DUK_USE_JX || DUK_USE_JC */
- {
- n2s_flags = 0;
- /* [ ... number ] -> [ ... string ] */
- duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags);
- }
- h_str = duk_to_hstring(ctx, -1);
- DUK_ASSERT(h_str != NULL);
- DUK__EMIT_HSTR(js_ctx, h_str);
- return;
- }
-
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
- DUK_JSON_FLAG_EXT_COMPATIBLE))) {
- stridx = DUK_STRIDX_LC_NULL;
- } else if (c == DUK_FP_NAN) {
- stridx = js_ctx->stridx_custom_nan;
- } else if (s == 0) {
- stridx = js_ctx->stridx_custom_posinf;
- } else {
- stridx = js_ctx->stridx_custom_neginf;
- }
-#else
- stridx = DUK_STRIDX_LC_NULL;
-#endif
- DUK__EMIT_STRIDX(js_ctx, stridx);
-}
-
-#if defined(DUK_USE_FASTINT)
-/* Encode a fastint from duk_tval ptr, no value stack effects. */
-DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
- duk_int64_t v;
-
- /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328
- * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808
- * (20 chars long). Alloc space for 64-bit range to be safe.
- */
- duk_uint8_t buf[20 + 1];
-
- /* Caller must ensure 'tv' is indeed a fastint! */
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
- v = DUK_TVAL_GET_FASTINT(tv);
-
- /* XXX: There are no format strings in duk_config.h yet, could add
- * one for formatting duk_int64_t. For now, assumes "%lld" and that
- * "long long" type exists. Could also rely on C99 directly but that
- * won't work for older MSVC.
- */
- DUK_SPRINTF((char *) buf, "%lld", (long long) v);
- DUK__EMIT_CSTR(js_ctx, (const char *) buf);
-}
-#endif
-
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-#if defined(DUK_USE_HEX_FASTPATH)
-DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
- duk_uint8_t *q;
- duk_uint16_t *q16;
- duk_small_uint_t x;
- duk_size_t i, len_safe;
-#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
- duk_bool_t shift_dst;
-#endif
-
- /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2.
- * For platforms where unaligned accesses are not allowed, shift 'dst'
- * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result
- * in place. The faster encoding loop makes up the difference.
- * There's always space for one extra byte because a terminator always
- * follows the hex data and that's been accounted for by the caller.
- */
-
-#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
- q16 = (duk_uint16_t *) (void *) dst;
-#else
- shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U);
- if (shift_dst) {
- DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1"));
- q16 = (duk_uint16_t *) (void *) (dst + 1);
- } else {
- DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned"));
- q16 = (duk_uint16_t *) (void *) dst;
- }
- DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0);
-#endif
-
- len_safe = src_len & ~0x03U;
- for (i = 0; i < len_safe; i += 4) {
- q16[0] = duk_hex_enctab[src[i]];
- q16[1] = duk_hex_enctab[src[i + 1]];
- q16[2] = duk_hex_enctab[src[i + 2]];
- q16[3] = duk_hex_enctab[src[i + 3]];
- q16 += 4;
- }
- q = (duk_uint8_t *) q16;
-
-#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
- if (shift_dst) {
- q--;
- DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe);
- DUK_ASSERT(dst + 2 * len_safe == q);
- }
-#endif
-
- for (; i < src_len; i++) {
- x = src[i];
- *q++ = duk_lc_digits[x >> 4];
- *q++ = duk_lc_digits[x & 0x0f];
- }
-
- return q;
-}
-#else /* DUK_USE_HEX_FASTPATH */
-DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
- const duk_uint8_t *p;
- const duk_uint8_t *p_end;
- duk_uint8_t *q;
- duk_small_uint_t x;
-
- p = src;
- p_end = src + src_len;
- q = dst;
- while (p != p_end) {
- x = *p++;
- *q++ = duk_lc_digits[x >> 4];
- *q++ = duk_lc_digits[x & 0x0f];
- }
-
- return q;
-}
-#endif /* DUK_USE_HEX_FASTPATH */
-
-DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) {
- duk_hthread *thr;
- duk_uint8_t *q;
- duk_size_t space;
-
- thr = js_ctx->thr;
-
- DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
- DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
-
- /* Buffer values are encoded in (lowercase) hex to make the
- * binary data readable. Base64 or similar would be more
- * compact but less readable, and the point of JX/JC
- * variants is to be as useful to a programmer as possible.
- */
-
- /* The #ifdef clutter here needs to handle the three cases:
- * (1) JX+JC, (2) JX only, (3) JC only.
- */
-
- /* Note: space must cater for both JX and JC. */
- space = 9 + buf_len * 2 + 2;
- DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL);
- DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */
- q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
-
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- if (js_ctx->flag_ext_custom)
-#endif
-#if defined(DUK_USE_JX)
- {
- *q++ = DUK_ASC_PIPE;
- q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
- *q++ = DUK_ASC_PIPE;
-
- }
-#endif
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- else
-#endif
-#if defined(DUK_USE_JC)
- {
- DUK_ASSERT(js_ctx->flag_ext_compatible);
- DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */
- q += 9;
- q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
- *q++ = DUK_ASC_DOUBLEQUOTE;
- *q++ = DUK_ASC_RCURLY;
- }
-#endif
-
- DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
-}
-
-DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
- duk__enc_buffer_data(js_ctx,
- (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
- (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
-}
-#endif /* DUK_USE_JX || DUK_USE_JC */
-
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
- char buf[64]; /* XXX: how to figure correct size? */
- const char *fmt;
-
- DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
- DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
-
- DUK_MEMZERO(buf, sizeof(buf));
-
- /* The #ifdef clutter here needs to handle the three cases:
- * (1) JX+JC, (2) JX only, (3) JC only.
- */
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- if (js_ctx->flag_ext_custom)
-#endif
-#if defined(DUK_USE_JX)
- {
- fmt = ptr ? "(%p)" : "(null)";
- }
-#endif
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- else
-#endif
-#if defined(DUK_USE_JC)
- {
- DUK_ASSERT(js_ctx->flag_ext_compatible);
- fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
- }
-#endif
-
- /* When ptr == NULL, the format argument is unused. */
- DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */
- DUK__EMIT_CSTR(js_ctx, buf);
-}
-#endif /* DUK_USE_JX || DUK_USE_JC */
-
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-DUK_LOCAL void duk__enc_bufferobject(duk_json_enc_ctx *js_ctx, duk_hbufferobject *h_bufobj) {
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- if (h_bufobj->buf == NULL || !DUK_HBUFFEROBJECT_VALID_SLICE(h_bufobj)) {
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
- } else {
- /* Handle both full and partial slice (as long as covered). */
- duk__enc_buffer_data(js_ctx,
- (duk_uint8_t *) DUK_HBUFFEROBJECT_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
- (duk_size_t) h_bufobj->length);
- }
-}
-#endif /* DUK_USE_JX || DUK_USE_JC */
-
-/* Indent helper. Calling code relies on js_ctx->recursion_depth also being
- * directly related to indent depth.
- */
-#if defined(DUK_USE_PREFER_SIZE)
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
- DUK_ASSERT(js_ctx->h_gap != NULL);
- DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
-
- DUK__EMIT_1(js_ctx, 0x0a);
- while (depth-- > 0) {
- DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap);
- }
-}
-#else /* DUK_USE_PREFER_SIZE */
-DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
- const duk_uint8_t *gap_data;
- duk_size_t gap_len;
- duk_size_t avail_bytes; /* bytes of indent available for copying */
- duk_size_t need_bytes; /* bytes of indent still needed */
- duk_uint8_t *p_start;
- duk_uint8_t *p;
-
- DUK_ASSERT(js_ctx->h_gap != NULL);
- DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
-
- DUK__EMIT_1(js_ctx, 0x0a);
- if (DUK_UNLIKELY(depth == 0)) {
- return;
- }
-
- /* To handle deeper indents efficiently, make use of copies we've
- * already emitted. In effect we can emit a sequence of 1, 2, 4,
- * 8, etc copies, and then finish the last run. Byte counters
- * avoid multiply with gap_len on every loop.
- */
-
- gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap);
- gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap);
- DUK_ASSERT(gap_len > 0);
-
- need_bytes = gap_len * depth;
- p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes);
- p_start = p;
-
- DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len);
- p += gap_len;
- avail_bytes = gap_len;
- DUK_ASSERT(need_bytes >= gap_len);
- need_bytes -= gap_len;
-
- while (need_bytes >= avail_bytes) {
- DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes);
- p += avail_bytes;
- need_bytes -= avail_bytes;
- avail_bytes <<= 1;
- }
-
- DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */
- DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes);
- p += need_bytes;
- /*avail_bytes += need_bytes*/
-
- DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p);
-}
-#endif /* DUK_USE_PREFER_SIZE */
-
-/* Shared entry handling for object/array serialization. */
-DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hobject *h_target;
- duk_uint_fast32_t i, n;
-
- *entry_top = duk_get_top(ctx);
-
- duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
-
- /* Loop check using a hybrid approach: a fixed-size visited[] array
- * with overflow in a loop check object.
- */
-
- h_target = duk_get_hobject(ctx, -1); /* object or array */
- DUK_ASSERT(h_target != NULL);
-
- n = js_ctx->recursion_depth;
- if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
- n = DUK_JSON_ENC_LOOPARRAY;
- }
- for (i = 0; i < n; i++) {
- if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
- DUK_DD(DUK_DDPRINT("slow path loop detect"));
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
- }
- }
- if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
- js_ctx->visiting[js_ctx->recursion_depth] = h_target;
- } else {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_dup_top(ctx); /* -> [ ... voidp voidp ] */
- if (duk_has_prop(ctx, js_ctx->idx_loop)) {
- DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
- }
- duk_push_true(ctx); /* -> [ ... voidp true ] */
- duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
- }
-
- /* C recursion check. */
-
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
- DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
- if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONENC_RECLIMIT);
- }
- js_ctx->recursion_depth++;
-
- DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
-}
-
-/* Shared exit handling for object/array serialization. */
-DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hobject *h_target;
-
- /* C recursion check. */
-
- DUK_ASSERT(js_ctx->recursion_depth > 0);
- DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
- js_ctx->recursion_depth--;
-
- /* Loop check. */
-
- h_target = duk_get_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */
- DUK_ASSERT(h_target != NULL);
-
- if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
- /* Previous entry was inside visited[], nothing to do. */
- } else {
- duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
- duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
- }
-
- /* Restore stack top after unbalanced code paths. */
- duk_set_top(ctx, *entry_top);
-
- DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
- (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
-}
-
-/* The JO(value) operation: encode object.
- *
- * Stack policy: [ object ] -> [ object ].
- */
-DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hstring *h_key;
- duk_idx_t entry_top;
- duk_idx_t idx_obj;
- duk_idx_t idx_keys;
- duk_bool_t emitted;
- duk_uarridx_t arr_len, i;
- duk_size_t prev_size;
-
- DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk__enc_objarr_entry(js_ctx, &entry_top);
-
- idx_obj = entry_top - 1;
-
- if (js_ctx->idx_proplist >= 0) {
- idx_keys = js_ctx->idx_proplist;
- } else {
- /* XXX: would be nice to enumerate an object at specified index */
- duk_dup(ctx, idx_obj);
- (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
- idx_keys = duk_require_normalize_index(ctx, -1);
- /* leave stack unbalanced on purpose */
- }
-
- DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
- (long) idx_keys, (duk_tval *) duk_get_tval(ctx, idx_keys)));
-
- /* Steps 8-10 have been merged to avoid a "partial" variable. */
-
- DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
-
- /* XXX: keys is an internal object with all keys to be processed
- * in its (gapless) array part. Because nobody can touch the keys
- * object, we could iterate its array part directly (keeping in mind
- * that it can be reallocated).
- */
-
- arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_keys);
- emitted = 0;
- for (i = 0; i < arr_len; i++) {
- duk_get_prop_index(ctx, idx_keys, i); /* -> [ ... key ] */
-
- DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
- (duk_tval *) duk_get_tval(ctx, idx_obj),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- h_key = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_key != NULL);
-
- prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
- if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
- duk__enc_key_autoquote(js_ctx, h_key);
- DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
- } else {
- duk__enc_key_autoquote(js_ctx, h_key);
- DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
- }
-
- /* [ ... key ] */
-
- if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_obj) == 0)) {
- /* Value would yield 'undefined', so skip key altogether.
- * Side effects have already happened.
- */
- DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
- } else {
- DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
- emitted = 1;
- }
-
- /* [ ... ] */
- }
-
- if (emitted) {
- DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
- DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
- if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
- DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
- }
- }
- DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
-
- duk__enc_objarr_exit(js_ctx, &entry_top);
-
- DUK_ASSERT_TOP(ctx, entry_top);
-}
-
-/* The JA(value) operation: encode array.
- *
- * Stack policy: [ array ] -> [ array ].
- */
-DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_idx_t entry_top;
- duk_idx_t idx_arr;
- duk_bool_t emitted;
- duk_uarridx_t i, arr_len;
-
- DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk__enc_objarr_entry(js_ctx, &entry_top);
-
- idx_arr = entry_top - 1;
-
- /* Steps 8-10 have been merged to avoid a "partial" variable. */
-
- DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
-
- arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr);
- emitted = 0;
- for (i = 0; i < arr_len; i++) {
- DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_arr),
- (long) i, (long) arr_len));
-
- if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
- DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
- }
-
- /* XXX: duk_push_uint_string() */
- duk_push_uint(ctx, (duk_uint_t) i);
- duk_to_string(ctx, -1); /* -> [ ... key ] */
-
- /* [ ... key ] */
-
- if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_arr) == 0)) {
- /* Value would normally be omitted, replace with 'null'. */
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
- } else {
- ;
- }
-
- /* [ ... ] */
-
- DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
- emitted = 1;
- }
-
- if (emitted) {
- DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
- DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
- if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
- DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
- }
- }
- DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
-
- duk__enc_objarr_exit(js_ctx, &entry_top);
-
- DUK_ASSERT_TOP(ctx, entry_top);
-}
-
-/* The Str(key, holder) operation.
- *
- * Stack policy: [ ... key ] -> [ ... ]
- */
-DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
- duk_context *ctx = (duk_context *) js_ctx->thr;
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
- duk_tval *tv;
- duk_tval *tv_holder;
- duk_tval *tv_key;
- duk_small_int_t c;
-
- DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
- (long) idx_holder, (duk_tval *) duk_get_tval(ctx, idx_holder),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- DUK_UNREF(thr);
-
- tv_holder = DUK_GET_TVAL_POSIDX(ctx, idx_holder);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
- tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
- (void) duk_hobject_getprop(thr, tv_holder, tv_key);
-
- /* -> [ ... key val ] */
-
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
-
- h = duk_get_hobject_or_lfunc_coerce(ctx, -1);
- if (h != NULL) {
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_TO_JSON);
- h = duk_get_hobject_or_lfunc_coerce(ctx, -1); /* toJSON() can also be a lightfunc */
-
- if (h != NULL && DUK_HOBJECT_IS_CALLABLE(h)) {
- DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
- /* XXX: duk_dup_unvalidated(ctx, -2) etc. */
- duk_dup(ctx, -2); /* -> [ ... key val toJSON val ] */
- duk_dup(ctx, -4); /* -> [ ... key val toJSON val key ] */
- duk_call_method(ctx, 1); /* -> [ ... key val val' ] */
- duk_remove(ctx, -2); /* -> [ ... key val' ] */
- } else {
- duk_pop(ctx); /* -> [ ... key val ] */
- }
- }
-
- /* [ ... key val ] */
-
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
-
- if (js_ctx->h_replacer) {
- /* XXX: Here a "slice copy" would be useful. */
- DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
- duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
- duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */
- duk_dup(ctx, -4); /* -> [ ... key val replacer holder key ] */
- duk_dup(ctx, -4); /* -> [ ... key val replacer holder key val ] */
- duk_call_method(ctx, 2); /* -> [ ... key val val' ] */
- duk_remove(ctx, -2); /* -> [ ... key val' ] */
- }
-
- /* [ ... key val ] */
-
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
-
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
- if (DUK_TVAL_IS_OBJECT(tv)) {
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- duk_hbufferobject *h_bufobj;
- h_bufobj = (duk_hbufferobject *) h;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- /* Conceptually we'd extract the plain underlying buffer
- * or its slice and then do a type mask check below to
- * see if we should reject it. Do the mask check here
- * instead to avoid making a copy of the buffer slice.
- */
-
- if (js_ctx->mask_for_undefined & DUK_TYPE_MASK_BUFFER) {
- DUK_DDD(DUK_DDDPRINT("-> bufferobject (-> plain buffer) will result in undefined (type mask check)"));
- goto pop2_undef;
- }
- DUK_DDD(DUK_DDDPRINT("-> bufferobject won't result in undefined, encode directly"));
- duk__enc_bufferobject(js_ctx, h_bufobj);
- goto pop2_emitted;
-#else
- DUK_DDD(DUK_DDDPRINT("no JX/JC support, bufferobject/buffer will always result in undefined"));
- goto pop2_undef;
-#endif
- } else {
- c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
- switch ((int) c) {
- case DUK_HOBJECT_CLASS_NUMBER: {
- DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
- duk_to_number(ctx, -1);
- /* The coercion potentially invokes user .valueOf() and .toString()
- * but can't result in a function value because [[DefaultValue]] would
- * reject such a result: test-dev-json-stringify-coercion-1.js.
- */
- DUK_ASSERT(!duk_is_callable(ctx, -1));
- break;
- }
- case DUK_HOBJECT_CLASS_STRING: {
- DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
- duk_to_string(ctx, -1);
- /* Same coercion behavior as for Number. */
- DUK_ASSERT(!duk_is_callable(ctx, -1));
- break;
- }
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- case DUK_HOBJECT_CLASS_POINTER:
-#endif
- case DUK_HOBJECT_CLASS_BOOLEAN: {
- DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- duk_remove(ctx, -2);
- break;
- }
- default: {
- /* Normal object which doesn't get automatically coerced to a
- * primitive value. Functions are checked for specially. The
- * primitive value coercions for Number, String, Pointer, and
- * Boolean can't result in functions so suffices to check here.
- */
- DUK_ASSERT(h != NULL);
- if (DUK_HOBJECT_IS_CALLABLE(h)) {
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
- DUK_JSON_FLAG_EXT_COMPATIBLE)) {
- /* We only get here when doing non-standard JSON encoding */
- DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
- DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
- goto pop2_emitted;
- } else {
- DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
- goto pop2_undef;
- }
-#else /* DUK_USE_JX || DUK_USE_JC */
- DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
- goto pop2_undef;
-#endif /* DUK_USE_JX || DUK_USE_JC */
- }
- }
- } /* end switch */
- }
- }
-
- /* [ ... key val ] */
-
- DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
-
- if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) {
- /* will result in undefined */
- DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
- goto pop2_undef;
- }
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
-
- switch (DUK_TVAL_GET_TAG(tv)) {
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- /* When JX/JC not in use, the type mask above will avoid this case if needed. */
- case DUK_TAG_UNDEFINED: {
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
- break;
- }
-#endif
- case DUK_TAG_NULL: {
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
- break;
- }
- case DUK_TAG_BOOLEAN: {
- DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
- DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
- break;
- }
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- /* When JX/JC not in use, the type mask above will avoid this case if needed. */
- case DUK_TAG_POINTER: {
- duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
- break;
- }
-#endif /* DUK_USE_JX || DUK_USE_JC */
- case DUK_TAG_STRING: {
- duk_hstring *h = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h != NULL);
-
- duk__enc_quote_string(js_ctx, h);
- break;
- }
- case DUK_TAG_OBJECT: {
- duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- /* Function values are handled completely above (including
- * coercion results):
- */
- DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h));
-
- if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
- duk__enc_array(js_ctx);
- } else {
- duk__enc_object(js_ctx);
- }
- break;
- }
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- /* When JX/JC not in use, the type mask above will avoid this case if needed. */
- case DUK_TAG_BUFFER: {
- duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
- break;
- }
-#endif /* DUK_USE_JX || DUK_USE_JC */
- case DUK_TAG_LIGHTFUNC: {
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- /* We only get here when doing non-standard JSON encoding */
- DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
-#else
- /* Standard JSON omits functions */
- DUK_UNREACHABLE();
-#endif
- break;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
- /* Number serialization has a significant impact relative to
- * other fast path code, so careful fast path for fastints.
- */
- duk__enc_fastint_tval(js_ctx, tv);
- break;
-#endif
- default: {
- /* number */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- /* XXX: A fast path for usual integers would be useful when
- * fastint support is not enabled.
- */
- duk__enc_double(js_ctx);
- break;
- }
- }
-
- pop2_emitted:
- duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
- return 1; /* emitted */
-
- pop2_undef:
- duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
- return 0; /* not emitted */
-}
-
-/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
-DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
- duk_hobject *h;
- duk_small_int_t c;
-
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_STRING(tv) || DUK_TVAL_IS_NUMBER(tv)) {
- return 1;
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
- if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) {
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
- * JSON.stringify() fast path
- *
- * Otherwise supports full JSON, JX, and JC features, but bails out on any
- * possible side effect which might change the value being serialized. The
- * fast path can take advantage of the fact that the value being serialized
- * is unchanged so that we can walk directly through property tables etc.
- */
-
-#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
-DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
- duk_uint_fast32_t i, n;
-
- DUK_DDD(DUK_DDDPRINT("stringify fast: %!T", tv));
-
- DUK_ASSERT(js_ctx != NULL);
- DUK_ASSERT(js_ctx->thr != NULL);
-
-#if 0 /* disabled for now */
- restart_match:
-#endif
-
- DUK_ASSERT(tv != NULL);
-
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED: {
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) {
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
- break;
- } else {
- goto emit_undefined;
- }
-#else
- goto emit_undefined;
-#endif
- }
- case DUK_TAG_NULL: {
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
- break;
- }
- case DUK_TAG_BOOLEAN: {
- DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
- DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
- break;
- }
- case DUK_TAG_STRING: {
- duk_hstring *h;
-
- h = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h != NULL);
- duk__enc_quote_string(js_ctx, h);
- break;
- }
- case DUK_TAG_OBJECT: {
- duk_hobject *obj;
- duk_tval *tv_val;
- duk_bool_t emitted = 0;
- duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
- c_func, c_bufobj, c_object;
-
- /* For objects JSON.stringify() only looks for own, enumerable
- * properties which is nice for the fast path here.
- *
- * For arrays JSON.stringify() uses [[Get]] so it will actually
- * inherit properties during serialization! This fast path
- * supports gappy arrays as long as there's no actual inherited
- * property (which might be a getter etc).
- *
- * Since recursion only happens for objects, we can have both
- * recursion and loop checks here. We use a simple, depth-limited
- * loop check in the fast path because the object-based tracking
- * is very slow (when tested, it accounted for 50% of fast path
- * execution time for input data with a lot of small objects!).
- */
-
- /* XXX: for real world code, could just ignore array inheritance
- * and only look at array own properties.
- */
-
- /* We rely on a few object flag / class number relationships here,
- * assert for them.
- */
-
- obj = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT_HOBJECT_VALID(obj);
-
- /* Once recursion depth is increased, exit path must decrease
- * it (though it's OK to abort the fast path).
- */
-
- DUK_ASSERT(js_ctx->recursion_depth >= 0);
- DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
- if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
- DUK_DD(DUK_DDPRINT("fast path recursion limit"));
- DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT);
- }
-
- for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) {
- if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) {
- DUK_DD(DUK_DDPRINT("fast path loop detect"));
- DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT);
- }
- }
-
- /* Guaranteed by recursion_limit setup so we don't have to
- * check twice.
- */
- DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY);
- js_ctx->visiting[js_ctx->recursion_depth] = obj;
- js_ctx->recursion_depth++;
-
- /* If object has a .toJSON() property, we can't be certain
- * that it wouldn't mutate any value arbitrarily, so bail
- * out of the fast path.
- *
- * If an object is a Proxy we also can't avoid side effects
- * so abandon.
- */
- /* XXX: non-callable .toJSON() doesn't need to cause an abort
- * but does at the moment, probably not worth fixing.
- */
- if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
- DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
- DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
- goto abort_fastpath;
- }
-
- /* We could use a switch-case for the class number but it turns out
- * a small if-else ladder on class masks is better. The if-ladder
- * should be in order of relevancy.
- */
-
- /* XXX: move masks to js_ctx? they don't change during one
- * fast path invocation.
- */
- DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31);
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (js_ctx->flag_ext_custom_or_compatible) {
- c_all = DUK_HOBJECT_CMASK_ALL;
- c_array = DUK_HOBJECT_CMASK_ARRAY;
- c_unbox = DUK_HOBJECT_CMASK_NUMBER |
- DUK_HOBJECT_CMASK_STRING |
- DUK_HOBJECT_CMASK_BOOLEAN |
- DUK_HOBJECT_CMASK_POINTER;
- c_func = DUK_HOBJECT_CMASK_FUNCTION;
- c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
- c_undef = 0;
- c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
- }
- else
-#endif
- {
- c_all = DUK_HOBJECT_CMASK_ALL;
- c_array = DUK_HOBJECT_CMASK_ARRAY;
- c_unbox = DUK_HOBJECT_CMASK_NUMBER |
- DUK_HOBJECT_CMASK_STRING |
- DUK_HOBJECT_CMASK_BOOLEAN;
- c_func = 0;
- c_bufobj = 0;
- c_undef = DUK_HOBJECT_CMASK_FUNCTION |
- DUK_HOBJECT_CMASK_POINTER |
- DUK_HOBJECT_CMASK_ALL_BUFFEROBJECTS;
- c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef);
- }
-
- c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj);
- if (c_bit & c_object) {
- /* All other object types. */
- DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
-
- /* A non-Array object should not have an array part in practice.
- * But since it is supported internally (and perhaps used at some
- * point), check and abandon if that's the case.
- */
- if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
- DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path"));
- goto abort_fastpath;
- }
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) {
- duk_hstring *k;
- duk_size_t prev_size;
-
- k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i);
- if (!k) {
- continue;
- }
- if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) {
- continue;
- }
- if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) {
- /* Getter might have arbitrary side effects,
- * so bail out.
- */
- DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path"));
- goto abort_fastpath;
- }
- if (DUK_HSTRING_HAS_INTERNAL(k)) {
- continue;
- }
-
- tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i);
-
- prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
- if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
- duk__enc_key_autoquote(js_ctx, k);
- DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
- } else {
- duk__enc_key_autoquote(js_ctx, k);
- DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
- }
-
- if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
- DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon"));
- DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
- } else {
- DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
- emitted = 1;
- }
- }
-
- /* If any non-Array value had enumerable virtual own
- * properties, they should be serialized here. Standard
- * types don't.
- */
-
- if (emitted) {
- DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
- DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
- if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
- DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
- }
- }
- DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
- } else if (c_bit & c_array) {
- duk_uint_fast32_t arr_len;
- duk_uint_fast32_t asize;
-
- DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
-
- /* Assume arrays are dense in the fast path. */
- if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
- DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path"));
- goto abort_fastpath;
- }
-
- arr_len = (duk_uint_fast32_t) duk_hobject_get_length(js_ctx->thr, obj);
- asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
- if (arr_len > asize) {
- /* Array length is larger than 'asize'. This shouldn't
- * happen in practice. Bail out just in case.
- */
- DUK_DD(DUK_DDPRINT("arr_len > asize, abort fast path"));
- goto abort_fastpath;
- }
- /* Array part may be larger than 'length'; if so, iterate
- * only up to array 'length'.
- */
- for (i = 0; i < arr_len; i++) {
- DUK_ASSERT(i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj));
-
- tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
-
- if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
- }
-
- if (DUK_UNLIKELY(DUK_TVAL_IS_UNUSED(tv_val))) {
- /* Gap in array; check for inherited property,
- * bail out if one exists. This should be enough
- * to support gappy arrays for all practical code.
- */
- duk_hstring *h_tmp;
- duk_bool_t has_inherited;
-
- /* XXX: refactor into an internal helper, pretty awkward */
- duk_push_uint((duk_context *) js_ctx->thr, (duk_uint_t) i);
- h_tmp = duk_to_hstring((duk_context *) js_ctx->thr, -1);
- DUK_ASSERT(h_tmp != NULL);
- has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
- duk_pop((duk_context *) js_ctx->thr);
-
- if (has_inherited) {
- DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
- goto abort_fastpath;
- }
-
- /* Ordinary gap, undefined encodes to 'null' in
- * standard JSON (and no JX/JC support here now).
- */
- DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
- } else {
- if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
- DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
- }
- }
- DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
- emitted = 1;
- }
-
- if (emitted) {
- DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
- DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
- if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
- DUK_ASSERT(js_ctx->recursion_depth >= 1);
- duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
- }
- }
- DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
- } else if (c_bit & c_unbox) {
- /* Certain boxed types are required to go through
- * automatic unboxing. Rely on internal value being
- * sane (to avoid infinite recursion).
- */
-#if 1
- /* The code below is incorrect if .toString() or .valueOf() have
- * have been overridden. The correct approach would be to look up
- * the method(s) and if they resolve to the built-in function we
- * can safely bypass it and look up the internal value directly.
- * Unimplemented for now, abort fast path for boxed values.
- */
- goto abort_fastpath;
-#else /* disabled */
- /* Disabled until fixed, see above. */
- duk_tval *tv_internal;
-
- DUK_DD(DUK_DDPRINT("auto unboxing in fast path"));
-
- tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj);
- DUK_ASSERT(tv_internal != NULL);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) ||
- DUK_TVAL_IS_NUMBER(tv_internal) ||
- DUK_TVAL_IS_BOOLEAN(tv_internal) ||
- DUK_TVAL_IS_POINTER(tv_internal));
-
- tv = tv_internal;
- DUK_ASSERT(js_ctx->recursion_depth > 0);
- js_ctx->recursion_depth--; /* required to keep recursion depth correct */
- goto restart_match;
-#endif /* disabled */
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- } else if (c_bit & c_func) {
- DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
- } else if (c_bit & c_bufobj) {
- duk__enc_bufferobject(js_ctx, (duk_hbufferobject *) obj);
-#endif
- } else {
- DUK_ASSERT((c_bit & c_undef) != 0);
-
- /* Must decrease recursion depth before returning. */
- DUK_ASSERT(js_ctx->recursion_depth > 0);
- DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
- js_ctx->recursion_depth--;
- goto emit_undefined;
- }
-
- DUK_ASSERT(js_ctx->recursion_depth > 0);
- DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
- js_ctx->recursion_depth--;
- break;
- }
- case DUK_TAG_BUFFER: {
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (js_ctx->flag_ext_custom_or_compatible) {
- duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
- break;
- } else {
- goto emit_undefined;
- }
-#else
- goto emit_undefined;
-#endif
- }
- case DUK_TAG_POINTER: {
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (js_ctx->flag_ext_custom_or_compatible) {
- duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
- break;
- } else {
- goto emit_undefined;
- }
-#else
- goto emit_undefined;
-#endif
- }
- case DUK_TAG_LIGHTFUNC: {
- /* A lightfunc might also inherit a .toJSON() so just bail out. */
- /* XXX: Could just lookup .toJSON() and continue in fast path,
- * as it would almost never be defined.
- */
- DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path"));
- goto abort_fastpath;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT: {
- /* Number serialization has a significant impact relative to
- * other fast path code, so careful fast path for fastints.
- */
- duk__enc_fastint_tval(js_ctx, tv);
- break;
- }
-#endif
- default: {
- /* XXX: A fast path for usual integers would be useful when
- * fastint support is not enabled.
- */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
-
- /* XXX: Stack discipline is annoying, could be changed in numconv. */
- duk_push_tval((duk_context *) js_ctx->thr, tv);
- duk__enc_double(js_ctx);
- duk_pop((duk_context *) js_ctx->thr);
-
-#if 0
- /* Could also rely on native sprintf(), but it will handle
- * values like NaN, Infinity, -0, exponent notation etc in
- * a JSON-incompatible way.
- */
- duk_double_t d;
- char buf[64];
-
- DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
- d = DUK_TVAL_GET_DOUBLE(tv);
- DUK_SPRINTF(buf, "%lg", d);
- DUK__EMIT_CSTR(js_ctx, buf);
-#endif
- }
- }
- return 1; /* not undefined */
-
- emit_undefined:
- return 0; /* value was undefined/unsupported */
-
- abort_fastpath:
- /* Error message doesn't matter: the error is ignored anyway. */
- DUK_DD(DUK_DDPRINT("aborting fast path"));
- DUK_ERROR_INTERNAL_DEFMSG(js_ctx->thr);
- return 0; /* unreachable */
-}
-
-DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx) {
- duk_json_enc_ctx *js_ctx;
- duk_tval *tv;
-
- DUK_ASSERT(ctx != NULL);
- tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
- DUK_ASSERT(DUK_TVAL_IS_POINTER(tv));
- js_ctx = (duk_json_enc_ctx *) DUK_TVAL_GET_POINTER(tv);
- DUK_ASSERT(js_ctx != NULL);
-
- tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
- if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
- DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
- return DUK_RET_ERROR; /* error message doesn't matter, ignored anyway */
- }
-
- return 0;
-}
-#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
-
-/*
- * Top level wrappers
- */
-
-DUK_INTERNAL
-void duk_bi_json_parse_helper(duk_context *ctx,
- duk_idx_t idx_value,
- duk_idx_t idx_reviver,
- duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_json_dec_ctx js_ctx_alloc;
- duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
- duk_hstring *h_text;
-#ifdef DUK_USE_ASSERTIONS
- duk_idx_t entry_top = duk_get_top(ctx);
-#endif
-
- /* negative top-relative indices not allowed now */
- DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
- DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
-
- DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_reviver),
- (unsigned long) flags,
- (long) duk_get_top(ctx)));
-
- DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
- js_ctx->thr = thr;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- /* nothing now */
-#endif
- js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT;
- DUK_ASSERT(js_ctx->recursion_depth == 0);
-
- /* Flag handling currently assumes that flags are consistent. This is OK
- * because the call sites are now strictly controlled.
- */
-
- js_ctx->flags = flags;
-#if defined(DUK_USE_JX)
- js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
-#endif
-#if defined(DUK_USE_JC)
- js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
-#endif
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
-#endif
-
- h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place */
- DUK_ASSERT(h_text != NULL);
-
- /* JSON parsing code is allowed to read [p_start,p_end]: p_end is
- * valid and points to the string NUL terminator (which is always
- * guaranteed for duk_hstrings.
- */
- js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
- js_ctx->p = js_ctx->p_start;
- js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
- DUK_HSTRING_GET_BYTELEN(h_text);
- DUK_ASSERT(*(js_ctx->p_end) == 0x00);
-
- duk__dec_value(js_ctx); /* -> [ ... value ] */
-
- /* Trailing whitespace has been eaten by duk__dec_value(), so if
- * we're not at end of input here, it's a SyntaxError.
- */
-
- if (js_ctx->p != js_ctx->p_end) {
- duk__dec_syntax_error(js_ctx);
- }
-
- if (duk_is_callable(ctx, idx_reviver)) {
- DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_reviver)));
-
- js_ctx->idx_reviver = idx_reviver;
-
- duk_push_object(ctx);
- duk_dup(ctx, -2); /* -> [ ... val root val ] */
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
-
- DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
- duk_remove(ctx, -2); /* -> [ ... val' ] */
- } else {
- DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_reviver)));
- }
-
- /* Final result is at stack top. */
-
- DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_reviver),
- (unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) duk_get_top(ctx)));
-
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
-}
-
-DUK_INTERNAL
-void duk_bi_json_stringify_helper(duk_context *ctx,
- duk_idx_t idx_value,
- duk_idx_t idx_replacer,
- duk_idx_t idx_space,
- duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_json_enc_ctx js_ctx_alloc;
- duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
- duk_hobject *h;
- duk_idx_t idx_holder;
- duk_idx_t entry_top;
-
- /* negative top-relative indices not allowed now */
- DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
- DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0);
- DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
-
- DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_replacer),
- (duk_tval *) duk_get_tval(ctx, idx_space),
- (unsigned long) flags,
- (long) duk_get_top(ctx)));
-
- entry_top = duk_get_top(ctx);
-
- /*
- * Context init
- */
-
- DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
- js_ctx->thr = thr;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- js_ctx->h_replacer = NULL;
- js_ctx->h_gap = NULL;
-#endif
- js_ctx->idx_proplist = -1;
-
- /* Flag handling currently assumes that flags are consistent. This is OK
- * because the call sites are now strictly controlled.
- */
-
- js_ctx->flags = flags;
- js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
- js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
-#ifdef DUK_USE_JX
- js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
-#endif
-#ifdef DUK_USE_JC
- js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
-#endif
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
-#endif
-
- /* The #ifdef clutter here handles the JX/JC enable/disable
- * combinations properly.
- */
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
-#if defined(DUK_USE_JX)
- if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
- js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED;
- js_ctx->stridx_custom_nan = DUK_STRIDX_NAN;
- js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY;
- js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY;
- js_ctx->stridx_custom_function =
- (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ?
- DUK_STRIDX_JSON_EXT_FUNCTION2 :
- DUK_STRIDX_JSON_EXT_FUNCTION1;
- }
-#endif /* DUK_USE_JX */
-#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
- else
-#endif /* DUK_USE_JX && DUK_USE_JC */
-#if defined(DUK_USE_JC)
- if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) {
- js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED;
- js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN;
- js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF;
- js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF;
- js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1;
- }
-#endif /* DUK_USE_JC */
-#endif /* DUK_USE_JX || DUK_USE_JC */
-
-#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
- if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
- DUK_JSON_FLAG_EXT_COMPATIBLE)) {
- DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */
- }
- else
-#endif /* DUK_USE_JX || DUK_USE_JC */
- {
- js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
- DUK_TYPE_MASK_POINTER |
- DUK_TYPE_MASK_BUFFER |
- DUK_TYPE_MASK_LIGHTFUNC;
- }
-
- DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
-
- js_ctx->idx_loop = duk_push_object_internal(ctx);
- DUK_ASSERT(js_ctx->idx_loop >= 0);
-
- /* [ ... buf loop ] */
-
- /*
- * Process replacer/proplist (2nd argument to JSON.stringify)
- */
-
- h = duk_get_hobject(ctx, idx_replacer);
- if (h != NULL) {
- if (DUK_HOBJECT_IS_CALLABLE(h)) {
- js_ctx->h_replacer = h;
- } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
- /* Here the specification requires correct array index enumeration
- * which is a bit tricky for sparse arrays (it is handled by the
- * enum setup code). We now enumerate ancestors too, although the
- * specification is not very clear on whether that is required.
- */
-
- duk_uarridx_t plist_idx = 0;
- duk_small_uint_t enum_flags;
-
- js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */
-
- enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
- DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
- duk_enum(ctx, idx_replacer, enum_flags);
- while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
- /* [ ... proplist enum_obj key val ] */
- if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
- /* XXX: duplicates should be eliminated here */
- DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_to_string(ctx, -1); /* extra coercion of strings is OK */
- duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
- plist_idx++;
- duk_pop(ctx);
- } else {
- DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_pop_2(ctx);
- }
- }
- duk_pop(ctx); /* pop enum */
-
- /* [ ... proplist ] */
- }
- }
-
- /* [ ... buf loop (proplist) ] */
-
- /*
- * Process space (3rd argument to JSON.stringify)
- */
-
- h = duk_get_hobject(ctx, idx_space);
- if (h != NULL) {
- int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
- if (c == DUK_HOBJECT_CLASS_NUMBER) {
- duk_to_number(ctx, idx_space);
- } else if (c == DUK_HOBJECT_CLASS_STRING) {
- duk_to_string(ctx, idx_space);
- }
- }
-
- if (duk_is_number(ctx, idx_space)) {
- duk_small_int_t nspace;
- /* spaces[] must be static to allow initializer with old compilers like BCC */
- static const char spaces[10] = {
- DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
- DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
- DUK_ASC_SPACE, DUK_ASC_SPACE
- }; /* XXX: helper */
-
- /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
- nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/);
- DUK_ASSERT(nspace >= 0 && nspace <= 10);
-
- duk_push_lstring(ctx, spaces, (duk_size_t) nspace);
- js_ctx->h_gap = duk_get_hstring(ctx, -1);
- DUK_ASSERT(js_ctx->h_gap != NULL);
- } else if (duk_is_string(ctx, idx_space)) {
- /* XXX: substring in-place at idx_place? */
- duk_dup(ctx, idx_space);
- duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */
- js_ctx->h_gap = duk_get_hstring(ctx, -1);
- DUK_ASSERT(js_ctx->h_gap != NULL);
- } else {
- /* nop */
- }
-
- if (js_ctx->h_gap != NULL) {
- /* if gap is empty, behave as if not given at all */
- if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
- js_ctx->h_gap = NULL;
- }
- }
-
- /* [ ... buf loop (proplist) (gap) ] */
-
- /*
- * Fast path: assume no mutation, iterate object property tables
- * directly; bail out if that assumption doesn't hold.
- */
-
-#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
- if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
- js_ctx->idx_proplist == -1) { /* proplist is very rare */
- duk_int_t pcall_rc;
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_small_uint_t prev_mark_and_sweep_base_flags;
-#endif
-
- DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
-
- /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[]
- * array so we don't need two counter checks in the fast path. The
- * slow path has a much larger recursion limit which we'll use if
- * necessary.
- */
- DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY);
- js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY;
- DUK_ASSERT(js_ctx->recursion_depth == 0);
-
- /* Execute the fast path in a protected call. If any error is thrown,
- * fall back to the slow path. This includes e.g. recursion limit
- * because the fast path has a smaller recursion limit (and simpler,
- * limited loop detection).
- */
-
- duk_push_pointer(ctx, (void *) js_ctx);
- duk_dup(ctx, idx_value);
-
-#if defined(DUK_USE_MARK_AND_SWEEP)
- /* Must prevent finalizers which may have arbitrary side effects. */
- prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
- thr->heap->mark_and_sweep_base_flags |=
- DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
- DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */
-#endif
-
- pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, 2 /*nargs*/, 0 /*nret*/);
-
-#if defined(DUK_USE_MARK_AND_SWEEP)
- thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
-#endif
- if (pcall_rc == DUK_EXEC_SUCCESS) {
- DUK_DD(DUK_DDPRINT("fast path successful"));
- DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
- goto replace_finished;
- }
-
- /* We come here for actual aborts (like encountering .toJSON())
- * but also for recursion/loop errors. Bufwriter size can be
- * kept because we'll probably need at least as much as we've
- * allocated so far.
- */
- DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead"));
- DUK_BW_RESET_SIZE(thr, &js_ctx->bw);
- js_ctx->recursion_depth = 0;
- }
-#endif
-
- /*
- * Create wrapper object and serialize
- */
-
- idx_holder = duk_push_object(ctx);
- duk_dup(ctx, idx_value);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_EMPTY_STRING);
-
- DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
- "proplist=%!T, gap=%!O, holder=%!T",
- (unsigned long) js_ctx->flags,
- (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
- (duk_heaphdr *) js_ctx->h_replacer,
- (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
- (duk_heaphdr *) js_ctx->h_gap,
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* serialize the wrapper with empty string key */
-
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
-
- /* [ ... buf loop (proplist) (gap) holder "" ] */
-
- js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT;
- DUK_ASSERT(js_ctx->recursion_depth == 0);
-
- if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
- /* Result is undefined. */
- duk_push_undefined(ctx);
- } else {
- /* Convert buffer to result string. */
- DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
- }
-
- DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
- "proplist=%!T, gap=%!O, holder=%!T",
- (unsigned long) js_ctx->flags,
- (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
- (duk_heaphdr *) js_ctx->h_replacer,
- (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
- (duk_heaphdr *) js_ctx->h_gap,
- (duk_tval *) duk_get_tval(ctx, idx_holder)));
-
- /* The stack has a variable shape here, so force it to the
- * desired one explicitly.
- */
-
-#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
- replace_finished:
-#endif
- duk_replace(ctx, entry_top);
- duk_set_top(ctx, entry_top + 1);
-
- DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
- "flags=0x%08lx, result=%!T, stack_top=%ld",
- (duk_tval *) duk_get_tval(ctx, idx_value),
- (duk_tval *) duk_get_tval(ctx, idx_replacer),
- (duk_tval *) duk_get_tval(ctx, idx_space),
- (unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) duk_get_top(ctx)));
-
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
-}
-
-/*
- * Entry points
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_context *ctx) {
- duk_bi_json_parse_helper(ctx,
- 0 /*idx_value*/,
- 1 /*idx_replacer*/,
- 0 /*flags*/);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
- duk_bi_json_stringify_helper(ctx,
- 0 /*idx_value*/,
- 1 /*idx_replacer*/,
- 2 /*idx_space*/,
- 0 /*flags*/);
- return 1;
-}
-
-#undef DUK__JSON_DECSTR_BUFSIZE
-#undef DUK__JSON_DECSTR_CHUNKSIZE
-#undef DUK__JSON_ENCSTR_CHUNKSIZE
-#undef DUK__JSON_STRINGIFY_BUFSIZE
-#undef DUK__JSON_MAX_ESC_LEN
-#line 1 "duk_bi_logger.c"
-/*
- * Logging support
- */
-
-/* include removed: duk_internal.h */
-
-/* 3-letter log level strings */
-DUK_LOCAL const duk_uint8_t duk__log_level_strings[] = {
- (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_C,
- (duk_uint8_t) DUK_ASC_UC_D, (duk_uint8_t) DUK_ASC_UC_B, (duk_uint8_t) DUK_ASC_UC_G,
- (duk_uint8_t) DUK_ASC_UC_I, (duk_uint8_t) DUK_ASC_UC_N, (duk_uint8_t) DUK_ASC_UC_F,
- (duk_uint8_t) DUK_ASC_UC_W, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_N,
- (duk_uint8_t) DUK_ASC_UC_E, (duk_uint8_t) DUK_ASC_UC_R, (duk_uint8_t) DUK_ASC_UC_R,
- (duk_uint8_t) DUK_ASC_UC_F, (duk_uint8_t) DUK_ASC_UC_T, (duk_uint8_t) DUK_ASC_UC_L
-};
-
-/* Constructor */
-DUK_INTERNAL duk_ret_t duk_bi_logger_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t nargs;
-
- /* Calling as a non-constructor is not meaningful. */
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- nargs = duk_get_top(ctx);
- duk_set_top(ctx, 1);
-
- duk_push_this(ctx);
-
- /* [ name this ] */
-
- if (nargs == 0) {
- /* Automatic defaulting of logger name from caller. This would
- * work poorly with tail calls, but constructor calls are currently
- * never tail calls, so tail calls are not an issue now.
- */
-
- if (thr->callstack_top >= 2) {
- duk_activation *act_caller = thr->callstack + thr->callstack_top - 2;
- duk_hobject *func_caller;
-
- func_caller = DUK_ACT_GET_FUNC(act_caller);
- if (func_caller) {
- /* Stripping the filename might be a good idea
- * ("/foo/bar/quux.js" -> logger name "quux"),
- * but now used verbatim.
- */
- duk_push_hobject(ctx, func_caller);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
- duk_replace(ctx, 0);
- }
- }
- }
- /* the stack is unbalanced here on purpose; we only rely on the
- * initial two values: [ name this ].
- */
-
- if (duk_is_string(ctx, 0)) {
- duk_dup(ctx, 0);
- duk_put_prop_stridx(ctx, 1, DUK_STRIDX_LC_N);
- } else {
- /* don't set 'n' at all, inherited value is used as name */
- }
-
- duk_compact(ctx, 1);
-
- return 0; /* keep default instance */
-}
-
-/* Default function to format objects. Tries to use toLogString() but falls
- * back to toString(). Any errors are propagated out without catching.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_fmt(duk_context *ctx) {
- if (duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_LOG_STRING)) {
- /* [ arg toLogString ] */
-
- duk_dup(ctx, 0);
- duk_call_method(ctx, 0);
-
- /* [ arg result ] */
- return 1;
- }
-
- /* [ arg undefined ] */
- duk_pop(ctx);
- duk_to_string(ctx, 0);
- return 1;
-}
-
-/* Default function to write a formatted log line. Writes to stderr,
- * appending a newline to the log line.
- *
- * The argument is a buffer whose visible size contains the log message.
- * This function should avoid coercing the buffer to a string to avoid
- * string table traffic.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) {
- const char *data;
- duk_size_t data_len;
-
- DUK_UNREF(ctx);
- DUK_UNREF(data);
- DUK_UNREF(data_len);
-
-#ifdef DUK_USE_FILE_IO
- data = (const char *) duk_require_buffer(ctx, 0, &data_len);
- DUK_FWRITE((const void *) data, 1, data_len, DUK_STDERR);
- DUK_FPUTC((int) '\n', DUK_STDERR);
- DUK_FFLUSH(DUK_STDERR);
-#else
- /* nop */
-#endif
- return 0;
-}
-
-/* Log frontend shared helper, magic value indicates log level. Provides
- * frontend functions: trace(), debug(), info(), warn(), error(), fatal().
- * This needs to have small footprint, reasonable performance, minimal
- * memory churn, etc.
- */
-DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_log_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_double_t now;
- duk_small_int_t entry_lev = duk_get_current_magic(ctx);
- duk_small_int_t logger_lev;
- duk_int_t nargs;
- duk_int_t i;
- duk_size_t tot_len;
- const duk_uint8_t *arg_str;
- duk_size_t arg_len;
- duk_uint8_t *buf, *p;
- const duk_uint8_t *q;
- duk_uint8_t date_buf[DUK_BI_DATE_ISO8601_BUFSIZE];
- duk_size_t date_len;
- duk_small_int_t rc;
-
- DUK_ASSERT(entry_lev >= 0 && entry_lev <= 5);
- DUK_UNREF(thr);
-
- /* XXX: sanitize to printable (and maybe ASCII) */
- /* XXX: better multiline */
-
- /*
- * Logger arguments are:
- *
- * magic: log level (0-5)
- * this: logger
- * stack: plain log args
- *
- * We want to minimize memory churn so a two-pass approach
- * is used: first pass formats arguments and computes final
- * string length, second pass copies strings either into a
- * pre-allocated and reused buffer (short messages) or into a
- * newly allocated fixed buffer. If the backend function plays
- * nice, it won't coerce the buffer to a string (and thus
- * intern it).
- */
-
- nargs = duk_get_top(ctx);
-
- /* [ arg1 ... argN this ] */
-
- /*
- * Log level check
- */
-
- duk_push_this(ctx);
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LC_L);
- logger_lev = (duk_small_int_t) duk_get_int(ctx, -1);
- if (entry_lev < logger_lev) {
- return 0;
- }
- /* log level could be popped but that's not necessary */
-
- now = DUK_USE_DATE_GET_NOW(ctx);
- duk_bi_date_format_timeval(now, date_buf);
- date_len = DUK_STRLEN((const char *) date_buf);
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LC_N);
- duk_to_string(ctx, -1);
- DUK_ASSERT(duk_is_string(ctx, -1));
-
- /* [ arg1 ... argN this loggerLevel loggerName ] */
-
- /*
- * Pass 1
- */
-
- /* Line format: <time> <entryLev> <loggerName>: <msg> */
-
- tot_len = 0;
- tot_len += 3 + /* separators: space, space, colon */
- 3 + /* level string */
- date_len + /* time */
- duk_get_length(ctx, -1); /* loggerName */
-
- for (i = 0; i < nargs; i++) {
- /* When formatting an argument to a string, errors may happen from multiple
- * causes. In general we want to catch obvious errors like a toLogString()
- * throwing an error, but we don't currently try to catch every possible
- * error. In particular, internal errors (like out of memory or stack) are
- * not caught. Also, we expect Error toString() to not throw an error.
- */
- if (duk_is_object(ctx, i)) {
- /* duk_pcall_prop() may itself throw an error, but we're content
- * in catching the obvious errors (like toLogString() throwing an
- * error).
- */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_FMT);
- duk_dup(ctx, i);
- /* [ arg1 ... argN this loggerLevel loggerName 'fmt' arg ] */
- /* call: this.fmt(arg) */
- rc = duk_pcall_prop(ctx, -5 /*obj_index*/, 1 /*nargs*/);
- if (rc) {
- /* Keep the error as the result (coercing it might fail below,
- * but we don't catch that now).
- */
- ;
- }
- duk_replace(ctx, i);
- }
- (void) duk_to_lstring(ctx, i, &arg_len);
- tot_len++; /* sep (even before first one) */
- tot_len += arg_len;
- }
-
- /*
- * Pass 2
- */
-
- /* XXX: There used to be a shared log buffer here, but it was removed
- * when dynamic buffer spare was removed. The problem with using
- * bufwriter is that, without the spare, the buffer gets passed on
- * as an argument to the raw() call so it'd need to be resized
- * (reallocated) anyway. If raw() call convention is changed, this
- * could be made more efficient.
- */
-
- buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, tot_len);
- DUK_ASSERT(buf != NULL);
- p = buf;
-
- DUK_MEMCPY((void *) p, (const void *) date_buf, (size_t) date_len);
- p += date_len;
- *p++ = (duk_uint8_t) DUK_ASC_SPACE;
-
- q = duk__log_level_strings + (entry_lev * 3);
- DUK_MEMCPY((void *) p, (const void *) q, (size_t) 3);
- p += 3;
-
- *p++ = (duk_uint8_t) DUK_ASC_SPACE;
-
- arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, -2, &arg_len);
- DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
- p += arg_len;
-
- *p++ = (duk_uint8_t) DUK_ASC_COLON;
-
- for (i = 0; i < nargs; i++) {
- *p++ = (duk_uint8_t) DUK_ASC_SPACE;
-
- arg_str = (const duk_uint8_t *) duk_get_lstring(ctx, i, &arg_len);
- DUK_ASSERT(arg_str != NULL);
- DUK_MEMCPY((void *) p, (const void *) arg_str, (size_t) arg_len);
- p += arg_len;
- }
- DUK_ASSERT(buf + tot_len == p);
-
- /* [ arg1 ... argN this loggerLevel loggerName buffer ] */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) && defined(DUK_USE_DEBUGGER_FWD_LOGGING)
- /* Do debugger forwarding before raw() because the raw() function
- * doesn't get the log level right now.
- */
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- const char *log_buf;
- duk_size_t sz_buf;
- log_buf = (const char *) duk_get_buffer(ctx, -1, &sz_buf);
- DUK_ASSERT(log_buf != NULL);
- duk_debug_write_notify(thr, DUK_DBG_CMD_LOG);
- duk_debug_write_int(thr, (duk_int32_t) entry_lev);
- duk_debug_write_string(thr, (const char *) log_buf, sz_buf);
- duk_debug_write_eom(thr);
- }
-#endif
-
- /* Call this.raw(msg); look up through the instance allows user to override
- * the raw() function in the instance or in the prototype for maximum
- * flexibility.
- */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_RAW);
- duk_dup(ctx, -2);
- /* [ arg1 ... argN this loggerLevel loggerName buffer 'raw' buffer ] */
- duk_call_prop(ctx, -6, 1); /* this.raw(buffer) */
-
- return 0;
-}
-#line 1 "duk_bi_math.c"
-/*
- * Math built-ins
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_MATH_BUILTIN)
-
-/*
- * Use static helpers which can work with math.h functions matching
- * the following signatures. This is not portable if any of these math
- * functions is actually a macro.
- *
- * Typing here is intentionally 'double' wherever values interact with
- * the standard library APIs.
- */
-
-typedef double (*duk__one_arg_func)(double);
-typedef double (*duk__two_arg_func)(double, double);
-
-DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk__two_arg_func min_max) {
- duk_idx_t n = duk_get_top(ctx);
- duk_idx_t i;
- duk_double_t res = initial;
- duk_double_t t;
-
- /*
- * Note: fmax() does not match the E5 semantics. E5 requires
- * that if -any- input to Math.max() is a NaN, the result is a
- * NaN. fmax() will return a NaN only if -both- inputs are NaN.
- * Same applies to fmin().
- *
- * Note: every input value must be coerced with ToNumber(), even
- * if we know the result will be a NaN anyway: ToNumber() may have
- * side effects for which even order of evaluation matters.
- */
-
- for (i = 0; i < n; i++) {
- t = duk_to_number(ctx, i);
- if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
- /* Note: not normalized, but duk_push_number() will normalize */
- res = (duk_double_t) DUK_DOUBLE_NAN;
- } else {
- res = (duk_double_t) min_max(res, (double) t);
- }
- }
-
- duk_push_number(ctx, res);
- return 1;
-}
-
-DUK_LOCAL double duk__fmin_fixed(double x, double y) {
- /* fmin() with args -0 and +0 is not guaranteed to return
- * -0 as Ecmascript requires.
- */
- if (x == 0 && y == 0) {
- /* XXX: what's the safest way of creating a negative zero? */
- if (DUK_SIGNBIT(x) != 0 || DUK_SIGNBIT(y) != 0) {
- return -0.0;
- } else {
- return +0.0;
- }
- }
-#ifdef DUK_USE_MATH_FMIN
- return DUK_FMIN(x, y);
-#else
- return (x < y ? x : y);
-#endif
-}
-
-DUK_LOCAL double duk__fmax_fixed(double x, double y) {
- /* fmax() with args -0 and +0 is not guaranteed to return
- * +0 as Ecmascript requires.
- */
- if (x == 0 && y == 0) {
- if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
- return +0.0;
- } else {
- return -0.0;
- }
- }
-#ifdef DUK_USE_MATH_FMAX
- return DUK_FMAX(x, y);
-#else
- return (x > y ? x : y);
-#endif
-}
-
-DUK_LOCAL double duk__round_fixed(double x) {
- /* Numbers half-way between integers must be rounded towards +Infinity,
- * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero
- * sign must be set appropriately. E5.1 Section 15.8.2.15.
- *
- * Note that ANSI C round() is "round to nearest integer, away from zero",
- * which is incorrect for negative values. Here we make do with floor().
- */
-
- duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
- if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
- return x;
- }
-
- /*
- * x is finite and non-zero
- *
- * -1.6 -> floor(-1.1) -> -2
- * -1.5 -> floor(-1.0) -> -1 (towards +Inf)
- * -1.4 -> floor(-0.9) -> -1
- * -0.5 -> -0.0 (special case)
- * -0.1 -> -0.0 (special case)
- * +0.1 -> +0.0 (special case)
- * +0.5 -> floor(+1.0) -> 1 (towards +Inf)
- * +1.4 -> floor(+1.9) -> 1
- * +1.5 -> floor(+2.0) -> 2 (towards +Inf)
- * +1.6 -> floor(+2.1) -> 2
- */
-
- if (x >= -0.5 && x < 0.5) {
- /* +0.5 is handled by floor, this is on purpose */
- if (x < 0.0) {
- return -0.0;
- } else {
- return +0.0;
- }
- }
-
- return DUK_FLOOR(x + 0.5);
-}
-
-DUK_LOCAL double duk__pow_fixed(double x, double y) {
- /* The ANSI C pow() semantics differ from Ecmascript.
- *
- * E.g. when x==1 and y is +/- infinite, the Ecmascript required
- * result is NaN, while at least Linux pow() returns 1.
- */
-
- duk_small_int_t cx, cy, sx;
-
- DUK_UNREF(cx);
- DUK_UNREF(sx);
- cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
-
- if (cy == DUK_FP_NAN) {
- goto ret_nan;
- }
- if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) {
- goto ret_nan;
- }
-#if defined(DUK_USE_POW_NETBSD_WORKAROUND)
- /* See test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least) does not
- * correctly handle some cases where x=+/-0. Specific fixes to these
- * here.
- */
- cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
- if (cx == DUK_FP_ZERO && y < 0.0) {
- sx = (duk_small_int_t) DUK_SIGNBIT(x);
- if (sx == 0) {
- /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow()
- * returns -Infinity instead when y is <0 and finite. The
- * if-clause also catches y == -Infinity (which works even
- * without the fix).
- */
- return DUK_DOUBLE_INFINITY;
- } else {
- /* Math.pow(-0,y) where y<0 should be:
- * - -Infinity if y<0 and an odd integer
- * - Infinity otherwise
- * NetBSD pow() returns -Infinity for all finite y<0. The
- * if-clause also catches y == -Infinity (which works even
- * without the fix).
- */
-
- /* fmod() return value has same sign as input (negative) so
- * the result here will be in the range ]-2,0], 1 indicates
- * odd. If x is -Infinity, NaN is returned and the odd check
- * always concludes "not odd" which results in desired outcome.
- */
- double tmp = DUK_FMOD(y, 2);
- if (tmp == -1.0) {
- return -DUK_DOUBLE_INFINITY;
- } else {
- /* Not odd, or y == -Infinity */
- return DUK_DOUBLE_INFINITY;
- }
- }
- }
-#endif
- return DUK_POW(x, y);
-
- ret_nan:
- return DUK_DOUBLE_NAN;
-}
-
-/* Wrappers for calling standard math library methods. These may be required
- * on platforms where one or more of the math built-ins are defined as macros
- * or inline functions and are thus not suitable to be used as function pointers.
- */
-#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
-DUK_LOCAL double duk__fabs(double x) {
- return DUK_FABS(x);
-}
-DUK_LOCAL double duk__acos(double x) {
- return DUK_ACOS(x);
-}
-DUK_LOCAL double duk__asin(double x) {
- return DUK_ASIN(x);
-}
-DUK_LOCAL double duk__atan(double x) {
- return DUK_ATAN(x);
-}
-DUK_LOCAL double duk__ceil(double x) {
- return DUK_CEIL(x);
-}
-DUK_LOCAL double duk__cos(double x) {
- return DUK_COS(x);
-}
-DUK_LOCAL double duk__exp(double x) {
- return DUK_EXP(x);
-}
-DUK_LOCAL double duk__floor(double x) {
- return DUK_FLOOR(x);
-}
-DUK_LOCAL double duk__log(double x) {
- return DUK_LOG(x);
-}
-DUK_LOCAL double duk__sin(double x) {
- return DUK_SIN(x);
-}
-DUK_LOCAL double duk__sqrt(double x) {
- return DUK_SQRT(x);
-}
-DUK_LOCAL double duk__tan(double x) {
- return DUK_TAN(x);
-}
-DUK_LOCAL double duk__atan2(double x, double y) {
- return DUK_ATAN2(x, y);
-}
-#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
-
-/* order must match constants in genbuiltins.py */
-DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
-#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
- duk__fabs,
- duk__acos,
- duk__asin,
- duk__atan,
- duk__ceil,
- duk__cos,
- duk__exp,
- duk__floor,
- duk__log,
- duk__round_fixed,
- duk__sin,
- duk__sqrt,
- duk__tan
-#else
- DUK_FABS,
- DUK_ACOS,
- DUK_ASIN,
- DUK_ATAN,
- DUK_CEIL,
- DUK_COS,
- DUK_EXP,
- DUK_FLOOR,
- DUK_LOG,
- duk__round_fixed,
- DUK_SIN,
- DUK_SQRT,
- DUK_TAN
-#endif
-};
-
-/* order must match constants in genbuiltins.py */
-DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
-#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
- duk__atan2,
- duk__pow_fixed
-#else
- DUK_ATAN2,
- duk__pow_fixed
-#endif
-};
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
- duk_small_int_t fun_idx = duk_get_current_magic(ctx);
- duk__one_arg_func fun;
-
- DUK_ASSERT(fun_idx >= 0);
- DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
- fun = duk__one_arg_funcs[fun_idx];
- duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0)));
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
- duk_small_int_t fun_idx = duk_get_current_magic(ctx);
- duk__two_arg_func fun;
-
- DUK_ASSERT(fun_idx >= 0);
- DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
- fun = duk__two_arg_funcs[fun_idx];
- duk_push_number(ctx, (duk_double_t) fun((double) duk_to_number(ctx, 0), (double) duk_to_number(ctx, 1)));
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
- return duk__math_minmax(ctx, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
- return duk__math_minmax(ctx, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
- duk_push_number(ctx, (duk_double_t) duk_util_tinyrandom_get_double((duk_hthread *) ctx));
- return 1;
-}
-
-#else /* DUK_USE_MATH_BUILTIN */
-
-/* A stubbed built-in is useful for e.g. compilation torture testing with BCC. */
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNIMPLEMENTED_ERROR;
-}
-
-#endif /* DUK_USE_MATH_BUILTIN */
-#line 1 "duk_bi_number.c"
-/*
- * Number built-ins
- */
-
-/* include removed: duk_internal.h */
-
-DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_context *ctx) {
- duk_hobject *h;
-
- /* Number built-in accepts a plain number or a Number object (whose
- * internal value is operated on). Other types cause TypeError.
- */
-
- duk_push_this(ctx);
- if (duk_is_number(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- goto done;
- }
- h = duk_get_hobject(ctx, -1);
- if (!h ||
- (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
- DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- DUK_ERROR_TYPE((duk_hthread *) ctx, "number expected");
- }
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_number(ctx, -1));
- DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
- duk_remove(ctx, -2);
-
- done:
- return duk_get_number(ctx, -1);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t nargs;
- duk_hobject *h_this;
-
- DUK_UNREF(thr);
-
- /*
- * The Number constructor uses ToNumber(arg) for number coercion
- * (coercing an undefined argument to NaN). However, if the
- * argument is not given at all, +0 must be used instead. To do
- * this, a vararg function is used.
- */
-
- nargs = duk_get_top(ctx);
- if (nargs == 0) {
- duk_push_int(ctx, 0);
- }
- duk_to_number(ctx, 0);
- duk_set_top(ctx, 1);
- DUK_ASSERT_TOP(ctx, 1);
-
- if (!duk_is_constructor_call(ctx)) {
- return 1;
- }
-
- /*
- * E5 Section 15.7.2.1 requires that the constructed object
- * must have the original Number.prototype as its internal
- * prototype. However, since Number.prototype is non-writable
- * and non-configurable, this doesn't have to be enforced here:
- * The default object (bound to 'this') is OK, though we have
- * to change its class.
- *
- * Internal value set to ToNumber(arg) or +0; if no arg given,
- * ToNumber(undefined) = NaN, so special treatment is needed
- * (above). String internal value is immutable.
- */
-
- /* XXX: helper */
- duk_push_this(ctx);
- h_this = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h_this != NULL);
- DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
-
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
- DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
- DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
-
- duk_dup(ctx, 0); /* -> [ val obj val ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
- return 0; /* no return value -> don't replace created value */
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx) {
- (void) duk__push_this_number_plain(ctx);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx) {
- duk_small_int_t radix;
- duk_small_uint_t n2s_flags;
-
- (void) duk__push_this_number_plain(ctx);
- if (duk_is_undefined(ctx, 0)) {
- radix = 10;
- } else {
- radix = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 2, 36);
- }
- DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
-
- n2s_flags = 0;
-
- duk_numconv_stringify(ctx,
- radix /*radix*/,
- 0 /*digits*/,
- n2s_flags /*flags*/);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx) {
- /* XXX: just use toString() for now; permitted although not recommended.
- * nargs==1, so radix is passed to toString().
- */
- return duk_bi_number_prototype_to_string(ctx);
-}
-
-/*
- * toFixed(), toExponential(), toPrecision()
- */
-
-/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
-
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) {
- duk_small_int_t frac_digits;
- duk_double_t d;
- duk_small_int_t c;
- duk_small_uint_t n2s_flags;
-
- frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
- d = duk__push_this_number_plain(ctx);
-
- c = (duk_small_int_t) DUK_FPCLASSIFY(d);
- if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
- goto use_to_string;
- }
-
- if (d >= 1.0e21 || d <= -1.0e21) {
- goto use_to_string;
- }
-
- n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
- DUK_N2S_FLAG_FRACTION_DIGITS;
-
- duk_numconv_stringify(ctx,
- 10 /*radix*/,
- frac_digits /*digits*/,
- n2s_flags /*flags*/);
- return 1;
-
- use_to_string:
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx) {
- duk_bool_t frac_undefined;
- duk_small_int_t frac_digits;
- duk_double_t d;
- duk_small_int_t c;
- duk_small_uint_t n2s_flags;
-
- d = duk__push_this_number_plain(ctx);
-
- frac_undefined = duk_is_undefined(ctx, 0);
- duk_to_int(ctx, 0); /* for side effects */
-
- c = (duk_small_int_t) DUK_FPCLASSIFY(d);
- if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
- goto use_to_string;
- }
-
- frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
-
- n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
- (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
-
- duk_numconv_stringify(ctx,
- 10 /*radix*/,
- frac_digits + 1 /*leading digit + fractions*/,
- n2s_flags /*flags*/);
- return 1;
-
- use_to_string:
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
- /* The specification has quite awkward order of coercion and
- * checks for toPrecision(). The operations below are a bit
- * reordered, within constraints of observable side effects.
- */
-
- duk_double_t d;
- duk_small_int_t prec;
- duk_small_int_t c;
- duk_small_uint_t n2s_flags;
-
- DUK_ASSERT_TOP(ctx, 1);
-
- d = duk__push_this_number_plain(ctx);
- if (duk_is_undefined(ctx, 0)) {
- goto use_to_string;
- }
- DUK_ASSERT_TOP(ctx, 2);
-
- duk_to_int(ctx, 0); /* for side effects */
-
- c = (duk_small_int_t) DUK_FPCLASSIFY(d);
- if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
- goto use_to_string;
- }
-
- prec = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 1, 21);
-
- n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
- DUK_N2S_FLAG_NO_ZERO_PAD;
-
- duk_numconv_stringify(ctx,
- 10 /*radix*/,
- prec /*digits*/,
- n2s_flags /*flags*/);
- return 1;
-
- use_to_string:
- /* Used when precision is undefined; also used for NaN (-> "NaN"),
- * and +/- infinity (-> "Infinity", "-Infinity").
- */
-
- DUK_ASSERT_TOP(ctx, 2);
- duk_to_string(ctx, -1);
- return 1;
-}
-#line 1 "duk_bi_object.c"
-/*
- * Object built-ins
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
- if (!duk_is_constructor_call(ctx) &&
- !duk_is_null_or_undefined(ctx, 0)) {
- duk_to_object(ctx, 0);
- return 1;
- }
-
- if (duk_is_object(ctx, 0)) {
- return 1;
- }
-
- /* Pointer and buffer primitive values are treated like other
- * primitives values which have a fully fledged object counterpart:
- * promote to an object value. Lightfuncs are coerced with
- * ToObject() even they could also be returned as is.
- */
- if (duk_check_type_mask(ctx, 0, DUK_TYPE_MASK_STRING |
- DUK_TYPE_MASK_BOOLEAN |
- DUK_TYPE_MASK_NUMBER |
- DUK_TYPE_MASK_POINTER |
- DUK_TYPE_MASK_BUFFER |
- DUK_TYPE_MASK_LIGHTFUNC)) {
- duk_to_object(ctx, 0);
- return 1;
- }
-
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- DUK_BIDX_OBJECT_PROTOTYPE);
- return 1;
-}
-
-/* Shared helper to implement Object.getPrototypeOf and the ES6
- * Object.prototype.__proto__ getter.
- *
- * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
- */
-DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
- duk_hobject *proto;
-
- DUK_UNREF(thr);
-
- /* magic: 0=getter call, 1=Object.getPrototypeOf */
- if (duk_get_current_magic(ctx) == 0) {
- duk_push_this_coercible_to_object(ctx);
- duk_insert(ctx, 0);
- }
-
- h = duk_require_hobject_or_lfunc(ctx, 0);
- /* h is NULL for lightfunc */
-
- /* XXX: should the API call handle this directly, i.e. attempt
- * to duk_push_hobject(ctx, null) would push a null instead?
- * (On the other hand 'undefined' would be just as logical, but
- * not wanted here.)
- */
-
- if (h == NULL) {
- duk_push_hobject_bidx(ctx, DUK_BIDX_FUNCTION_PROTOTYPE);
- } else {
- proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
- if (proto) {
- duk_push_hobject(ctx, proto);
- } else {
- duk_push_null(ctx);
- }
- }
- return 1;
-}
-
-/* Shared helper to implement ES6 Object.setPrototypeOf and
- * Object.prototype.__proto__ setter.
- *
- * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
- * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
- */
-DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_obj;
- duk_hobject *h_new_proto;
- duk_hobject *h_curr;
- duk_ret_t ret_success = 1; /* retval for success path */
-
- /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4);
- * magic: 0=setter call, 1=Object.setPrototypeOf
- */
- if (duk_get_current_magic(ctx) == 0) {
- duk_push_this_check_object_coercible(ctx);
- duk_insert(ctx, 0);
- if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
- return 0;
- }
-
- /* __proto__ setter returns 'undefined' on success unlike the
- * setPrototypeOf() call which returns the target object.
- */
- ret_success = 0;
- } else {
- duk_require_object_coercible(ctx, 0);
- duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
- }
-
- h_new_proto = duk_get_hobject(ctx, 1);
- /* h_new_proto may be NULL */
- if (duk_is_lightfunc(ctx, 0)) {
- if (h_new_proto == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]) {
- goto skip;
- }
- goto fail_nonextensible;
- }
- h_obj = duk_get_hobject(ctx, 0);
- if (!h_obj) {
- goto skip;
- }
- DUK_ASSERT(h_obj != NULL);
-
- /* [[SetPrototypeOf]] standard behavior, E6 9.1.2 */
- /* TODO: implement Proxy object support here */
-
- if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
- goto skip;
- }
- if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
- goto fail_nonextensible;
- }
- for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
- /* Loop prevention */
- if (h_curr == h_obj) {
- goto fail_loop;
- }
- }
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
- /* fall thru */
-
- skip:
- duk_set_top(ctx, 1);
- return ret_success;
-
- fail_nonextensible:
- fail_loop:
- return DUK_RET_TYPE_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
- /* XXX: no need for indirect call */
- return duk_hobject_object_get_own_property_descriptor(ctx);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
- duk_tval *tv;
- duk_hobject *proto = NULL;
-
- DUK_ASSERT_TOP(ctx, 2);
-
- tv = duk_get_tval(ctx, 0);
- DUK_ASSERT(tv != NULL);
- if (DUK_TVAL_IS_NULL(tv)) {
- ;
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- proto = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(proto != NULL);
- } else {
- return DUK_RET_TYPE_ERROR;
- }
-
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- proto);
-
- if (!duk_is_undefined(ctx, 1)) {
- /* [ O Properties obj ] */
-
- duk_replace(ctx, 0);
-
- /* [ obj Properties ] */
-
- /* Just call the "original" Object.defineProperties() to
- * finish up.
- */
-
- return duk_bi_object_constructor_define_properties(ctx);
- }
-
- /* [ O Properties obj ] */
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
- duk_hobject *obj;
- duk_hstring *key;
- duk_hobject *get;
- duk_hobject *set;
- duk_idx_t idx_value;
- duk_uint_t defprop_flags;
-
- DUK_ASSERT(ctx != NULL);
-
- DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
- (void *) ctx,
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
-
- /* [ obj key desc ] */
-
- /* Lightfuncs are currently supported by coercing to a temporary
- * Function object; changes will be allowed (the coerced value is
- * extensible) but will be lost.
- */
- obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
- (void) duk_to_string(ctx, 1);
- key = duk_require_hstring(ctx, 1);
- (void) duk_require_hobject(ctx, 2);
-
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(duk_get_hobject(ctx, 2) != NULL);
-
- /*
- * Validate and convert argument property descriptor (an Ecmascript
- * object) into a set of defprop_flags and possibly property value,
- * getter, and/or setter values on the value stack.
- *
- * Lightfunc set/get values are coerced to full Functions.
- */
-
- duk_hobject_prepare_property_descriptor(ctx,
- 2 /*idx_desc*/,
- &defprop_flags,
- &idx_value,
- &get,
- &set);
-
- /*
- * Use Object.defineProperty() helper for the actual operation.
- */
-
- duk_hobject_define_property_helper(ctx,
- defprop_flags,
- obj,
- key,
- idx_value,
- get,
- set);
-
- /* Ignore the normalize/validate helper outputs on the value stack,
- * they're popped automatically.
- */
-
- /*
- * Return target object.
- */
-
- duk_push_hobject(ctx, obj);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
- duk_small_uint_t pass;
- duk_uint_t defprop_flags;
- duk_hobject *obj;
- duk_idx_t idx_value;
- duk_hobject *get;
- duk_hobject *set;
-
- /* Lightfunc handling by ToObject() coercion. */
- obj = duk_require_hobject_or_lfunc_coerce(ctx, 0); /* target */
- DUK_ASSERT(obj != NULL);
-
- duk_to_object(ctx, 1); /* properties object */
-
- DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
-
- /*
- * Two pass approach to processing the property descriptors.
- * On first pass validate and normalize all descriptors before
- * any changes are made to the target object. On second pass
- * make the actual modifications to the target object.
- *
- * Right now we'll just use the same normalize/validate helper
- * on both passes, ignoring its outputs on the first pass.
- */
-
- for (pass = 0; pass < 2; pass++) {
- duk_set_top(ctx, 2); /* -> [ hobject props ] */
- duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY /*enum_flags*/);
-
- for (;;) {
- duk_hstring *key;
-
- /* [ hobject props enum(props) ] */
-
- duk_set_top(ctx, 3);
-
- if (!duk_next(ctx, 2, 1 /*get_value*/)) {
- break;
- }
-
- DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* [ hobject props enum(props) key desc ] */
-
- duk_hobject_prepare_property_descriptor(ctx,
- 4 /*idx_desc*/,
- &defprop_flags,
- &idx_value,
- &get,
- &set);
-
- /* [ hobject props enum(props) key desc value? getter? setter? ] */
-
- if (pass == 0) {
- continue;
- }
-
- key = duk_get_hstring(ctx, 3);
- DUK_ASSERT(key != NULL);
-
- duk_hobject_define_property_helper(ctx,
- defprop_flags,
- obj,
- key,
- idx_value,
- get,
- set);
- }
- }
-
- /*
- * Return target object
- */
-
- duk_dup(ctx, 0);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
- duk_bool_t is_freeze;
-
- h = duk_require_hobject_or_lfunc(ctx, 0);
- if (!h) {
- /* Lightfunc, always success. */
- return 1;
- }
-
- is_freeze = (duk_bool_t) duk_get_current_magic(ctx);
- duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
-
- /* Sealed and frozen objects cannot gain any more properties,
- * so this is a good time to compact them.
- */
- duk_hobject_compact_props(thr, h);
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h;
-
- h = duk_require_hobject_or_lfunc(ctx, 0);
- if (!h) {
- /* Lightfunc, always success. */
- return 1;
- }
- DUK_ASSERT(h != NULL);
-
- DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
-
- /* A non-extensible object cannot gain any more properties,
- * so this is a good time to compact.
- */
- duk_hobject_compact_props(thr, h);
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) {
- duk_hobject *h;
- duk_bool_t is_frozen;
- duk_bool_t rc;
-
- h = duk_require_hobject_or_lfunc(ctx, 0);
- if (!h) {
- duk_push_true(ctx); /* frozen and sealed */
- } else {
- is_frozen = duk_get_current_magic(ctx);
- rc = duk_hobject_object_is_sealed_frozen_helper((duk_hthread *) ctx, h, is_frozen /*is_frozen*/);
- duk_push_boolean(ctx, rc);
- }
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) {
- duk_hobject *h;
-
- h = duk_require_hobject_or_lfunc(ctx, 0);
- if (!h) {
- duk_push_false(ctx);
- } else {
- duk_push_boolean(ctx, DUK_HOBJECT_HAS_EXTENSIBLE(h));
- }
- return 1;
-}
-
-/* Shared helper for Object.getOwnPropertyNames() and Object.keys().
- * Magic: 0=getOwnPropertyNames, 1=Object.keys.
- */
-DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
-#if defined(DUK_USE_ES6_PROXY)
- duk_hobject *h_proxy_target;
- duk_hobject *h_proxy_handler;
- duk_hobject *h_trap_result;
- duk_uarridx_t i, len, idx;
-#endif
- duk_small_uint_t enum_flags;
-
- DUK_ASSERT_TOP(ctx, 1);
- DUK_UNREF(thr);
-
- obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
- DUK_ASSERT(obj != NULL);
- DUK_UNREF(obj);
-
-#if defined(DUK_USE_ES6_PROXY)
- if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
- obj,
- &h_proxy_target,
- &h_proxy_handler))) {
- goto skip_proxy;
- }
-
- duk_push_hobject(ctx, h_proxy_handler);
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
- /* Careful with reachability here: don't pop 'obj' before pushing
- * proxy target.
- */
- DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
- duk_pop_2(ctx);
- duk_push_hobject(ctx, h_proxy_target);
- duk_replace(ctx, 0);
- DUK_ASSERT_TOP(ctx, 1);
- goto skip_proxy;
- }
-
- /* [ obj handler trap ] */
- duk_insert(ctx, -2);
- duk_push_hobject(ctx, h_proxy_target); /* -> [ obj trap handler target ] */
- duk_call_method(ctx, 1 /*nargs*/); /* -> [ obj trap_result ] */
- h_trap_result = duk_require_hobject(ctx, -1);
- DUK_UNREF(h_trap_result);
-
- len = (duk_uarridx_t) duk_get_length(ctx, -1);
- idx = 0;
- duk_push_array(ctx);
- for (i = 0; i < len; i++) {
- /* [ obj trap_result res_arr ] */
- if (duk_get_prop_index(ctx, -2, i) && duk_is_string(ctx, -1)) {
- /* XXX: for Object.keys() we should check enumerability of key */
- /* [ obj trap_result res_arr propname ] */
- duk_put_prop_index(ctx, -2, idx);
- idx++;
- } else {
- duk_pop(ctx);
- }
- }
-
- /* XXX: missing trap result validation for non-configurable target keys
- * (must be present), for non-extensible target all target keys must be
- * present and no extra keys can be present.
- * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
- */
-
- /* XXX: for Object.keys() the [[OwnPropertyKeys]] result (trap result)
- * should be filtered so that only enumerable keys remain. Enumerability
- * should be checked with [[GetOwnProperty]] on the original object
- * (i.e., the proxy in this case). If the proxy has a getOwnPropertyDescriptor
- * trap, it should be triggered for every property. If the proxy doesn't have
- * the trap, enumerability should be checked against the target object instead.
- * We don't do any of this now, so Object.keys() and Object.getOwnPropertyNames()
- * return the same result now for proxy traps. We still do clean up the trap
- * result, so that Object.keys() and Object.getOwnPropertyNames() will return a
- * clean array of strings without gaps.
- */
- return 1;
-
- skip_proxy:
-#endif /* DUK_USE_ES6_PROXY */
-
- DUK_ASSERT_TOP(ctx, 1);
-
- if (duk_get_current_magic(ctx)) {
- /* Object.keys */
- enum_flags = DUK_ENUM_OWN_PROPERTIES_ONLY |
- DUK_ENUM_NO_PROXY_BEHAVIOR;
- } else {
- /* Object.getOwnPropertyNames */
- enum_flags = DUK_ENUM_INCLUDE_NONENUMERABLE |
- DUK_ENUM_OWN_PROPERTIES_ONLY |
- DUK_ENUM_NO_PROXY_BEHAVIOR;
- }
-
- return duk_hobject_get_enumerated_keys(ctx, enum_flags);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
- duk_push_this(ctx);
- duk_to_object_class_string_top(ctx);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 0);
- (void) duk_push_this_coercible_to_object(ctx);
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_TO_STRING);
- if (!duk_is_callable(ctx, 1)) {
- return DUK_RET_TYPE_ERROR;
- }
- duk_dup(ctx, 0); /* -> [ O toString O ] */
- duk_call_method(ctx, 0); /* XXX: call method tail call? */
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx) {
- (void) duk_push_this_coercible_to_object(ctx);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_v;
- duk_hobject *h_obj;
-
- DUK_ASSERT_TOP(ctx, 1);
-
- h_v = duk_get_hobject(ctx, 0);
- if (!h_v) {
- duk_push_false(ctx); /* XXX: tail call: return duk_push_false(ctx) */
- return 1;
- }
-
- h_obj = duk_push_this_coercible_to_object(ctx);
- DUK_ASSERT(h_obj != NULL);
-
- /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
- * Prototype loops should cause an error to be thrown.
- */
- duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx) {
- return duk_hobject_object_ownprop_helper(ctx, 0 /*required_desc_flags*/);
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx) {
- return duk_hobject_object_ownprop_helper(ctx, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
-}
-#line 1 "duk_bi_pointer.c"
-/*
- * Pointer built-ins
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Constructor
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx) {
- /* XXX: this behavior is quite useless now; it would be nice to be able
- * to create pointer values from e.g. numbers or strings. Numbers are
- * problematic on 64-bit platforms though. Hex encoded strings?
- */
- if (duk_get_top(ctx) == 0) {
- duk_push_pointer(ctx, NULL);
- } else {
- duk_to_pointer(ctx, 0);
- }
- DUK_ASSERT(duk_is_pointer(ctx, 0));
- duk_set_top(ctx, 1);
-
- if (duk_is_constructor_call(ctx)) {
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
- DUK_BIDX_POINTER_PROTOTYPE);
-
- /* Pointer object internal value is immutable */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
- }
- /* Note: unbalanced stack on purpose */
-
- return 1;
-}
-
-/*
- * toString(), valueOf()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx) {
- duk_tval *tv;
- duk_small_int_t to_string = duk_get_current_magic(ctx);
-
- duk_push_this(ctx);
- tv = duk_require_tval(ctx, -1);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_POINTER(tv)) {
- /* nop */
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- /* Must be a "pointer object", i.e. class "Pointer" */
- if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) {
- goto type_error;
- }
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- } else {
- goto type_error;
- }
-
- if (to_string) {
- duk_to_string(ctx, -1);
- }
- return 1;
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-#line 1 "duk_bi_proxy.c"
-/*
- * Proxy built-in (ES6)
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
- duk_hobject *h_target;
- duk_hobject *h_handler;
-
- if (!duk_is_constructor_call(ctx)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- /* Reject a proxy object as the target because it would need
- * special handler in property lookups. (ES6 has no such restriction)
- */
- h_target = duk_require_hobject_or_lfunc_coerce(ctx, 0);
- DUK_ASSERT(h_target != NULL);
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_target)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- /* Reject a proxy object as the handler because it would cause
- * potentially unbounded recursion. (ES6 has no such restriction)
- */
- h_handler = duk_require_hobject_or_lfunc_coerce(ctx, 1);
- DUK_ASSERT(h_handler != NULL);
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_handler)) {
- return DUK_RET_TYPE_ERROR;
- }
-
- /* XXX: the returned value is exotic in ES6, but we use a
- * simple object here with no prototype. Without a prototype,
- * [[DefaultValue]] coercion fails which is abit confusing.
- * No callable check/handling in the current Proxy subset.
- */
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- NULL);
- DUK_ASSERT_TOP(ctx, 3);
-
- /* Make _Target and _Handler non-configurable and non-writable.
- * They can still be forcibly changed by C code (both user and
- * Duktape internal), but not by Ecmascript code.
- */
-
- /* Proxy target */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
-
- /* Proxy handler */
- duk_dup(ctx, 1);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_HANDLER, DUK_PROPDESC_FLAGS_NONE);
-
- return 1; /* replacement handler */
-}
-#else /* DUK_USE_ES6_PROXY */
-DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_ES6_PROXY */
-#line 1 "duk_bi_regexp.c"
-/*
- * RegExp built-ins
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_REGEXP_SUPPORT
-
-DUK_LOCAL void duk__get_this_regexp(duk_context *ctx) {
- duk_hobject *h;
-
- duk_push_this(ctx);
- h = duk_require_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_REGEXP);
- DUK_ASSERT(h != NULL);
- DUK_UNREF(h);
- duk_insert(ctx, 0); /* prepend regexp to valstack 0 index */
-}
-
-/* XXX: much to improve (code size) */
-DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *h_pattern;
-
- DUK_ASSERT_TOP(ctx, 2);
- h_pattern = duk_get_hobject(ctx, 0);
-
- if (!duk_is_constructor_call(ctx) &&
- h_pattern != NULL &&
- DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
- duk_is_undefined(ctx, 1)) {
- /* Called as a function, pattern has [[Class]] "RegExp" and
- * flags is undefined -> return object as is.
- */
- duk_dup(ctx, 0);
- return 1;
- }
-
- /* Else functionality is identical for function call and constructor
- * call.
- */
-
- if (h_pattern != NULL &&
- DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
- if (duk_is_undefined(ctx, 1)) {
- duk_bool_t flag_g, flag_i, flag_m;
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
- flag_g = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
- flag_i = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_IGNORE_CASE, NULL);
- flag_m = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_MULTILINE, NULL);
-
- duk_push_sprintf(ctx, "%s%s%s",
- (const char *) (flag_g ? "g" : ""),
- (const char *) (flag_i ? "i" : ""),
- (const char *) (flag_m ? "m" : ""));
-
- /* [ ... pattern flags ] */
- } else {
- return DUK_RET_TYPE_ERROR;
- }
- } else {
- if (duk_is_undefined(ctx, 0)) {
- duk_push_string(ctx, "");
- } else {
- duk_dup(ctx, 0);
- duk_to_string(ctx, -1);
- }
- if (duk_is_undefined(ctx, 1)) {
- duk_push_string(ctx, "");
- } else {
- duk_dup(ctx, 1);
- duk_to_string(ctx, -1);
- }
-
- /* [ ... pattern flags ] */
- }
-
- DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
- (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* [ ... pattern flags ] */
-
- duk_regexp_compile(thr);
-
- /* [ ... bytecode escaped_source ] */
-
- duk_regexp_create_instance(thr);
-
- /* [ ... RegExp ] */
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
- duk__get_this_regexp(ctx);
-
- /* [ regexp input ] */
-
- duk_regexp_match((duk_hthread *) ctx);
-
- /* [ result ] */
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
- duk__get_this_regexp(ctx);
-
- /* [ regexp input ] */
-
- /* result object is created and discarded; wasteful but saves code space */
- duk_regexp_match((duk_hthread *) ctx);
-
- /* [ result ] */
-
- duk_push_boolean(ctx, (duk_is_null(ctx, -1) ? 0 : 1));
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
- duk_hstring *h_bc;
- duk_small_int_t re_flags;
-
-#if 0
- /* A little tricky string approach to provide the flags string.
- * This depends on the specific flag values in duk_regexp.h,
- * which needs to be asserted for. In practice this doesn't
- * produce more compact code than the easier approach in use.
- */
-
- const char *flag_strings = "gim\0gi\0gm\0g\0";
- duk_uint8_t flag_offsets[8] = {
- (duk_uint8_t) 3, /* flags: "" */
- (duk_uint8_t) 10, /* flags: "g" */
- (duk_uint8_t) 5, /* flags: "i" */
- (duk_uint8_t) 4, /* flags: "gi" */
- (duk_uint8_t) 2, /* flags: "m" */
- (duk_uint8_t) 7, /* flags: "gm" */
- (duk_uint8_t) 1, /* flags: "im" */
- (duk_uint8_t) 0, /* flags: "gim" */
- };
- DUK_ASSERT(DUK_RE_FLAG_GLOBAL == 1);
- DUK_ASSERT(DUK_RE_FLAG_IGNORE_CASE == 2);
- DUK_ASSERT(DUK_RE_FLAG_MULTILINE == 4);
-#endif
-
- duk__get_this_regexp(ctx);
-
- /* [ regexp ] */
-
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_INT_BYTECODE);
- h_bc = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_bc != NULL);
- DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1);
- DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
- DUK_ASSERT(DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80);
- re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
-
- /* [ regexp source bytecode ] */
-
-#if 1
- /* This is a cleaner approach and also produces smaller code than
- * the other alternative. Use duk_require_string() for format
- * safety (although the source property should always exist).
- */
- duk_push_sprintf(ctx, "/%s/%s%s%s",
- (const char *) duk_require_string(ctx, -2), /* require to be safe */
- (re_flags & DUK_RE_FLAG_GLOBAL) ? "g" : "",
- (re_flags & DUK_RE_FLAG_IGNORE_CASE) ? "i" : "",
- (re_flags & DUK_RE_FLAG_MULTILINE) ? "m" : "");
-#else
- /* This should not be necessary because no-one should tamper with the
- * regexp bytecode, but is prudent to avoid potential segfaults if that
- * were to happen for some reason.
- */
- re_flags &= 0x07;
- DUK_ASSERT(re_flags >= 0 && re_flags <= 7); /* three flags */
- duk_push_sprintf(ctx, "/%s/%s",
- (const char *) duk_require_string(ctx, -2),
- (const char *) (flag_strings + flag_offsets[re_flags]));
-#endif
-
- return 1;
-}
-
-#else /* DUK_USE_REGEXP_SUPPORT */
-
-DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_to_string(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-
-#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_bi_string.c"
-/*
- * String built-ins
- */
-
-/* XXX: There are several limitations in the current implementation for
- * strings with >= 0x80000000UL characters. In some cases one would need
- * to be able to represent the range [-0xffffffff,0xffffffff] and so on.
- * Generally character and byte length are assumed to fit into signed 32
- * bits (< 0x80000000UL). Places with issues are not marked explicitly
- * below in all cases, look for signed type usage (duk_int_t etc) for
- * offsets/lengths.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Constructor
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_context *ctx) {
- /* String constructor needs to distinguish between an argument not given at all
- * vs. given as 'undefined'. We're a vararg function to handle this properly.
- */
-
- if (duk_get_top(ctx) == 0) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
- } else {
- duk_to_string(ctx, 0);
- }
- DUK_ASSERT(duk_is_string(ctx, 0));
- duk_set_top(ctx, 1);
-
- if (duk_is_constructor_call(ctx)) {
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING),
- DUK_BIDX_STRING_PROTOTYPE);
-
- /* String object internal value is immutable */
- duk_dup(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
- }
- /* Note: unbalanced stack on purpose */
-
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_bufwriter_ctx bw_alloc;
- duk_bufwriter_ctx *bw;
- duk_idx_t i, n;
- duk_ucodepoint_t cp;
-
- /* XXX: It would be nice to build the string directly but ToUint16()
- * coercion is needed so a generic helper would not be very
- * helpful (perhaps coerce the value stack first here and then
- * build a string from a duk_tval number sequence in one go?).
- */
-
- n = duk_get_top(ctx);
-
- bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, n); /* initial estimate for ASCII only codepoints */
-
- for (i = 0; i < n; i++) {
- /* XXX: could improve bufwriter handling to write multiple codepoints
- * with one ensure call but the relative benefit would be quite small.
- */
-
-#if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT)
- /* ToUint16() coercion is mandatory in the E5.1 specification, but
- * this non-compliant behavior makes more sense because we support
- * non-BMP codepoints. Don't use CESU-8 because that'd create
- * surrogate pairs.
- */
-
- cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
- DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
-#else
- cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
- DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
-#endif
- }
-
- DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1);
- return 1;
-}
-
-/*
- * toString(), valueOf()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
- duk_tval *tv;
-
- duk_push_this(ctx);
- tv = duk_require_tval(ctx, -1);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_IS_STRING(tv)) {
- /* return as is */
- return 1;
- } else if (DUK_TVAL_IS_OBJECT(tv)) {
- duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
-
- /* Must be a "string object", i.e. class "String" */
- if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) {
- goto type_error;
- }
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE);
- DUK_ASSERT(duk_is_string(ctx, -1));
-
- return 1;
- } else {
- goto type_error;
- }
-
- /* never here, but fall through */
-
- type_error:
- return DUK_RET_TYPE_ERROR;
-}
-
-/*
- * Character and charcode access
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx) {
- duk_int_t pos;
-
- /* XXX: faster implementation */
-
- (void) duk_push_this_coercible_to_string(ctx);
- pos = duk_to_int(ctx, 0);
- duk_substring(ctx, -1, pos, pos + 1);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_int_t pos;
- duk_hstring *h;
- duk_bool_t clamped;
-
- /* XXX: faster implementation */
-
- DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(ctx, 0)));
-
- h = duk_push_this_coercible_to_string(ctx);
- DUK_ASSERT(h != NULL);
-
- pos = duk_to_int_clamped_raw(ctx,
- 0 /*index*/,
- 0 /*min(incl)*/,
- DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
- &clamped /*out_clamped*/);
- if (clamped) {
- duk_push_number(ctx, DUK_DOUBLE_NAN);
- return 1;
- }
-
- duk_push_u32(ctx, (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, pos));
- return 1;
-}
-
-/*
- * substring(), substr(), slice()
- */
-
-/* XXX: any chance of merging these three similar but still slightly
- * different algorithms so that footprint would be reduced?
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
- duk_hstring *h;
- duk_int_t start_pos, end_pos;
- duk_int_t len;
-
- h = duk_push_this_coercible_to_string(ctx);
- DUK_ASSERT(h != NULL);
- len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
-
- /* [ start end str ] */
-
- start_pos = duk_to_int_clamped(ctx, 0, 0, len);
- if (duk_is_undefined(ctx, 1)) {
- end_pos = len;
- } else {
- end_pos = duk_to_int_clamped(ctx, 1, 0, len);
- }
- DUK_ASSERT(start_pos >= 0 && start_pos <= len);
- DUK_ASSERT(end_pos >= 0 && end_pos <= len);
-
- if (start_pos > end_pos) {
- duk_int_t tmp = start_pos;
- start_pos = end_pos;
- end_pos = tmp;
- }
-
- DUK_ASSERT(end_pos >= start_pos);
-
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
- return 1;
-}
-
-#ifdef DUK_USE_SECTION_B
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
- duk_hstring *h;
- duk_int_t start_pos, end_pos;
- duk_int_t len;
-
- /* Unlike non-obsolete String calls, substr() algorithm in E5.1
- * specification will happily coerce undefined and null to strings
- * ("undefined" and "null").
- */
- duk_push_this(ctx);
- h = duk_to_hstring(ctx, -1);
- DUK_ASSERT(h != NULL);
- len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
-
- /* [ start length str ] */
-
- /* The implementation for computing of start_pos and end_pos differs
- * from the standard algorithm, but is intended to result in the exactly
- * same behavior. This is not always obvious.
- */
-
- /* combines steps 2 and 5; -len ensures max() not needed for step 5 */
- start_pos = duk_to_int_clamped(ctx, 0, -len, len);
- if (start_pos < 0) {
- start_pos = len + start_pos;
- }
- DUK_ASSERT(start_pos >= 0 && start_pos <= len);
-
- /* combines steps 3, 6; step 7 is not needed */
- if (duk_is_undefined(ctx, 1)) {
- end_pos = len;
- } else {
- DUK_ASSERT(start_pos <= len);
- end_pos = start_pos + duk_to_int_clamped(ctx, 1, 0, len - start_pos);
- }
- DUK_ASSERT(start_pos >= 0 && start_pos <= len);
- DUK_ASSERT(end_pos >= 0 && end_pos <= len);
- DUK_ASSERT(end_pos >= start_pos);
-
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
- return 1;
-}
-#else /* DUK_USE_SECTION_B */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_SECTION_B */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
- duk_hstring *h;
- duk_int_t start_pos, end_pos;
- duk_int_t len;
-
- h = duk_push_this_coercible_to_string(ctx);
- DUK_ASSERT(h != NULL);
- len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
-
- /* [ start end str ] */
-
- start_pos = duk_to_int_clamped(ctx, 0, -len, len);
- if (start_pos < 0) {
- start_pos = len + start_pos;
- }
- if (duk_is_undefined(ctx, 1)) {
- end_pos = len;
- } else {
- end_pos = duk_to_int_clamped(ctx, 1, -len, len);
- if (end_pos < 0) {
- end_pos = len + end_pos;
- }
- }
- DUK_ASSERT(start_pos >= 0 && start_pos <= len);
- DUK_ASSERT(end_pos >= 0 && end_pos <= len);
-
- if (end_pos < start_pos) {
- end_pos = start_pos;
- }
-
- DUK_ASSERT(end_pos >= start_pos);
-
- duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
- return 1;
-}
-
-/*
- * Case conversion
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_small_int_t uppercase = duk_get_current_magic(ctx);
-
- (void) duk_push_this_coercible_to_string(ctx);
- duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase);
- return 1;
-}
-
-/*
- * indexOf() and lastIndexOf()
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_this;
- duk_hstring *h_search;
- duk_int_t clen_this;
- duk_int_t cpos;
- duk_int_t bpos;
- const duk_uint8_t *p_start, *p_end, *p;
- const duk_uint8_t *q_start;
- duk_int_t q_blen;
- duk_uint8_t firstbyte;
- duk_uint8_t t;
- duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */
-
- h_this = duk_push_this_coercible_to_string(ctx);
- DUK_ASSERT(h_this != NULL);
- clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
-
- h_search = duk_to_hstring(ctx, 0);
- DUK_ASSERT(h_search != NULL);
- q_start = DUK_HSTRING_GET_DATA(h_search);
- q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search);
-
- duk_to_number(ctx, 1);
- if (duk_is_nan(ctx, 1) && is_lastindexof) {
- /* indexOf: NaN should cause pos to be zero.
- * lastIndexOf: NaN should cause pos to be +Infinity
- * (and later be clamped to len).
- */
- cpos = clen_this;
- } else {
- cpos = duk_to_int_clamped(ctx, 1, 0, clen_this);
- }
-
- /* Empty searchstring always matches; cpos must be clamped here.
- * (If q_blen were < 0 due to clamped coercion, it would also be
- * caught here.)
- */
- if (q_blen <= 0) {
- duk_push_int(ctx, cpos);
- return 1;
- }
- DUK_ASSERT(q_blen > 0);
-
- bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
-
- p_start = DUK_HSTRING_GET_DATA(h_this);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
- p = p_start + bpos;
-
- /* This loop is optimized for size. For speed, there should be
- * two separate loops, and we should ensure that memcmp() can be
- * used without an extra "will searchstring fit" check. Doing
- * the preconditioning for 'p' and 'p_end' is easy but cpos
- * must be updated if 'p' is wound back (backward scanning).
- */
-
- firstbyte = q_start[0]; /* leading byte of match string */
- while (p <= p_end && p >= p_start) {
- t = *p;
-
- /* For Ecmascript strings, this check can only match for
- * initial UTF-8 bytes (not continuation bytes). For other
- * strings all bets are off.
- */
-
- if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
- DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */
- if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
- duk_push_int(ctx, cpos);
- return 1;
- }
- }
-
- /* track cpos while scanning */
- if (is_lastindexof) {
- /* when going backwards, we decrement cpos 'early';
- * 'p' may point to a continuation byte of the char
- * at offset 'cpos', but that's OK because we'll
- * backtrack all the way to the initial byte.
- */
- if ((t & 0xc0) != 0x80) {
- cpos--;
- }
- p--;
- } else {
- if ((t & 0xc0) != 0x80) {
- cpos++;
- }
- p++;
- }
- }
-
- /* Not found. Empty string case is handled specially above. */
- duk_push_int(ctx, -1);
- return 1;
-}
-
-/*
- * replace()
- */
-
-/* XXX: the current implementation works but is quite clunky; it compiles
- * to almost 1,4kB of x86 code so it needs to be simplified (better approach,
- * shared helpers, etc). Some ideas for refactoring:
- *
- * - a primitive to convert a string into a regexp matcher (reduces matching
- * code at the cost of making matching much slower)
- * - use replace() as a basic helper for match() and split(), which are both
- * much simpler
- * - API call to get_prop and to_boolean
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_input;
- duk_hstring *h_match;
- duk_hstring *h_search;
- duk_hobject *h_re;
- duk_bufwriter_ctx bw_alloc;
- duk_bufwriter_ctx *bw;
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_bool_t is_regexp;
- duk_bool_t is_global;
-#endif
- duk_bool_t is_repl_func;
- duk_uint32_t match_start_coff, match_start_boff;
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_int_t match_caps;
-#endif
- duk_uint32_t prev_match_end_boff;
- const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */
- duk_size_t tmp_sz;
-
- DUK_ASSERT_TOP(ctx, 2);
- h_input = duk_push_this_coercible_to_string(ctx);
- DUK_ASSERT(h_input != NULL);
-
- bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */
-
- DUK_ASSERT_TOP(ctx, 4);
-
- /* stack[0] = search value
- * stack[1] = replace value
- * stack[2] = input string
- * stack[3] = result buffer
- */
-
- h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP);
- if (h_re) {
-#ifdef DUK_USE_REGEXP_SUPPORT
- is_regexp = 1;
- is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
-
- if (is_global) {
- /* start match from beginning */
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- }
-#else /* DUK_USE_REGEXP_SUPPORT */
- return DUK_RET_UNSUPPORTED_ERROR;
-#endif /* DUK_USE_REGEXP_SUPPORT */
- } else {
- duk_to_string(ctx, 0);
-#ifdef DUK_USE_REGEXP_SUPPORT
- is_regexp = 0;
- is_global = 0;
-#endif
- }
-
- if (duk_is_function(ctx, 1)) {
- is_repl_func = 1;
- r_start = NULL;
- r_end = NULL;
- } else {
- duk_hstring *h_repl;
-
- is_repl_func = 0;
- h_repl = duk_to_hstring(ctx, 1);
- DUK_ASSERT(h_repl != NULL);
- r_start = DUK_HSTRING_GET_DATA(h_repl);
- r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
- }
-
- prev_match_end_boff = 0;
-
- for (;;) {
- /*
- * If matching with a regexp:
- * - non-global RegExp: lastIndex not touched on a match, zeroed
- * on a non-match
- * - global RegExp: on match, lastIndex will be updated by regexp
- * executor to point to next char after the matching part (so that
- * characters in the matching part are not matched again)
- *
- * If matching with a string:
- * - always non-global match, find first occurrence
- *
- * We need:
- * - The character offset of start-of-match for the replacer function
- * - The byte offsets for start-of-match and end-of-match to implement
- * the replacement values $&, $`, and $', and to copy non-matching
- * input string portions (including header and trailer) verbatim.
- *
- * NOTE: the E5.1 specification is a bit vague how the RegExp should
- * behave in the replacement process; e.g. is matching done first for
- * all matches (in the global RegExp case) before any replacer calls
- * are made? See: test-bi-string-proto-replace.js for discussion.
- */
-
- DUK_ASSERT_TOP(ctx, 4);
-
-#ifdef DUK_USE_REGEXP_SUPPORT
- if (is_regexp) {
- duk_dup(ctx, 0);
- duk_dup(ctx, 2);
- duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
- break;
- }
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_start_coff = duk_get_int(ctx, -1);
- duk_pop(ctx);
-
- duk_get_prop_index(ctx, -1, 0);
- DUK_ASSERT(duk_is_string(ctx, -1));
- h_match = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_match != NULL);
- duk_pop(ctx); /* h_match is borrowed, remains reachable through match_obj */
-
- if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
- /* This should be equivalent to match() algorithm step 8.f.iii.2:
- * detect an empty match and allow it, but don't allow it twice.
- */
- duk_uint32_t last_index;
-
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- last_index = (duk_uint32_t) duk_get_uint(ctx, -1);
- DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
- (long) last_index, (long) (last_index + 1)));
- duk_pop(ctx);
- duk_push_int(ctx, last_index + 1);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- }
-
- DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_INT_MAX); /* string limits */
- match_caps = (duk_int_t) duk_get_length(ctx, -1);
- } else {
-#else /* DUK_USE_REGEXP_SUPPORT */
- { /* unconditionally */
-#endif /* DUK_USE_REGEXP_SUPPORT */
- const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
- const duk_uint8_t *q_start; /* match string */
- duk_size_t q_blen;
-
-#ifdef DUK_USE_REGEXP_SUPPORT
- DUK_ASSERT(!is_global); /* single match always */
-#endif
-
- p_start = DUK_HSTRING_GET_DATA(h_input);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
- p = p_start;
-
- h_search = duk_get_hstring(ctx, 0);
- DUK_ASSERT(h_search != NULL);
- q_start = DUK_HSTRING_GET_DATA(h_search);
- q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
-
- p_end -= q_blen; /* ensure full memcmp() fits in while */
-
- match_start_coff = 0;
-
- while (p <= p_end) {
- DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
- if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
- duk_dup(ctx, 0);
- h_match = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_match != NULL);
-#ifdef DUK_USE_REGEXP_SUPPORT
- match_caps = 0;
-#endif
- goto found;
- }
-
- /* track utf-8 non-continuation bytes */
- if ((p[0] & 0xc0) != 0x80) {
- match_start_coff++;
- }
- p++;
- }
-
- /* not found */
- break;
- }
- found:
-
- /* stack[0] = search value
- * stack[1] = replace value
- * stack[2] = input string
- * stack[3] = result buffer
- * stack[4] = regexp match OR match string
- */
-
- match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
-
- tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
- DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
-
- prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match);
-
- if (is_repl_func) {
- duk_idx_t idx_args;
- duk_hstring *h_repl;
-
- /* regexp res_obj is at index 4 */
-
- duk_dup(ctx, 1);
- idx_args = duk_get_top(ctx);
-
-#ifdef DUK_USE_REGEXP_SUPPORT
- if (is_regexp) {
- duk_int_t idx;
- duk_require_stack(ctx, match_caps + 2);
- for (idx = 0; idx < match_caps; idx++) {
- /* match followed by capture(s) */
- duk_get_prop_index(ctx, 4, idx);
- }
- } else {
-#else /* DUK_USE_REGEXP_SUPPORT */
- { /* unconditionally */
-#endif /* DUK_USE_REGEXP_SUPPORT */
- /* match == search string, by definition */
- duk_dup(ctx, 0);
- }
- duk_push_int(ctx, match_start_coff);
- duk_dup(ctx, 2);
-
- /* [ ... replacer match [captures] match_char_offset input ] */
-
- duk_call(ctx, duk_get_top(ctx) - idx_args);
- h_repl = duk_to_hstring(ctx, -1); /* -> [ ... repl_value ] */
- DUK_ASSERT(h_repl != NULL);
-
- DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);
-
- duk_pop(ctx); /* repl_value */
- } else {
- r = r_start;
-
- while (r < r_end) {
- duk_int_t ch1;
- duk_int_t ch2;
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_int_t ch3;
-#endif
- duk_size_t left;
-
- ch1 = *r++;
- if (ch1 != DUK_ASC_DOLLAR) {
- goto repl_write;
- }
- left = r_end - r;
-
- if (left <= 0) {
- goto repl_write;
- }
-
- ch2 = r[0];
- switch ((int) ch2) {
- case DUK_ASC_DOLLAR: {
- ch1 = (1 << 8) + DUK_ASC_DOLLAR;
- goto repl_write;
- }
- case DUK_ASC_AMP: {
- DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match);
- r++;
- continue;
- }
- case DUK_ASC_GRAVE: {
- tmp_sz = (duk_size_t) match_start_boff;
- DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz);
- r++;
- continue;
- }
- case DUK_ASC_SINGLEQUOTE: {
- duk_uint32_t match_end_boff;
-
- /* Use match charlen instead of bytelen, just in case the input and
- * match codepoint encodings would have different lengths.
- */
- match_end_boff = duk_heap_strcache_offset_char2byte(thr,
- h_input,
- match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match));
-
- tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
- DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
- r++;
- continue;
- }
- default: {
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_int_t capnum, captmp, capadv;
- /* XXX: optional check, match_caps is zero if no regexp,
- * so dollar will be interpreted literally anyway.
- */
-
- if (!is_regexp) {
- goto repl_write;
- }
-
- if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) {
- goto repl_write;
- }
- capnum = ch2 - DUK_ASC_0;
- capadv = 1;
-
- if (left >= 2) {
- ch3 = r[1];
- if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) {
- captmp = capnum * 10 + (ch3 - DUK_ASC_0);
- if (captmp < match_caps) {
- capnum = captmp;
- capadv = 2;
- }
- }
- }
-
- if (capnum > 0 && capnum < match_caps) {
- DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */
-
- /* regexp res_obj is at offset 4 */
- duk_get_prop_index(ctx, 4, (duk_uarridx_t) capnum);
- if (duk_is_string(ctx, -1)) {
- duk_hstring *h_tmp_str;
-
- h_tmp_str = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_tmp_str != NULL);
-
- DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
- } else {
- /* undefined -> skip (replaced with empty) */
- }
- duk_pop(ctx);
- r += capadv;
- continue;
- } else {
- goto repl_write;
- }
-#else /* DUK_USE_REGEXP_SUPPORT */
- goto repl_write; /* unconditionally */
-#endif /* DUK_USE_REGEXP_SUPPORT */
- } /* default case */
- } /* switch (ch2) */
-
- repl_write:
- /* ch1 = (r_increment << 8) + byte */
-
- DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff));
- r += ch1 >> 8;
- } /* while repl */
- } /* if (is_repl_func) */
-
- duk_pop(ctx); /* pop regexp res_obj or match string */
-
-#ifdef DUK_USE_REGEXP_SUPPORT
- if (!is_global) {
-#else
- { /* unconditionally; is_global==0 */
-#endif
- break;
- }
- }
-
- /* trailer */
- tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
- DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
-
- DUK_ASSERT_TOP(ctx, 4);
- DUK_BW_COMPACT(thr, bw);
- duk_to_string(ctx, -1);
- return 1;
-}
-
-/*
- * split()
- */
-
-/* XXX: very messy now, but works; clean up, remove unused variables (nomimally
- * used so compiler doesn't complain).
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_input;
- duk_hstring *h_sep;
- duk_uint32_t limit;
- duk_uint32_t arr_idx;
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_bool_t is_regexp;
-#endif
- duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */
- duk_uint32_t prev_match_end_coff, prev_match_end_boff;
- duk_uint32_t match_start_boff, match_start_coff;
- duk_uint32_t match_end_boff, match_end_coff;
-
- DUK_UNREF(thr);
-
- h_input = duk_push_this_coercible_to_string(ctx);
- DUK_ASSERT(h_input != NULL);
-
- duk_push_array(ctx);
-
- if (duk_is_undefined(ctx, 1)) {
- limit = 0xffffffffUL;
- } else {
- limit = duk_to_uint32(ctx, 1);
- }
-
- if (limit == 0) {
- return 1;
- }
-
- /* If the separator is a RegExp, make a "clone" of it. The specification
- * algorithm calls [[Match]] directly for specific indices; we emulate this
- * by tweaking lastIndex and using a "force global" variant of duk_regexp_match()
- * which will use global-style matching even when the RegExp itself is non-global.
- */
-
- if (duk_is_undefined(ctx, 0)) {
- /* The spec algorithm first does "R = ToString(separator)" before checking
- * whether separator is undefined. Since this is side effect free, we can
- * skip the ToString() here.
- */
- duk_dup(ctx, 2);
- duk_put_prop_index(ctx, 3, 0);
- return 1;
- } else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
- duk_dup(ctx, 0);
- duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
- duk_replace(ctx, 0);
- /* lastIndex is initialized to zero by new RegExp() */
- is_regexp = 1;
-#else
- return DUK_RET_UNSUPPORTED_ERROR;
-#endif
- } else {
- duk_to_string(ctx, 0);
-#ifdef DUK_USE_REGEXP_SUPPORT
- is_regexp = 0;
-#endif
- }
-
- /* stack[0] = separator (string or regexp)
- * stack[1] = limit
- * stack[2] = input string
- * stack[3] = result array
- */
-
- prev_match_end_boff = 0;
- prev_match_end_coff = 0;
- arr_idx = 0;
- matched = 0;
-
- for (;;) {
- /*
- * The specification uses RegExp [[Match]] to attempt match at specific
- * offsets. We don't have such a primitive, so we use an actual RegExp
- * and tweak lastIndex. Since the RegExp may be non-global, we use a
- * special variant which forces global-like behavior for matching.
- */
-
- DUK_ASSERT_TOP(ctx, 4);
-
-#ifdef DUK_USE_REGEXP_SUPPORT
- if (is_regexp) {
- duk_dup(ctx, 0);
- duk_dup(ctx, 2);
- duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
- break;
- }
- matched = 1;
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_start_coff = duk_get_int(ctx, -1);
- match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
- duk_pop(ctx);
-
- if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
- /* don't allow an empty match at the end of the string */
- duk_pop(ctx);
- break;
- }
-
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- match_end_coff = duk_get_int(ctx, -1);
- match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
- duk_pop(ctx);
-
- /* empty match -> bump and continue */
- if (prev_match_end_boff == match_end_boff) {
- duk_push_int(ctx, match_end_coff + 1);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- duk_pop(ctx);
- continue;
- }
- } else {
-#else /* DUK_USE_REGEXP_SUPPORT */
- { /* unconditionally */
-#endif /* DUK_USE_REGEXP_SUPPORT */
- const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
- const duk_uint8_t *q_start; /* match string */
- duk_size_t q_blen, q_clen;
-
- p_start = DUK_HSTRING_GET_DATA(h_input);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
- p = p_start + prev_match_end_boff;
-
- h_sep = duk_get_hstring(ctx, 0);
- DUK_ASSERT(h_sep != NULL);
- q_start = DUK_HSTRING_GET_DATA(h_sep);
- q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
- q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
-
- p_end -= q_blen; /* ensure full memcmp() fits in while */
-
- match_start_coff = prev_match_end_coff;
-
- if (q_blen == 0) {
- /* Handle empty separator case: it will always match, and always
- * triggers the check in step 13.c.iii initially. Note that we
- * must skip to either end of string or start of first codepoint,
- * skipping over any continuation bytes!
- *
- * Don't allow an empty string to match at the end of the input.
- */
-
- matched = 1; /* empty separator can always match */
-
- match_start_coff++;
- p++;
- while (p < p_end) {
- if ((p[0] & 0xc0) != 0x80) {
- goto found;
- }
- p++;
- }
- goto not_found;
- }
-
- DUK_ASSERT(q_blen > 0 && q_clen > 0);
- while (p <= p_end) {
- DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
- DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */
- if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
- /* never an empty match, so step 13.c.iii can't be triggered */
- goto found;
- }
-
- /* track utf-8 non-continuation bytes */
- if ((p[0] & 0xc0) != 0x80) {
- match_start_coff++;
- }
- p++;
- }
-
- not_found:
- /* not found */
- break;
-
- found:
- matched = 1;
- match_start_boff = (duk_uint32_t) (p - p_start);
- match_end_coff = (duk_uint32_t) (match_start_coff + q_clen); /* constrained by string length */
- match_end_boff = (duk_uint32_t) (match_start_boff + q_blen); /* ditto */
-
- /* empty match (may happen with empty separator) -> bump and continue */
- if (prev_match_end_boff == match_end_boff) {
- prev_match_end_boff++;
- prev_match_end_coff++;
- continue;
- }
- } /* if (is_regexp) */
-
- /* stack[0] = separator (string or regexp)
- * stack[1] = limit
- * stack[2] = input string
- * stack[3] = result array
- * stack[4] = regexp res_obj (if is_regexp)
- */
-
- DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld",
- (long) match_start_boff, (long) match_start_coff,
- (long) match_end_boff, (long) match_end_coff,
- (long) prev_match_end_boff, (long) prev_match_end_coff));
-
- duk_push_lstring(ctx,
- (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
- (duk_size_t) (match_start_boff - prev_match_end_boff));
- duk_put_prop_index(ctx, 3, arr_idx);
- arr_idx++;
- if (arr_idx >= limit) {
- goto hit_limit;
- }
-
-#ifdef DUK_USE_REGEXP_SUPPORT
- if (is_regexp) {
- duk_size_t i, len;
-
- len = duk_get_length(ctx, 4);
- for (i = 1; i < len; i++) {
- DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */
- duk_get_prop_index(ctx, 4, (duk_uarridx_t) i);
- duk_put_prop_index(ctx, 3, arr_idx);
- arr_idx++;
- if (arr_idx >= limit) {
- goto hit_limit;
- }
- }
-
- duk_pop(ctx);
- /* lastIndex already set up for next match */
- } else {
-#else /* DUK_USE_REGEXP_SUPPORT */
- { /* unconditionally */
-#endif /* DUK_USE_REGEXP_SUPPORT */
- /* no action */
- }
-
- prev_match_end_boff = match_end_boff;
- prev_match_end_coff = match_end_coff;
- continue;
- } /* for */
-
- /* Combined step 11 (empty string special case) and 14-15. */
-
- DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld",
- (long) prev_match_end_boff, (long) prev_match_end_coff));
-
- if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) {
- /* Add trailer if:
- * a) non-empty input
- * b) empty input and no (zero size) match found (step 11)
- */
-
- duk_push_lstring(ctx,
- (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
- (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
- duk_put_prop_index(ctx, 3, arr_idx);
- /* No arr_idx update or limit check */
- }
-
- return 1;
-
- hit_limit:
-#ifdef DUK_USE_REGEXP_SUPPORT
- if (is_regexp) {
- duk_pop(ctx);
- }
-#endif
-
- return 1;
-}
-
-/*
- * Various
- */
-
-#ifdef DUK_USE_REGEXP_SUPPORT
-DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t index, duk_bool_t force_new) {
- duk_hobject *h;
-
- /* Shared helper for match() steps 3-4, search() steps 3-4. */
-
- DUK_ASSERT(index >= 0);
-
- if (force_new) {
- goto do_new;
- }
-
- h = duk_get_hobject_with_class(ctx, index, DUK_HOBJECT_CLASS_REGEXP);
- if (!h) {
- goto do_new;
- }
- return;
-
- do_new:
- duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
- duk_dup(ctx, index);
- duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
- duk_replace(ctx, index);
-}
-#endif /* DUK_USE_REGEXP_SUPPORT */
-
-#ifdef DUK_USE_REGEXP_SUPPORT
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
-
- /* Easiest way to implement the search required by the specification
- * is to do a RegExp test() with lastIndex forced to zero. To avoid
- * side effects on the argument, "clone" the RegExp if a RegExp was
- * given as input.
- *
- * The global flag of the RegExp should be ignored; setting lastIndex
- * to zero (which happens when "cloning" the RegExp) should have an
- * equivalent effect.
- */
-
- DUK_ASSERT_TOP(ctx, 1);
- (void) duk_push_this_coercible_to_string(ctx); /* at index 1 */
- duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/);
-
- /* stack[0] = regexp
- * stack[1] = string
- */
-
- /* Avoid using RegExp.prototype methods, as they're writable and
- * configurable and may have been changed.
- */
-
- duk_dup(ctx, 0);
- duk_dup(ctx, 1); /* [ ... re_obj input ] */
- duk_regexp_match(thr); /* -> [ ... res_obj ] */
-
- if (!duk_is_object(ctx, -1)) {
- duk_push_int(ctx, -1);
- return 1;
- }
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- return 1;
-}
-#else /* DUK_USE_REGEXP_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_REGEXP_SUPPORT */
-
-#ifdef DUK_USE_REGEXP_SUPPORT
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_bool_t global;
- duk_int_t prev_last_index;
- duk_int_t this_index;
- duk_int_t arr_idx;
-
- DUK_ASSERT_TOP(ctx, 1);
- (void) duk_push_this_coercible_to_string(ctx);
- duk__to_regexp_helper(ctx, 0 /*index*/, 0 /*force_new*/);
- global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
- DUK_ASSERT_TOP(ctx, 2);
-
- /* stack[0] = regexp
- * stack[1] = string
- */
-
- if (!global) {
- duk_regexp_match(thr); /* -> [ res_obj ] */
- return 1; /* return 'res_obj' */
- }
-
- /* Global case is more complex. */
-
- /* [ regexp string ] */
-
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- duk_push_array(ctx);
-
- /* [ regexp string res_arr ] */
-
- prev_last_index = 0;
- arr_idx = 0;
-
- for (;;) {
- DUK_ASSERT_TOP(ctx, 3);
-
- duk_dup(ctx, 0);
- duk_dup(ctx, 1);
- duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */
-
- if (!duk_is_object(ctx, -1)) {
- duk_pop(ctx);
- break;
- }
-
- duk_get_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- DUK_ASSERT(duk_is_number(ctx, -1));
- this_index = duk_get_int(ctx, -1);
- duk_pop(ctx);
-
- if (this_index == prev_last_index) {
- this_index++;
- duk_push_int(ctx, this_index);
- duk_put_prop_stridx(ctx, 0, DUK_STRIDX_LAST_INDEX);
- }
- prev_last_index = this_index;
-
- duk_get_prop_index(ctx, -1, 0); /* match string */
- duk_put_prop_index(ctx, 2, arr_idx);
- arr_idx++;
- duk_pop(ctx); /* res_obj */
- }
-
- if (arr_idx == 0) {
- duk_push_null(ctx);
- }
-
- return 1; /* return 'res_arr' or 'null' */
-}
-#else /* DUK_USE_REGEXP_SUPPORT */
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_UNSUPPORTED_ERROR;
-}
-#endif /* DUK_USE_REGEXP_SUPPORT */
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx) {
- /* duk_concat() coerces arguments with ToString() in correct order */
- (void) duk_push_this_coercible_to_string(ctx);
- duk_insert(ctx, 0); /* this is relatively expensive */
- duk_concat(ctx, duk_get_top(ctx));
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx) {
- DUK_ASSERT_TOP(ctx, 0);
- (void) duk_push_this_coercible_to_string(ctx);
- duk_trim(ctx, 0);
- DUK_ASSERT_TOP(ctx, 1);
- return 1;
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx) {
- duk_hstring *h1;
- duk_hstring *h2;
- duk_size_t h1_len, h2_len, prefix_len;
- duk_small_int_t ret = 0;
- duk_small_int_t rc;
-
- /* The current implementation of localeCompare() is simply a codepoint
- * by codepoint comparison, implemented with a simple string compare
- * because UTF-8 should preserve codepoint ordering (assuming valid
- * shortest UTF-8 encoding).
- *
- * The specification requires that the return value must be related
- * to the sort order: e.g. negative means that 'this' comes before
- * 'that' in sort order. We assume an ascending sort order.
- */
-
- /* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */
-
- h1 = duk_push_this_coercible_to_string(ctx);
- DUK_ASSERT(h1 != NULL);
-
- h2 = duk_to_hstring(ctx, 0);
- DUK_ASSERT(h2 != NULL);
-
- h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
- h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
- prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
-
- /* Zero size compare not an issue with DUK_MEMCMP. */
- rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1),
- (const void *) DUK_HSTRING_GET_DATA(h2),
- (size_t) prefix_len);
-
- if (rc < 0) {
- ret = -1;
- goto done;
- } else if (rc > 0) {
- ret = 1;
- goto done;
- }
-
- /* prefix matches, lengths matter now */
- if (h1_len > h2_len) {
- ret = 1;
- goto done;
- } else if (h1_len == h2_len) {
- DUK_ASSERT(ret == 0);
- goto done;
- }
- ret = -1;
- goto done;
-
- done:
- duk_push_int(ctx, (duk_int_t) ret);
- return 1;
-}
-#line 1 "duk_bi_thread.c"
-/*
- * Thread builtins
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Constructor
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
- duk_hthread *new_thr;
- duk_hobject *func;
-
- /* XXX: need a duk_require_func_or_lfunc_coerce() */
- if (!duk_is_callable(ctx, 0)) {
- return DUK_RET_TYPE_ERROR;
- }
- func = duk_require_hobject_or_lfunc_coerce(ctx, 0);
- DUK_ASSERT(func != NULL);
-
- duk_push_thread(ctx);
- new_thr = (duk_hthread *) duk_get_hobject(ctx, -1);
- DUK_ASSERT(new_thr != NULL);
- new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
-
- /* push initial function call to new thread stack; this is
- * picked up by resume().
- */
- duk_push_hobject((duk_context *) new_thr, func);
-
- return 1; /* return thread */
-}
-
-/*
- * Resume a thread.
- *
- * The thread must be in resumable state, either (a) new thread which hasn't
- * yet started, or (b) a thread which has previously yielded. This method
- * must be called from an Ecmascript function.
- *
- * Args:
- * - thread
- * - value
- * - isError (defaults to false)
- *
- * Note: yield and resume handling is currently asymmetric.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hthread *thr_resume;
- duk_tval *tv;
- duk_hobject *func;
- duk_hobject *caller_func;
- duk_small_int_t is_error;
-
- DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1),
- (duk_tval *) duk_get_tval(ctx, 2)));
-
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
- DUK_ASSERT(thr->heap->curr_thread == thr);
-
- thr_resume = duk_require_hthread(ctx, 0);
- is_error = (duk_small_int_t) duk_to_boolean(ctx, 2);
- duk_set_top(ctx, 2);
-
- /* [ thread value ] */
-
- /*
- * Thread state and calling context checks
- */
-
- if (thr->callstack_top < 2) {
- DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
- goto state_error;
- }
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
- DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
-
- caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
- DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"));
- goto state_error;
- }
-
- /* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
- * like for yield.
- */
-
- if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
- thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
- DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"));
- goto state_error;
- }
-
- DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
- thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
-
- /* Further state-dependent pre-checks */
-
- if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
- /* no pre-checks now, assume a previous yield() has left things in
- * tip-top shape (longjmp handler will assert for these).
- */
- } else {
- DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
-
- if ((thr_resume->callstack_top != 0) ||
- (thr_resume->valstack_top - thr_resume->valstack != 1)) {
- goto state_invalid_initial;
- }
- tv = &thr_resume->valstack_top[-1];
- DUK_ASSERT(tv >= thr_resume->valstack && tv < thr_resume->valstack_top);
- if (!DUK_TVAL_IS_OBJECT(tv)) {
- goto state_invalid_initial;
- }
- func = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(func != NULL);
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- /* Note: cannot be a bound function either right now,
- * this would be easy to relax though.
- */
- goto state_invalid_initial;
- }
-
- }
-
- /*
- * The error object has been augmented with a traceback and other
- * info from its creation point -- usually another thread. The
- * error handler is called here right before throwing, but it also
- * runs in the resumer's thread. It might be nice to get a traceback
- * from the resumee but this is not the case now.
- */
-
-#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- if (is_error) {
- DUK_ASSERT_TOP(ctx, 2); /* value (error) is at stack top */
- duk_err_augment_error_throw(thr); /* in resumer's context */
- }
-#endif
-
-#ifdef DUK_USE_DEBUG
- if (is_error) {
- DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
- } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
- DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
- } else {
- DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
- }
-#endif
-
- thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
-
- /* lj value2: thread */
- DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]); /* side effects */
-
- /* lj value1: value */
- DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */
- DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
-
- thr->heap->lj.iserror = is_error;
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
- duk_err_longjmp(thr); /* execution resumes in bytecode executor */
- return 0; /* never here */
-
- state_invalid_initial:
- DUK_ERROR_TYPE(thr, "invalid initial thread state/stack");
- return 0; /* never here */
-
- state_error:
- DUK_ERROR_TYPE(thr, "invalid state");
- return 0; /* never here */
-}
-
-/*
- * Yield the current thread.
- *
- * The thread must be in yieldable state: it must have a resumer, and there
- * must not be any yield-preventing calls (native calls and constructor calls,
- * currently) in the thread's call stack (otherwise a resume would not be
- * possible later). This method must be called from an Ecmascript function.
- *
- * Args:
- * - value
- * - isError (defaults to false)
- *
- * Note: yield and resume handling is currently asymmetric.
- */
-
-DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *caller_func;
- duk_small_int_t is_error;
-
- DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
- (duk_tval *) duk_get_tval(ctx, 0),
- (duk_tval *) duk_get_tval(ctx, 1)));
-
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
- DUK_ASSERT(thr->heap->curr_thread == thr);
-
- is_error = (duk_small_int_t) duk_to_boolean(ctx, 1);
- duk_set_top(ctx, 1);
-
- /* [ value ] */
-
- /*
- * Thread state and calling context checks
- */
-
- if (!thr->resumer) {
- DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer"));
- goto state_error;
- }
- DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
-
- if (thr->callstack_top < 2) {
- DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
- goto state_error;
- }
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
- DUK_ASSERT(DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
-
- caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(caller_func)) {
- DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"));
- goto state_error;
- }
-
- DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
- if (thr->callstack_preventcount != 1) {
- /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
- DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)",
- (long) thr->callstack_preventcount));
- goto state_error;
- }
-
- /*
- * The error object has been augmented with a traceback and other
- * info from its creation point -- usually the current thread.
- * The error handler, however, is called right before throwing
- * and runs in the yielder's thread.
- */
-
-#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- if (is_error) {
- DUK_ASSERT_TOP(ctx, 1); /* value (error) is at stack top */
- duk_err_augment_error_throw(thr); /* in yielder's context */
- }
-#endif
-
-#ifdef DUK_USE_DEBUG
- if (is_error) {
- DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0)));
- } else {
- DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
- (duk_tval *) duk_get_tval(ctx, 0)));
- }
-#endif
-
- /*
- * Process yield
- *
- * After longjmp(), processing continues in bytecode executor longjmp
- * handler, which will e.g. update thr->resumer to NULL.
- */
-
- thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
-
- /* lj value1: value */
- DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */
- DUK_TVAL_CHKFAST_INPLACE(&thr->heap->lj.value1);
-
- thr->heap->lj.iserror = is_error;
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
- duk_err_longjmp(thr); /* execution resumes in bytecode executor */
- return 0; /* never here */
-
- state_error:
- DUK_ERROR_TYPE(thr, "invalid state");
- return 0; /* never here */
-}
-
-DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_context *ctx) {
- duk_push_current_thread(ctx);
- return 1;
-}
-#line 1 "duk_bi_thrower.c"
-/*
- * Type error thrower, E5 Section 13.2.3.
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx) {
- DUK_UNREF(ctx);
- return DUK_RET_TYPE_ERROR;
-}
-#line 1 "duk_debug_fixedbuffer.c"
-/*
- * Fixed buffer helper useful for debugging, requires no allocation
- * which is critical for debugging.
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_DEBUG
-
-DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
- duk_size_t avail;
- duk_size_t copylen;
-
- avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
- if (length > avail) {
- copylen = avail;
- fb->truncated = 1;
- } else {
- copylen = length;
- }
- DUK_MEMCPY(fb->buffer + fb->offset, buffer, copylen);
- fb->offset += copylen;
-}
-
-DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
- duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1);
-}
-
-DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
- duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
-}
-
-DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
- duk_size_t avail;
- va_list ap;
-
- va_start(ap, fmt);
- avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
- if (avail > 0) {
- duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap);
- if (res < 0) {
- /* error */
- } else if ((duk_size_t) res >= avail) {
- /* (maybe) truncated */
- fb->offset += avail;
- if ((duk_size_t) res > avail) {
- /* actual chars dropped (not just NUL term) */
- fb->truncated = 1;
- }
- } else {
- /* normal */
- fb->offset += res;
- }
- }
- va_end(ap);
-}
-
-DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) {
- char buf[64+1];
- duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size);
- buf[sizeof(buf) - 1] = (char) 0;
- duk_fb_put_cstring(fb, buf);
-}
-
-DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
- return (fb->offset >= fb->length);
-}
-
-#endif /* DUK_USE_DEBUG */
-#line 1 "duk_debug_heap.c"
-/*
- * Debug dumping of duk_heap.
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_DEBUG
-
-#if 0 /*unused*/
-DUK_LOCAL void duk__sanitize_snippet(char *buf, duk_size_t buf_size, duk_hstring *str) {
- duk_size_t i;
- duk_size_t nchars;
- duk_size_t maxchars;
- duk_uint8_t *data;
-
- DUK_MEMZERO(buf, buf_size);
-
- maxchars = (duk_size_t) (buf_size - 1);
- data = DUK_HSTRING_GET_DATA(str);
- nchars = ((duk_size_t) str->blen < maxchars ? (duk_size_t) str->blen : maxchars);
- for (i = 0; i < nchars; i++) {
- duk_small_int_t c = (duk_small_int_t) data[i];
- if (c < 0x20 || c > 0x7e) {
- c = '.';
- }
- buf[i] = (char) c;
- }
-}
-#endif
-
-#if 0
-DUK_LOCAL const char *duk__get_heap_type_string(duk_heaphdr *hdr) {
- switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
- case DUK_HTYPE_STRING:
- return "string";
- case DUK_HTYPE_OBJECT:
- return "object";
- case DUK_HTYPE_BUFFER:
- return "buffer";
- default:
- return "???";
- }
-}
-#endif
-
-#if 0
-DUK_LOCAL void duk__dump_indented(duk_heaphdr *obj, int index) {
- DUK_UNREF(obj);
- DUK_UNREF(index);
- DUK_UNREF(duk__get_heap_type_string);
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx, ref: %ld) -> %!O",
- (long) index,
- (void *) obj,
- (const char *) duk__get_heap_type_string(obj),
- (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj),
- (long) DUK_HEAPHDR_GET_REFCOUNT(obj),
- (duk_heaphdr *) obj));
-#else
- DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx) -> %!O",
- (long) index,
- (void *) obj,
- (const char *) duk__get_heap_type_string(obj),
- (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj),
- (duk_heaphdr *) obj));
-#endif
-}
-#endif
-
-#if 0 /*unused*/
-DUK_LOCAL void duk__dump_heaphdr_list(duk_heap *heap, duk_heaphdr *root, const char *name) {
- duk_int_t count;
- duk_heaphdr *curr;
-
- DUK_UNREF(heap);
- DUK_UNREF(name);
-
- count = 0;
- curr = root;
- while (curr) {
- count++;
- curr = DUK_HEAPHDR_GET_NEXT(curr);
- }
-
- DUK_D(DUK_DPRINT("%s, %ld objects", (const char *) name, (long) count));
-
- count = 0;
- curr = root;
- while (curr) {
- count++;
- duk__dump_indented(curr, count);
- curr = DUK_HEAPHDR_GET_NEXT(curr);
- }
-}
-#endif
-
-#if 0 /*unused*/
-DUK_LOCAL void duk__dump_stringtable(duk_heap *heap) {
- duk_uint_fast32_t i;
- char buf[64+1];
-
- DUK_D(DUK_DPRINT("stringtable %p, used %ld, size %ld, load %ld%%",
- (void *) heap->strtable,
- (long) heap->st_used,
- (long) heap->st_size,
- (long) (((double) heap->st_used) / ((double) heap->st_size) * 100.0)));
-
- for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
- duk_hstring *e = heap->strtable[i];
-
- if (!e) {
- DUK_D(DUK_DPRINT(" [%ld]: NULL", (long) i));
- } else if (e == DUK_STRTAB_DELETED_MARKER(heap)) {
- DUK_D(DUK_DPRINT(" [%ld]: DELETED", (long) i));
- } else {
- duk__sanitize_snippet(buf, sizeof(buf), e);
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_D(DUK_DPRINT(" [%ld]: %p (flags: 0x%08lx, ref: %ld) '%s', strhash=0x%08lx, blen=%ld, clen=%ld, "
- "arridx=%ld, internal=%ld, reserved_word=%ld, strict_reserved_word=%ld, eval_or_arguments=%ld",
- (long) i,
- (void *) e,
- (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
- (long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) e),
- (const char *) buf,
- (unsigned long) e->hash,
- (long) e->blen,
- (long) e->clen,
- (long) (DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0)));
-#else
- DUK_D(DUK_DPRINT(" [%ld]: %p (flags: 0x%08lx) '%s', strhash=0x%08lx, blen=%ld, clen=%ld, "
- "arridx=%ld, internal=%ld, reserved_word=%ld, strict_reserved_word=%ld, eval_or_arguments=%ld",
- (long) i,
- (void *) e,
- (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) e),
- (const char *) buf,
- (long) e->hash,
- (long) e->blen,
- (long) e->clen,
- (long) (DUK_HSTRING_HAS_ARRIDX(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_INTERNAL(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_RESERVED_WORD(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(e) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(e) ? 1 : 0)));
-#endif
- }
- }
-}
-#endif
-
-#if 0 /*unused*/
-DUK_LOCAL void duk__dump_strcache(duk_heap *heap) {
- duk_uint_fast32_t i;
- char buf[64+1];
-
- DUK_D(DUK_DPRINT("stringcache"));
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = &heap->strcache[i];
- if (!c->h) {
- DUK_D(DUK_DPRINT(" [%ld]: bidx=%ld, cidx=%ld, str=NULL",
- (long) i, (long) c->bidx, (long) c->cidx));
- } else {
- duk__sanitize_snippet(buf, sizeof(buf), c->h);
- DUK_D(DUK_DPRINT(" [%ld]: bidx=%ld cidx=%ld str=%s",
- (long) i, (long) c->bidx, (long) c->cidx, (const char *) buf));
- }
- }
-}
-#endif
-
-#if 0 /*unused*/
-DUK_INTERNAL void duk_debug_dump_heap(duk_heap *heap) {
- char buf[64+1];
-
- DUK_D(DUK_DPRINT("=== heap %p ===", (void *) heap));
- DUK_D(DUK_DPRINT(" flags: 0x%08lx", (unsigned long) heap->flags));
-
- /* Note: there is no standard formatter for function pointers */
-#ifdef DUK_USE_GCC_PRAGMAS
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-pedantic"
-#endif
- duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->alloc_func, sizeof(heap->alloc_func));
- DUK_D(DUK_DPRINT(" alloc_func: %s", (const char *) buf));
- duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->realloc_func, sizeof(heap->realloc_func));
- DUK_D(DUK_DPRINT(" realloc_func: %s", (const char *) buf));
- duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->free_func, sizeof(heap->free_func));
- DUK_D(DUK_DPRINT(" free_func: %s", (const char *) buf));
- duk_debug_format_funcptr(buf, sizeof(buf), (duk_uint8_t *) &heap->fatal_func, sizeof(heap->fatal_func));
- DUK_D(DUK_DPRINT(" fatal_func: %s", (const char *) buf));
-#ifdef DUK_USE_GCC_PRAGMAS
-#pragma GCC diagnostic pop
-#endif
-
- DUK_D(DUK_DPRINT(" heap_udata: %p", (void *) heap->heap_udata));
-
-#ifdef DUK_USE_MARK_AND_SWEEP
-#ifdef DUK_USE_VOLUNTARY_GC
- DUK_D(DUK_DPRINT(" mark-and-sweep trig counter: %ld", (long) heap->mark_and_sweep_trigger_counter));
-#endif
- DUK_D(DUK_DPRINT(" mark-and-sweep rec depth: %ld", (long) heap->mark_and_sweep_recursion_depth));
- DUK_D(DUK_DPRINT(" mark-and-sweep base flags: 0x%08lx", (unsigned long) heap->mark_and_sweep_base_flags));
-#endif
-
- DUK_D(DUK_DPRINT(" lj.jmpbuf_ptr: %p", (void *) heap->lj.jmpbuf_ptr));
- DUK_D(DUK_DPRINT(" lj.type: %ld", (long) heap->lj.type));
- DUK_D(DUK_DPRINT(" lj.value1: %!T", (duk_tval *) &heap->lj.value1));
- DUK_D(DUK_DPRINT(" lj.value2: %!T", (duk_tval *) &heap->lj.value2));
- DUK_D(DUK_DPRINT(" lj.iserror: %ld", (long) heap->lj.iserror));
-
- DUK_D(DUK_DPRINT(" handling_error: %ld", (long) heap->handling_error));
-
- DUK_D(DUK_DPRINT(" heap_thread: %!@O", (duk_heaphdr *) heap->heap_thread));
- DUK_D(DUK_DPRINT(" curr_thread: %!@O", (duk_heaphdr *) heap->curr_thread));
- DUK_D(DUK_DPRINT(" heap_object: %!@O", (duk_heaphdr *) heap->heap_object));
-
- DUK_D(DUK_DPRINT(" call_recursion_depth: %ld", (long) heap->call_recursion_depth));
- DUK_D(DUK_DPRINT(" call_recursion_limit: %ld", (long) heap->call_recursion_limit));
-
- DUK_D(DUK_DPRINT(" hash_seed: 0x%08lx", (unsigned long) heap->hash_seed));
- DUK_D(DUK_DPRINT(" rnd_state: 0x%08lx", (unsigned long) heap->rnd_state));
-
- duk__dump_strcache(heap);
-
- duk__dump_heaphdr_list(heap, heap->heap_allocated, "heap allocated");
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__dump_heaphdr_list(heap, heap->refzero_list, "refcounting refzero list");
-#endif
-
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk__dump_heaphdr_list(heap, heap->finalize_list, "mark-and-sweep finalize list");
-#endif
-
- duk__dump_stringtable(heap);
-
- /* heap->strs: not worth dumping */
-}
-#endif
-
-#endif /* DUK_USE_DEBUG */
-#line 1 "duk_debug_vsnprintf.c"
-/*
- * Custom formatter for debug printing, allowing Duktape specific data
- * structures (such as tagged values and heap objects) to be printed with
- * a nice format string. Because debug printing should not affect execution
- * state, formatting here must be independent of execution (see implications
- * below) and must not allocate memory.
- *
- * Custom format tags begin with a '%!' to safely distinguish them from
- * standard format tags. The following conversions are supported:
- *
- * %!T tagged value (duk_tval *)
- * %!O heap object (duk_heaphdr *)
- * %!I decoded bytecode instruction
- * %!C bytecode instruction opcode name (arg is long)
- *
- * Everything is serialized in a JSON-like manner. The default depth is one
- * level, internal prototype is not followed, and internal properties are not
- * serialized. The following modifiers change this behavior:
- *
- * @ print pointers
- * # print binary representations (where applicable)
- * d deep traversal of own properties (not prototype)
- * p follow prototype chain (useless without 'd')
- * i include internal properties (other than prototype)
- * x hexdump buffers
- * h heavy formatting
- *
- * For instance, the following serializes objects recursively, but does not
- * follow the prototype chain nor print internal properties: "%!dO".
- *
- * Notes:
- *
- * * Standard snprintf return value semantics seem to vary. This
- * implementation returns the number of bytes it actually wrote
- * (excluding the null terminator). If retval == buffer size,
- * output was truncated (except for corner cases).
- *
- * * Output format is intentionally different from Ecmascript
- * formatting requirements, as formatting here serves debugging
- * of internals.
- *
- * * Depth checking (and updating) is done in each type printer
- * separately, to allow them to call each other freely.
- *
- * * Some pathological structures might take ages to print (e.g.
- * self recursion with 100 properties pointing to the object
- * itself). To guard against these, each printer also checks
- * whether the output buffer is full; if so, early exit.
- *
- * * Reference loops are detected using a loop stack.
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_DEBUG
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-
-/* list of conversion specifiers that terminate a format tag;
- * this is unfortunately guesswork.
- */
-#define DUK__ALLOWED_STANDARD_SPECIFIERS "diouxXeEfFgGaAcsCSpnm"
-
-/* maximum length of standard format tag that we support */
-#define DUK__MAX_FORMAT_TAG_LENGTH 32
-
-/* heapobj recursion depth when deep printing is selected */
-#define DUK__DEEP_DEPTH_LIMIT 8
-
-/* maximum recursion depth for loop detection stacks */
-#define DUK__LOOP_STACK_DEPTH 256
-
-/* must match bytecode defines now; build autogenerate? */
-DUK_LOCAL const char *duk__bc_optab[64] = {
- "LDREG", "STREG", "LDCONST", "LDINT", "LDINTX", "MPUTOBJ", "MPUTOBJI", "MPUTARR", "MPUTARRI", "NEW",
- "NEWI", "REGEXP", "CSREG", "CSREGI", "GETVAR", "PUTVAR", "DECLVAR", "DELVAR", "CSVAR", "CSVARI",
- "CLOSURE", "GETPROP", "PUTPROP", "DELPROP", "CSPROP", "CSPROPI", "ADD", "SUB", "MUL", "DIV",
- "MOD", "BAND", "BOR", "BXOR", "BASL", "BLSR", "BASR", "EQ", "NEQ", "SEQ",
- "SNEQ", "GT", "GE", "LT", "LE", "IF", "JUMP", "RETURN", "CALL", "CALLI",
- "TRYCATCH", "EXTRA", "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
- "PREINCP", "PREDECP", "POSTINCP", "POSTDECP"
-};
-
-DUK_LOCAL const char *duk__bc_extraoptab[256] = {
- "NOP", "INVALID", "LDTHIS", "LDUNDEF", "LDNULL", "LDTRUE", "LDFALSE", "NEWOBJ", "NEWARR", "SETALEN",
- "TYPEOF", "TYPEOFID", "INITENUM", "NEXTENUM", "INITSET", "INITSETI", "INITGET", "INITGETI", "ENDTRY", "ENDCATCH",
- "ENDFIN", "THROW", "INVLHS", "UNM", "UNP", "DEBUGGER", "BREAK", "CONTINUE", "BNOT", "LNOT",
- "INSTOF", "IN", "LABEL", "ENDLABEL", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX", "XXX",
-
- "XXX", "XXX", "XXX", "XXX", "XXX", "XXX"
-};
-
-typedef struct duk__dprint_state duk__dprint_state;
-struct duk__dprint_state {
- duk_fixedbuffer *fb;
-
- /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice
- * to not couple these two mechanisms unnecessarily.
- */
- duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH];
- duk_int_t loop_stack_index;
- duk_int_t loop_stack_limit;
-
- duk_int_t depth;
- duk_int_t depth_limit;
-
- duk_bool_t pointer;
- duk_bool_t heavy;
- duk_bool_t binary;
- duk_bool_t follow_proto;
- duk_bool_t internal;
- duk_bool_t hexdump;
-};
-
-/* helpers */
-DUK_LOCAL_DECL void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, duk_bool_t quotes);
-DUK_LOCAL_DECL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h);
-DUK_LOCAL_DECL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h);
-DUK_LOCAL_DECL void duk__print_tval(duk__dprint_state *st, duk_tval *tv);
-DUK_LOCAL_DECL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins);
-DUK_LOCAL_DECL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
-DUK_LOCAL_DECL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
-DUK_LOCAL_DECL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h);
-
-DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
- duk_fixedbuffer *fb = st->fb;
-
- if (st->heavy) {
- duk_fb_sprintf(fb, "(%p)", (void *) h);
- }
-
- if (!h) {
- return;
- }
-
- if (st->binary) {
- duk_size_t i;
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
- for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
- duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
- }
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
- }
-
-#ifdef DUK_USE_REFERENCE_COUNTING /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
- if (st->heavy) {
- duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld,"
- "reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
- (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
- (void *) DUK_HEAPHDR_GET_PREV(NULL, h),
- (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(h),
- (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
- (long) DUK_HEAPHDR_GET_TYPE(h),
- (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
- }
-#else
- if (st->heavy) {
- duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
- (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
- (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
- (long) DUK_HEAPHDR_GET_TYPE(h),
- (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
- }
-#endif
-}
-
-DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) {
- duk_fixedbuffer *fb = st->fb;
-
- if (st->heavy) {
- duk_fb_sprintf(fb, "(%p)", (void *) h);
- }
-
- if (!h) {
- return;
- }
-
- if (st->binary) {
- duk_size_t i;
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
- for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
- duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
- }
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
- }
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- if (st->heavy) {
- duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
- (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h),
- (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
- (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
- (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
- }
-#else
- if (st->heavy) {
- duk_fb_sprintf(fb, "[h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
- (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
- (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
- (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
- (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
- }
-#endif
-}
-
-DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_bool_t quotes) {
- duk_fixedbuffer *fb = st->fb;
- const duk_uint8_t *p;
- const duk_uint8_t *p_end;
-
- /* terminal type: no depth check */
-
- if (duk_fb_is_full(fb)) {
- return;
- }
-
- duk__print_shared_heaphdr_string(st, &h->hdr);
-
- if (!h) {
- duk_fb_put_cstring(fb, "NULL");
- return;
- }
-
- p = DUK_HSTRING_GET_DATA(h);
- p_end = p + DUK_HSTRING_GET_BYTELEN(h);
-
- if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) {
- /* if property key begins with underscore, encode it with
- * forced quotes (e.g. "_Foo") to distinguish it from encoded
- * internal properties (e.g. \xffBar -> _Bar).
- */
- quotes = 1;
- }
-
- if (quotes) {
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
- }
- while (p < p_end) {
- duk_uint8_t ch = *p++;
-
- /* two special escapes: '\' and '"', other printables as is */
- if (ch == '\\') {
- duk_fb_sprintf(fb, "\\\\");
- } else if (ch == '"') {
- duk_fb_sprintf(fb, "\\\"");
- } else if (ch >= 0x20 && ch <= 0x7e) {
- duk_fb_put_byte(fb, ch);
- } else if (ch == 0xff && !quotes) {
- /* encode \xffBar as _Bar if no quotes are applied, this is for
- * readable internal keys.
- */
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE);
- } else {
- duk_fb_sprintf(fb, "\\x%02lx", (unsigned long) ch);
- }
- }
- if (quotes) {
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
- }
-#ifdef DUK_USE_REFERENCE_COUNTING
- /* XXX: limit to quoted strings only, to save keys from being cluttered? */
- duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
-#endif
-}
-
-#ifdef DUK__COMMA
-#undef DUK__COMMA
-#endif
-#define DUK__COMMA() do { \
- if (first) { \
- first = 0; \
- } else { \
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); \
- } \
- } while (0)
-
-DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
- duk_fixedbuffer *fb = st->fb;
- duk_uint_fast32_t i;
- duk_tval *tv;
- duk_hstring *key;
- duk_bool_t first = 1;
- const char *brace1 = "{";
- const char *brace2 = "}";
- duk_bool_t pushed_loopstack = 0;
-
- if (duk_fb_is_full(fb)) {
- return;
- }
-
- duk__print_shared_heaphdr(st, &h->hdr);
-
- if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) {
- brace1 = "[";
- brace2 = "]";
- }
-
- if (!h) {
- duk_fb_put_cstring(fb, "NULL");
- goto finished;
- }
-
- if (st->depth >= st->depth_limit) {
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_fb_sprintf(fb, "%sobject/compiledfunction %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_fb_sprintf(fb, "%sobject/nativefunction %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
- } else if (DUK_HOBJECT_IS_THREAD(h)) {
- duk_fb_sprintf(fb, "%sobject/thread %p%s", (const char *) brace1, (void *) h, (const char *) brace2);
- } else {
- duk_fb_sprintf(fb, "%sobject %p%s", (const char *) brace1, (void *) h, (const char *) brace2); /* may be NULL */
- }
- return;
- }
-
- for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) {
- if (st->loop_stack[i] == h) {
- duk_fb_sprintf(fb, "%sLOOP:%p%s", (const char *) brace1, (void *) h, (const char *) brace2);
- return;
- }
- }
-
- /* after this, return paths should 'goto finished' for decrement */
- st->depth++;
-
- if (st->loop_stack_index >= st->loop_stack_limit) {
- duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", (const char *) brace1, (const char *) brace2);
- goto finished;
- }
- st->loop_stack[st->loop_stack_index++] = h;
- pushed_loopstack = 1;
-
- /*
- * Notation: double underscore used for internal properties which are not
- * stored in the property allocation (e.g. '__valstack').
- */
-
- duk_fb_put_cstring(fb, brace1);
-
- if (DUK_HOBJECT_GET_PROPS(NULL, h)) {
- duk_uint32_t a_limit;
-
- a_limit = DUK_HOBJECT_GET_ASIZE(h);
- if (st->internal) {
- /* dump all allocated entries, unused entries print as 'unused',
- * note that these may extend beyond current 'length' and look
- * a bit funny.
- */
- } else {
- /* leave out trailing 'unused' elements */
- while (a_limit > 0) {
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1);
- if (!DUK_TVAL_IS_UNUSED(tv)) {
- break;
- }
- a_limit--;
- }
- }
-
- for (i = 0; i < a_limit; i++) {
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i);
- DUK__COMMA();
- duk__print_tval(st, tv);
- }
- for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) {
- key = DUK_HOBJECT_E_GET_KEY(NULL, h, i);
- if (!key) {
- continue;
- }
- if (!st->internal &&
- DUK_HSTRING_GET_BYTELEN(key) > 0 &&
- DUK_HSTRING_GET_DATA(key)[0] == 0xff) {
- /* XXX: use DUK_HSTRING_FLAG_INTERNAL? */
- continue;
- }
- DUK__COMMA();
- duk__print_hstring(st, key, 0);
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON);
- if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) {
- duk_fb_sprintf(fb, "[get:%p,set:%p]",
- (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get,
- (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set);
- } else {
- tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v;
- duk__print_tval(st, tv);
- }
- if (st->heavy) {
- duk_fb_sprintf(fb, "<%02lx>", (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i));
- }
- }
- }
- if (st->internal) {
- if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_BOUND(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__bound:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__compiledfunction:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_NATIVEFUNCTION(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__nativefunction:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_THREAD(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_ARRAY_PART(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_STRICT(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_NEWENV(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_NAMEBINDING(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_CREATEARGS(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_dukfunc:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufferobj:true");
- } else {
- ;
- }
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true");
- } else {
- ;
- }
- }
- if (st->internal && DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
- DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
- duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(NULL, f));
- DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs);
- DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld", (long) f->start_line);
- DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line);
-#endif
- DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
- duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(NULL, f));
- } else if (st->internal && DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_hnativefunction *f = (duk_hnativefunction *) h;
- DUK__COMMA(); duk_fb_sprintf(fb, "__func:");
- duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func));
- DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
- DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic);
- } else if (st->internal && DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- duk_hbufferobject *b = (duk_hbufferobject *) h;
- DUK__COMMA(); duk_fb_sprintf(fb, "__buf:");
- duk__print_hbuffer(st, (duk_hbuffer *) b->buf);
- DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset);
- DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length);
- DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift);
- DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type);
- } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
- duk_hthread *t = (duk_hthread *) h;
- DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict);
- DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state);
- DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1);
- DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2);
- DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_max:%ld", (long) t->valstack_max);
- DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_max:%ld", (long) t->callstack_max);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_max:%ld", (long) t->catchstack_max);
- DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
- DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack));
- DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack));
- DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack));
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack:%p", (void *) t->catchstack);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_size:%ld", (long) t->catchstack_size);
- DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_top:%ld", (long) t->catchstack_top);
- DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
- /* XXX: print built-ins array? */
-
- }
-#ifdef DUK_USE_REFERENCE_COUNTING
- if (st->internal) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h));
- }
-#endif
- if (st->internal) {
- DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld", (long) DUK_HOBJECT_GET_CLASS_NUMBER(h));
- }
-
- DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p", (void *) h); /* own pointer */
-
- /* prototype should be last, for readability */
- if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) {
- if (st->follow_proto) {
- DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
- } else {
- DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p", (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
- }
- }
-
- duk_fb_put_cstring(fb, brace2);
-
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) {
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
- for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) {
- duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i);
- if (i > 0) {
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA);
- }
- if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) {
- duk_fb_sprintf(fb, "u");
- } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) {
- duk_fb_sprintf(fb, "d");
- } else {
- duk_fb_sprintf(fb, "%ld", (long) h_idx);
- }
- }
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
- }
-#endif
-
- finished:
- st->depth--;
- if (pushed_loopstack) {
- st->loop_stack_index--;
- st->loop_stack[st->loop_stack_index] = NULL;
- }
-}
-
-#undef DUK__COMMA
-
-DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
- duk_fixedbuffer *fb = st->fb;
- duk_size_t i, n;
- duk_uint8_t *p;
-
- if (duk_fb_is_full(fb)) {
- return;
- }
-
- /* terminal type: no depth check */
-
- if (!h) {
- duk_fb_put_cstring(fb, "NULL");
- return;
- }
-
- if (DUK_HBUFFER_HAS_DYNAMIC(h)) {
- if (DUK_HBUFFER_HAS_EXTERNAL(h)) {
- duk_hbuffer_external *g = (duk_hbuffer_external *) h;
- duk_fb_sprintf(fb, "buffer:external:%p:%ld",
- (void *) DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(NULL, g),
- (long) DUK_HBUFFER_EXTERNAL_GET_SIZE(g));
- } else {
- duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
- duk_fb_sprintf(fb, "buffer:dynamic:%p:%ld",
- (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(NULL, g),
- (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(g));
- }
- } else {
- duk_fb_sprintf(fb, "buffer:fixed:%ld", (long) DUK_HBUFFER_GET_SIZE(h));
- }
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
-#endif
-
- if (st->hexdump) {
- duk_fb_sprintf(fb, "=[");
- n = DUK_HBUFFER_GET_SIZE(h);
- p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(NULL, h);
- for (i = 0; i < n; i++) {
- duk_fb_sprintf(fb, "%02lx", (unsigned long) p[i]);
- }
- duk_fb_sprintf(fb, "]");
- }
-}
-
-DUK_LOCAL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
- duk_fixedbuffer *fb = st->fb;
-
- if (duk_fb_is_full(fb)) {
- return;
- }
-
- if (!h) {
- duk_fb_put_cstring(fb, "NULL");
- return;
- }
-
- switch (DUK_HEAPHDR_GET_TYPE(h)) {
- case DUK_HTYPE_STRING:
- duk__print_hstring(st, (duk_hstring *) h, 1);
- break;
- case DUK_HTYPE_OBJECT:
- duk__print_hobject(st, (duk_hobject *) h);
- break;
- case DUK_HTYPE_BUFFER:
- duk__print_hbuffer(st, (duk_hbuffer *) h);
- break;
- default:
- duk_fb_sprintf(fb, "[unknown htype %ld]", (long) DUK_HEAPHDR_GET_TYPE(h));
- break;
- }
-}
-
-DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
- duk_fixedbuffer *fb = st->fb;
-
- if (duk_fb_is_full(fb)) {
- return;
- }
-
- /* depth check is done when printing an actual type */
-
- if (st->heavy) {
- duk_fb_sprintf(fb, "(%p)", (void *) tv);
- }
-
- if (!tv) {
- duk_fb_put_cstring(fb, "NULL");
- return;
- }
-
- if (st->binary) {
- duk_size_t i;
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
- for (i = 0; i < (duk_size_t) sizeof(*tv); i++) {
- duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)tv)[i]);
- }
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
- }
-
- if (st->heavy) {
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
- }
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED: {
- duk_fb_put_cstring(fb, "undefined");
- break;
- }
- case DUK_TAG_UNUSED: {
- duk_fb_put_cstring(fb, "unused");
- break;
- }
- case DUK_TAG_NULL: {
- duk_fb_put_cstring(fb, "null");
- break;
- }
- case DUK_TAG_BOOLEAN: {
- duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false");
- break;
- }
- case DUK_TAG_STRING: {
- /* Note: string is a terminal heap object, so no depth check here */
- duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1);
- break;
- }
- case DUK_TAG_OBJECT: {
- duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv));
- break;
- }
- case DUK_TAG_BUFFER: {
- duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv));
- break;
- }
- case DUK_TAG_POINTER: {
- duk_fb_sprintf(fb, "pointer:%p", (void *) DUK_TVAL_GET_POINTER(tv));
- break;
- }
- case DUK_TAG_LIGHTFUNC: {
- duk_c_function func;
- duk_small_uint_t lf_flags;
-
- DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
- duk_fb_sprintf(fb, "lightfunc:");
- duk_fb_put_funcptr(fb, (duk_uint8_t *) &func, sizeof(func));
- duk_fb_sprintf(fb, ":%04lx", (long) lf_flags);
- break;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default: {
- /* IEEE double is approximately 16 decimal digits; print a couple extra */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- duk_fb_sprintf(fb, "%.18g", (double) DUK_TVAL_GET_NUMBER(tv));
- break;
- }
- }
- if (st->heavy) {
- duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
- }
-}
-
-DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) {
- duk_fixedbuffer *fb = st->fb;
- duk_small_int_t op;
- const char *op_name;
- const char *extraop_name;
-
- op = (duk_small_int_t) DUK_DEC_OP(ins);
- op_name = duk__bc_optab[op];
-
- /* XXX: option to fix opcode length so it lines up nicely */
-
- if (op == DUK_OP_EXTRA) {
- extraop_name = duk__bc_extraoptab[DUK_DEC_A(ins)];
-
- duk_fb_sprintf(fb, "%s %ld, %ld",
- (const char *) extraop_name, (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
- } else if (op == DUK_OP_JUMP) {
- duk_int_t diff1 = DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS; /* from next pc */
- duk_int_t diff2 = diff1 + 1; /* from curr pc */
-
- duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)",
- (const char *) op_name, (long) diff1,
- (int) (diff2 >= 0 ? '+' : '-'), /* char format: use int */
- (long) (diff2 >= 0 ? diff2 : -diff2));
- } else {
- duk_fb_sprintf(fb, "%s %ld, %ld, %ld",
- (const char *) op_name, (long) DUK_DEC_A(ins),
- (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
- }
-}
-
-DUK_LOCAL void duk__print_opcode(duk__dprint_state *st, duk_small_int_t opcode) {
- duk_fixedbuffer *fb = st->fb;
-
- if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) {
- duk_fb_sprintf(fb, "?(%ld)", (long) opcode);
- } else {
- duk_fb_sprintf(fb, "%s", (const char *) duk__bc_optab[opcode]);
- }
-}
-
-DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap) {
- duk_fixedbuffer fb;
- const char *p = format;
- const char *p_end = p + DUK_STRLEN(format);
- duk_int_t retval;
-
- DUK_MEMZERO(&fb, sizeof(fb));
- fb.buffer = (duk_uint8_t *) str;
- fb.length = size;
- fb.offset = 0;
- fb.truncated = 0;
-
- while (p < p_end) {
- char ch = *p++;
- const char *p_begfmt = NULL;
- duk_bool_t got_exclamation = 0;
- duk_bool_t got_long = 0; /* %lf, %ld etc */
- duk__dprint_state st;
-
- if (ch != DUK_ASC_PERCENT) {
- duk_fb_put_byte(&fb, (duk_uint8_t) ch);
- continue;
- }
-
- /*
- * Format tag parsing. Since we don't understand all the
- * possible format tags allowed, we just scan for a terminating
- * specifier and keep track of relevant modifiers that we do
- * understand. See man 3 printf.
- */
-
- DUK_MEMZERO(&st, sizeof(st));
- st.fb = &fb;
- st.depth = 0;
- st.depth_limit = 1;
- st.loop_stack_index = 0;
- st.loop_stack_limit = DUK__LOOP_STACK_DEPTH;
-
- p_begfmt = p - 1;
- while (p < p_end) {
- ch = *p++;
-
- if (ch == DUK_ASC_STAR) {
- /* unsupported: would consume multiple args */
- goto error;
- } else if (ch == DUK_ASC_PERCENT) {
- duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT);
- break;
- } else if (ch == DUK_ASC_EXCLAMATION) {
- got_exclamation = 1;
- } else if (!got_exclamation && ch == DUK_ASC_LC_L) {
- got_long = 1;
- } else if (got_exclamation && ch == DUK_ASC_LC_D) {
- st.depth_limit = DUK__DEEP_DEPTH_LIMIT;
- } else if (got_exclamation && ch == DUK_ASC_LC_P) {
- st.follow_proto = 1;
- } else if (got_exclamation && ch == DUK_ASC_LC_I) {
- st.internal = 1;
- } else if (got_exclamation && ch == DUK_ASC_LC_X) {
- st.hexdump = 1;
- } else if (got_exclamation && ch == DUK_ASC_LC_H) {
- st.heavy = 1;
- } else if (got_exclamation && ch == DUK_ASC_ATSIGN) {
- st.pointer = 1;
- } else if (got_exclamation && ch == DUK_ASC_HASH) {
- st.binary = 1;
- } else if (got_exclamation && ch == DUK_ASC_UC_T) {
- duk_tval *t = va_arg(ap, duk_tval *);
- if (st.pointer && !st.heavy) {
- duk_fb_sprintf(&fb, "(%p)", (void *) t);
- }
- duk__print_tval(&st, t);
- break;
- } else if (got_exclamation && ch == DUK_ASC_UC_O) {
- duk_heaphdr *t = va_arg(ap, duk_heaphdr *);
- if (st.pointer && !st.heavy) {
- duk_fb_sprintf(&fb, "(%p)", (void *) t);
- }
- duk__print_heaphdr(&st, t);
- break;
- } else if (got_exclamation && ch == DUK_ASC_UC_I) {
- duk_instr_t t = va_arg(ap, duk_instr_t);
- duk__print_instr(&st, t);
- break;
- } else if (got_exclamation && ch == DUK_ASC_UC_C) {
- long t = va_arg(ap, long);
- duk__print_opcode(&st, (duk_small_int_t) t);
- break;
- } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) {
- char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH];
- duk_size_t fmtlen;
-
- DUK_ASSERT(p >= p_begfmt);
- fmtlen = (duk_size_t) (p - p_begfmt);
- if (fmtlen >= sizeof(fmtbuf)) {
- /* format is too large, abort */
- goto error;
- }
- DUK_MEMZERO(fmtbuf, sizeof(fmtbuf));
- DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen);
-
- /* assume exactly 1 arg, which is why '*' is forbidden; arg size still
- * depends on type though.
- */
-
- if (ch == DUK_ASC_LC_F || ch == DUK_ASC_LC_G || ch == DUK_ASC_LC_E) {
- /* %f and %lf both consume a 'long' */
- double arg = va_arg(ap, double);
- duk_fb_sprintf(&fb, fmtbuf, arg);
- } else if (ch == DUK_ASC_LC_D && got_long) {
- /* %ld */
- long arg = va_arg(ap, long);
- duk_fb_sprintf(&fb, fmtbuf, arg);
- } else if (ch == DUK_ASC_LC_D) {
- /* %d; only 16 bits are guaranteed */
- int arg = va_arg(ap, int);
- duk_fb_sprintf(&fb, fmtbuf, arg);
- } else if (ch == DUK_ASC_LC_U && got_long) {
- /* %lu */
- unsigned long arg = va_arg(ap, unsigned long);
- duk_fb_sprintf(&fb, fmtbuf, arg);
- } else if (ch == DUK_ASC_LC_U) {
- /* %u; only 16 bits are guaranteed */
- unsigned int arg = va_arg(ap, unsigned int);
- duk_fb_sprintf(&fb, fmtbuf, arg);
- } else if (ch == DUK_ASC_LC_X && got_long) {
- /* %lx */
- unsigned long arg = va_arg(ap, unsigned long);
- duk_fb_sprintf(&fb, fmtbuf, arg);
- } else if (ch == DUK_ASC_LC_X) {
- /* %x; only 16 bits are guaranteed */
- unsigned int arg = va_arg(ap, unsigned int);
- duk_fb_sprintf(&fb, fmtbuf, arg);
- } else if (ch == DUK_ASC_LC_S) {
- /* %s */
- const char *arg = va_arg(ap, const char *);
- if (arg == NULL) {
- /* '%s' and NULL is not portable, so special case
- * it for debug printing.
- */
- duk_fb_sprintf(&fb, "NULL");
- } else {
- duk_fb_sprintf(&fb, fmtbuf, arg);
- }
- } else if (ch == DUK_ASC_LC_P) {
- /* %p */
- void *arg = va_arg(ap, void *);
- if (arg == NULL) {
- /* '%p' and NULL is portable, but special case it
- * anyway to get a standard NULL marker in logs.
- */
- duk_fb_sprintf(&fb, "NULL");
- } else {
- duk_fb_sprintf(&fb, fmtbuf, arg);
- }
- } else if (ch == DUK_ASC_LC_C) {
- /* '%c', passed concretely as int */
- int arg = va_arg(ap, int);
- duk_fb_sprintf(&fb, fmtbuf, arg);
- } else {
- /* Should not happen. */
- duk_fb_sprintf(&fb, "INVALID-FORMAT(%s)", (const char *) fmtbuf);
- }
- break;
- } else {
- /* ignore */
- }
- }
- }
- goto done;
-
- error:
- duk_fb_put_cstring(&fb, "FMTERR");
- /* fall through */
-
- done:
- retval = (duk_int_t) fb.offset;
- duk_fb_put_byte(&fb, (duk_uint8_t) 0);
-
- /* return total chars written excluding terminator */
- return retval;
-}
-
-#if 0 /*unused*/
-DUK_INTERNAL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...) {
- duk_int_t retval;
- va_list ap;
- va_start(ap, format);
- retval = duk_debug_vsnprintf(str, size, format, ap);
- va_end(ap);
- return retval;
-}
-#endif
-
-/* Formatting function pointers is tricky: there is no standard pointer for
- * function pointers and the size of a function pointer may depend on the
- * specific pointer type. This helper formats a function pointer based on
- * its memory layout to get something useful on most platforms.
- */
-DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size) {
- duk_size_t i;
- duk_uint8_t *p = (duk_uint8_t *) buf;
- duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1);
-
- DUK_MEMZERO(buf, buf_size);
-
- for (i = 0; i < fptr_size; i++) {
- duk_int_t left = (duk_int_t) (p_end - p);
- duk_uint8_t ch;
- if (left <= 0) {
- break;
- }
-
- /* Quite approximate but should be useful for little and big endian. */
-#ifdef DUK_USE_INTEGER_BE
- ch = fptr[i];
-#else
- ch = fptr[fptr_size - 1 - i];
-#endif
- p += DUK_SNPRINTF((char *) p, left, "%02lx", (unsigned long) ch);
- }
-}
-
-#endif /* DUK_USE_DEBUG */
-#line 1 "duk_debugger.c"
-/*
- * Duktape debugger
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-
-/*
- * Helper structs
- */
-
-typedef union {
- void *p;
- duk_uint_t b[1];
- /* Use b[] to access the size of the union, which is strictly not
- * correct. Can't use fixed size unless there's feature detection
- * for pointer byte size.
- */
-} duk__ptr_union;
-
-/*
- * Detach handling
- */
-
-#define DUK__SET_CONN_BROKEN(thr,reason) do { \
- /* For now shared handler is fine. */ \
- duk__debug_do_detach1((thr)->heap, (reason)); \
- } while (0)
-
-DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
- /* Can be called multiple times with no harm. Mark the transport
- * bad (dbg_read_cb == NULL) and clear state except for the detached
- * callback and the udata field. The detached callback is delayed
- * to the message loop so that it can be called between messages;
- * this avoids corner cases related to immediate debugger reattach
- * inside the detached callback.
- */
-
- if (heap->dbg_detaching) {
- DUK_D(DUK_DPRINT("debugger already detaching, ignore detach1"));
- return;
- }
-
- DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken"));
-
- heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */
-
- if (heap->dbg_write_cb != NULL) {
- duk_hthread *thr;
-
- thr = heap->heap_thread;
- DUK_ASSERT(thr != NULL);
-
- duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING);
- duk_debug_write_int(thr, reason);
- duk_debug_write_eom(thr);
- }
-
- heap->dbg_read_cb = NULL;
- heap->dbg_write_cb = NULL;
- heap->dbg_peek_cb = NULL;
- heap->dbg_read_flush_cb = NULL;
- heap->dbg_write_flush_cb = NULL;
- heap->dbg_request_cb = NULL;
- /* heap->dbg_detached_cb: keep */
- /* heap->dbg_udata: keep */
- /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */
- heap->dbg_paused = 0;
- heap->dbg_state_dirty = 0;
- heap->dbg_force_restart = 0;
- heap->dbg_step_type = 0;
- heap->dbg_step_thread = NULL;
- heap->dbg_step_csindex = 0;
- heap->dbg_step_startline = 0;
- heap->dbg_have_next_byte = 0;
-
- /* Ensure there are no stale active breakpoint pointers.
- * Breakpoint list is currently kept - we could empty it
- * here but we'd need to handle refcounts correctly, and
- * we'd need a 'thr' reference for that.
- *
- * XXX: clear breakpoint on either attach or detach?
- */
- heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
-}
-
-DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
- duk_debug_detached_function detached_cb;
- void *detached_udata;
-
- /* Safe to call multiple times. */
-
- detached_cb = heap->dbg_detached_cb;
- detached_udata = heap->dbg_udata;
- heap->dbg_detached_cb = NULL;
- heap->dbg_udata = NULL;
-
- if (detached_cb) {
- /* Careful here: state must be wiped before the call
- * so that we can cleanly handle a re-attach from
- * inside the callback.
- */
- DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
- detached_cb(detached_udata);
- }
-
- heap->dbg_detaching = 0;
-}
-
-DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
- duk__debug_do_detach1(heap, 0);
- duk__debug_do_detach2(heap);
-}
-
-/* Called on a read/write error: NULL all callbacks except the detached
- * callback so that we never accidentally call them after a read/write
- * error has been indicated. This is especially important for the transport
- * I/O callbacks to fulfill guaranteed callback semantics.
- */
-DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
- duk_heap *heap;
- heap = thr->heap;
- DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached"));
- heap->dbg_read_cb = NULL;
- heap->dbg_write_cb = NULL; /* this is especially critical to avoid another write call in detach1() */
- heap->dbg_peek_cb = NULL;
- heap->dbg_read_flush_cb = NULL;
- heap->dbg_write_flush_cb = NULL;
- heap->dbg_request_cb = NULL;
- /* keep heap->dbg_detached_cb */
-}
-
-/*
- * Debug connection peek and flush primitives
- */
-
-DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
- duk_heap *heap;
-
- DUK_ASSERT(thr != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- if (heap->dbg_read_cb == NULL) {
- DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)"));
- return 0;
- }
- if (heap->dbg_peek_cb == NULL) {
- DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)"));
- return 0;
- }
-
- return (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
-}
-
-DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
- duk_heap *heap;
-
- DUK_ASSERT(thr != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- if (heap->dbg_read_cb == NULL) {
- DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore"));
- return;
- }
- if (heap->dbg_read_flush_cb == NULL) {
- DUK_DD(DUK_DDPRINT("no read flush callback, ignore"));
- return;
- }
-
- heap->dbg_read_flush_cb(heap->dbg_udata);
-}
-
-DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
- duk_heap *heap;
-
- DUK_ASSERT(thr != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- if (heap->dbg_read_cb == NULL) {
- DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore"));
- return;
- }
- if (heap->dbg_write_flush_cb == NULL) {
- DUK_DD(DUK_DDPRINT("no write flush callback, ignore"));
- return;
- }
-
- heap->dbg_write_flush_cb(heap->dbg_udata);
-}
-
-/*
- * Debug connection skip primitives
- */
-
-/* Skip fully. */
-DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) {
- duk_uint8_t dummy[64];
- duk_size_t now;
-
- DUK_ASSERT(thr != NULL);
-
- while (length > 0) {
- now = (length > sizeof(dummy) ? sizeof(dummy) : length);
- duk_debug_read_bytes(thr, dummy, now);
- length -= now;
- }
-}
-
-DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) {
- DUK_ASSERT(thr != NULL);
-
- (void) duk_debug_read_byte(thr);
-}
-
-/*
- * Debug connection read primitives
- */
-
-/* Peek ahead in the stream one byte. */
-DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) {
- /* It is important not to call this if the last byte read was an EOM.
- * Reading ahead in this scenario would cause unnecessary blocking if
- * another message is not available.
- */
-
- duk_uint8_t x;
-
- x = duk_debug_read_byte(thr);
- thr->heap->dbg_have_next_byte = 1;
- thr->heap->dbg_next_byte = x;
- return x;
-}
-
-/* Read fully. */
-DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) {
- duk_heap *heap;
- duk_uint8_t *p;
- duk_size_t left;
- duk_size_t got;
-
- DUK_ASSERT(thr != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- if (heap->dbg_read_cb == NULL) {
- DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));
- goto fail;
- }
-
- /* NOTE: length may be zero */
- p = data;
- if (length >= 1 && heap->dbg_have_next_byte) {
- heap->dbg_have_next_byte = 0;
- *p++ = heap->dbg_next_byte;
- }
- for (;;) {
- left = (duk_size_t) ((data + length) - p);
- if (left == 0) {
- break;
- }
- DUK_ASSERT(heap->dbg_read_cb != NULL);
- DUK_ASSERT(left >= 1);
-#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
- left = 1;
-#endif
- got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
- if (got == 0 || got > left) {
- DUK_D(DUK_DPRINT("connection error during read, return zero data"));
- duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
- DUK__SET_CONN_BROKEN(thr, 1);
- goto fail;
- }
- p += got;
- }
- return;
-
- fail:
- DUK_MEMZERO((void *) data, (size_t) length);
-}
-
-DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
- duk_uint8_t x;
-
- x = 0; /* just in case callback is broken and won't write 'x' */
- duk_debug_read_bytes(thr, &x, 1);
- return x;
-}
-
-DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
- duk_uint8_t buf[4];
-
- DUK_ASSERT(thr != NULL);
-
- duk_debug_read_bytes(thr, buf, 4);
- return ((duk_uint32_t) buf[0] << 24) |
- ((duk_uint32_t) buf[1] << 16) |
- ((duk_uint32_t) buf[2] << 8) |
- (duk_uint32_t) buf[3];
-}
-
-DUK_LOCAL duk_uint32_t duk__debug_read_int32_raw(duk_hthread *thr) {
- return (duk_int32_t) duk__debug_read_uint32_raw(thr);
-}
-
-DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) {
- duk_uint8_t buf[2];
-
- DUK_ASSERT(thr != NULL);
-
- duk_debug_read_bytes(thr, buf, 2);
- return ((duk_uint16_t) buf[0] << 8) |
- (duk_uint16_t) buf[1];
-}
-
-DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
- duk_small_uint_t x;
- duk_small_uint_t t;
-
- DUK_ASSERT(thr != NULL);
-
- x = duk_debug_read_byte(thr);
- if (x >= 0xc0) {
- t = duk_debug_read_byte(thr);
- return (duk_int32_t) (((x - 0xc0) << 8) + t);
- } else if (x >= 0x80) {
- return (duk_int32_t) (x - 0x80);
- } else if (x == DUK_DBG_IB_INT4) {
- return (duk_int32_t) duk__debug_read_uint32_raw(thr);
- }
-
- DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
- DUK__SET_CONN_BROKEN(thr, 1);
- return 0;
-}
-
-DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
- duk_context *ctx = (duk_context *) thr;
- duk_uint8_t buf[31];
- duk_uint8_t *p;
-
- if (len <= sizeof(buf)) {
- duk_debug_read_bytes(thr, buf, (duk_size_t) len);
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
- } else {
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- DUK_ASSERT(p != NULL);
- duk_debug_read_bytes(thr, p, (duk_size_t) len);
- duk_to_string(ctx, -1);
- }
-
- return duk_require_hstring(ctx, -1);
-}
-
-DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_t x;
- duk_uint32_t len;
-
- DUK_ASSERT(thr != NULL);
-
- x = duk_debug_read_byte(thr);
- if (x >= 0x60 && x <= 0x7f) {
- /* For short strings, use a fixed temp buffer. */
- len = (duk_uint32_t) (x - 0x60);
- } else if (x == DUK_DBG_IB_STR2) {
- len = (duk_uint32_t) duk__debug_read_uint16_raw(thr);
- } else if (x == DUK_DBG_IB_STR4) {
- len = (duk_uint32_t) duk__debug_read_uint32_raw(thr);
- } else {
- goto fail;
- }
-
- return duk__debug_read_hstring_raw(thr, len);
-
- fail:
- DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
- DUK__SET_CONN_BROKEN(thr, 1);
- duk_push_hstring_stridx(thr, DUK_STRIDX_EMPTY_STRING); /* always push some string */
- return duk_require_hstring(ctx, -1);
-}
-
-DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
- duk_context *ctx = (duk_context *) thr;
- duk_uint8_t *p;
-
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len);
- DUK_ASSERT(p != NULL);
- duk_debug_read_bytes(thr, p, (duk_size_t) len);
-
- return duk_require_hbuffer(ctx, -1);
-}
-
-DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
- duk_small_uint_t x;
- duk__ptr_union pu;
-
- DUK_ASSERT(thr != NULL);
-
- x = duk_debug_read_byte(thr);
- if (x != sizeof(pu)) {
- goto fail;
- }
- duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu));
-#if defined(DUK_USE_INTEGER_LE)
- duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
-#endif
- return (void *) pu.p;
-
- fail:
- DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer"));
- DUK__SET_CONN_BROKEN(thr, 1);
- return (void *) NULL;
-}
-
-DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) {
- duk_double_union du;
-
- DUK_ASSERT(sizeof(du.uc) == 8);
- duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc));
- DUK_DBLUNION_DOUBLE_NTOH(&du);
- return du.d;
-}
-
-#if 0
-DUK_INTERNAL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr) {
- duk_small_uint_t x;
-
- DUK_ASSERT(thr != NULL);
-
- x = duk_debug_read_byte(thr);
- if (x != DUK_DBG_IB_HEAPPTR) {
- goto fail;
- }
-
- return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
-
- fail:
- DUK_D(DUK_DPRINT("debug connection error: failed to decode heapptr"));
- DUK__SET_CONN_BROKEN(thr, 1);
- return NULL;
-}
-#endif
-
-DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) {
- duk_small_uint_t x;
-
- DUK_ASSERT(thr != NULL);
-
- x = duk_debug_read_byte(thr);
- switch (x) {
- case DUK_DBG_IB_OBJECT:
- case DUK_DBG_IB_POINTER:
- case DUK_DBG_IB_HEAPPTR:
- /* Accept any pointer-like value; for 'object' dvalue, read
- * and ignore the class number.
- */
- if (x == DUK_DBG_IB_OBJECT) {
- duk_debug_skip_byte(thr);
- }
- break;
- default:
- goto fail;
- }
-
- return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
-
- fail:
- DUK_D(DUK_DPRINT("debug connection error: failed to decode any pointer (object, pointer, heapptr)"));
- DUK__SET_CONN_BROKEN(thr, 1);
- return NULL;
-}
-
-DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_uint8_t x;
- duk_uint_t t;
- duk_uint32_t len;
-
- DUK_ASSERT(thr != NULL);
-
- x = duk_debug_read_byte(thr);
-
- if (x >= 0xc0) {
- t = (duk_uint_t) (x - 0xc0);
- t = (t << 8) + duk_debug_read_byte(thr);
- duk_push_uint(ctx, (duk_uint_t) t);
- goto return_ptr;
- }
- if (x >= 0x80) {
- duk_push_uint(ctx, (duk_uint_t) (x - 0x80));
- goto return_ptr;
- }
- if (x >= 0x60) {
- len = (duk_uint32_t) (x - 0x60);
- duk__debug_read_hstring_raw(thr, len);
- goto return_ptr;
- }
-
- switch (x) {
- case DUK_DBG_IB_INT4: {
- duk_int32_t i = duk__debug_read_int32_raw(thr);
- duk_push_i32(ctx, i);
- break;
- }
- case DUK_DBG_IB_STR4: {
- len = duk__debug_read_uint32_raw(thr);
- duk__debug_read_hstring_raw(thr, len);
- break;
- }
- case DUK_DBG_IB_STR2: {
- len = duk__debug_read_uint16_raw(thr);
- duk__debug_read_hstring_raw(thr, len);
- break;
- }
- case DUK_DBG_IB_BUF4: {
- len = duk__debug_read_uint32_raw(thr);
- duk__debug_read_hbuffer_raw(thr, len);
- break;
- }
- case DUK_DBG_IB_BUF2: {
- len = duk__debug_read_uint16_raw(thr);
- duk__debug_read_hbuffer_raw(thr, len);
- break;
- }
- case DUK_DBG_IB_UNDEFINED: {
- duk_push_undefined(ctx);
- break;
- }
- case DUK_DBG_IB_NULL: {
- duk_push_null(ctx);
- break;
- }
- case DUK_DBG_IB_TRUE: {
- duk_push_true(ctx);
- break;
- }
- case DUK_DBG_IB_FALSE: {
- duk_push_false(ctx);
- break;
- }
- case DUK_DBG_IB_NUMBER: {
- duk_double_t d;
- d = duk__debug_read_double_raw(thr);
- duk_push_number(ctx, d);
- break;
- }
- case DUK_DBG_IB_OBJECT: {
- duk_heaphdr *h;
- duk_debug_skip_byte(thr);
- h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
- duk_push_heapptr(thr, (void *) h);
- break;
- }
- case DUK_DBG_IB_POINTER: {
- void *ptr;
- ptr = duk__debug_read_pointer_raw(thr);
- duk_push_pointer(thr, ptr);
- break;
- }
- case DUK_DBG_IB_LIGHTFUNC: {
- /* XXX: Not needed for now, so not implemented. Note that
- * function pointers may have different size/layout than
- * a void pointer.
- */
- DUK_D(DUK_DPRINT("reading lightfunc values unimplemented"));
- goto fail;
- }
- case DUK_DBG_IB_HEAPPTR: {
- duk_heaphdr *h;
- h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
- duk_push_heapptr(thr, (void *) h);
- break;
- }
- case DUK_DBG_IB_UNUSED: /* unused: not accepted in inbound messages */
- default:
- goto fail;
- }
-
- return_ptr:
- return DUK_GET_TVAL_NEGIDX(thr, -1);
-
- fail:
- DUK_D(DUK_DPRINT("debug connection error: failed to decode tval"));
- DUK__SET_CONN_BROKEN(thr, 1);
- return NULL;
-}
-
-/*
- * Debug connection write primitives
- */
-
-/* Write fully. */
-DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) {
- duk_heap *heap;
- const duk_uint8_t *p;
- duk_size_t left;
- duk_size_t got;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(length == 0 || data != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- if (heap->dbg_write_cb == NULL) {
- DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore", (long) length));
- return;
- }
- if (length == 0) {
- /* Avoid doing an actual write callback with length == 0,
- * because that's reserved for a write flush.
- */
- return;
- }
- DUK_ASSERT(data != NULL);
-
- p = data;
- for (;;) {
- left = (duk_size_t) ((data + length) - p);
- if (left == 0) {
- break;
- }
- DUK_ASSERT(heap->dbg_write_cb != NULL);
- DUK_ASSERT(left >= 1);
-#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
- left = 1;
-#endif
- got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
- if (got == 0 || got > left) {
- duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
- DUK_D(DUK_DPRINT("connection error during write"));
- DUK__SET_CONN_BROKEN(thr, 1);
- return;
- }
- p += got;
- }
-}
-
-DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
- duk_debug_write_bytes(thr, (const duk_uint8_t *) &x, 1);
-}
-
-DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
- duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
-}
-
-DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) {
- duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
-}
-
-#if defined(DUK_USE_DEBUGGER_INSPECT)
-DUK_INTERNAL void duk_debug_write_null(duk_hthread *thr) {
- duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
-}
-#endif
-
-DUK_INTERNAL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val) {
- duk_debug_write_byte(thr, val ? DUK_DBG_IB_TRUE : DUK_DBG_IB_FALSE);
-}
-
-/* Write signed 32-bit integer. */
-DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) {
- duk_uint8_t buf[5];
- duk_size_t len;
-
- DUK_ASSERT(thr != NULL);
-
- if (x >= 0 && x <= 0x3fL) {
- buf[0] = (duk_uint8_t) (0x80 + x);
- len = 1;
- } else if (x >= 0 && x <= 0x3fffL) {
- buf[0] = (duk_uint8_t) (0xc0 + (x >> 8));
- buf[1] = (duk_uint8_t) (x & 0xff);
- len = 2;
- } else {
- /* Signed integers always map to 4 bytes now. */
- buf[0] = (duk_uint8_t) DUK_DBG_IB_INT4;
- buf[1] = (duk_uint8_t) ((x >> 24) & 0xff);
- buf[2] = (duk_uint8_t) ((x >> 16) & 0xff);
- buf[3] = (duk_uint8_t) ((x >> 8) & 0xff);
- buf[4] = (duk_uint8_t) (x & 0xff);
- len = 5;
- }
- duk_debug_write_bytes(thr, buf, len);
-}
-
-/* Write unsigned 32-bit integer. */
-DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) {
- /* The debugger protocol doesn't support a plain integer encoding for
- * the full 32-bit unsigned range (only 32-bit signed). For now,
- * unsigned 32-bit values simply written as signed ones. This is not
- * a concrete issue except for 32-bit heaphdr fields. Proper solutions
- * would be to (a) write such integers as IEEE doubles or (b) add an
- * unsigned 32-bit dvalue.
- */
- if (x >= 0x80000000UL) {
- DUK_D(DUK_DPRINT("writing unsigned integer 0x%08lx as signed integer",
- (long) x));
- }
- duk_debug_write_int(thr, (duk_int32_t) x);
-}
-
-DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) {
- duk_uint8_t buf[5];
- duk_size_t buflen;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(length == 0 || data != NULL);
-
- if (length <= 0x1fUL && marker_base == DUK_DBG_IB_STR4) {
- /* For strings, special form for short lengths. */
- buf[0] = (duk_uint8_t) (0x60 + length);
- buflen = 1;
- } else if (length <= 0xffffUL) {
- buf[0] = (duk_uint8_t) (marker_base + 1);
- buf[1] = (duk_uint8_t) (length >> 8);
- buf[2] = (duk_uint8_t) (length & 0xff);
- buflen = 3;
- } else {
- buf[0] = (duk_uint8_t) marker_base;
- buf[1] = (duk_uint8_t) (length >> 24);
- buf[2] = (duk_uint8_t) ((length >> 16) & 0xff);
- buf[3] = (duk_uint8_t) ((length >> 8) & 0xff);
- buf[4] = (duk_uint8_t) (length & 0xff);
- buflen = 5;
- }
-
- duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen);
- duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length);
-}
-
-DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) {
- duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_STR4);
-}
-
-DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) {
- DUK_ASSERT(thr != NULL);
-
- duk_debug_write_string(thr,
- data,
- data ? DUK_STRLEN(data) : 0);
-}
-
-DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
- DUK_ASSERT(thr != NULL);
-
- /* XXX: differentiate null pointer from empty string? */
- duk_debug_write_string(thr,
- (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL),
- (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0));
-}
-
-DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_debug_write_hstring(thr, duk_safe_to_hstring(ctx, -1));
-}
-
-DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
- duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_BUF4);
-}
-
-DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
- DUK_ASSERT(thr != NULL);
-
- duk_debug_write_buffer(thr,
- (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL),
- (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0));
-}
-
-DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) {
- duk_uint8_t buf[2];
- duk__ptr_union pu;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16);
- /* ptr may be NULL */
-
- buf[0] = ibyte;
- buf[1] = sizeof(pu);
- duk_debug_write_bytes(thr, buf, 2);
- pu.p = (void *) ptr;
-#if defined(DUK_USE_INTEGER_LE)
- duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
-#endif
- duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
-}
-
-DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) {
- duk__debug_write_pointer_raw(thr, ptr, DUK_DBG_IB_POINTER);
-}
-
-#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
-DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) {
- duk__debug_write_pointer_raw(thr, (void *) h, DUK_DBG_IB_HEAPPTR);
-}
-#endif /* DUK_USE_DEBUGGER_DUMPHEAP || DUK_USE_DEBUGGER_INSPECT */
-
-DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
- duk_uint8_t buf[3];
- duk__ptr_union pu;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16);
- DUK_ASSERT(obj != NULL);
-
- buf[0] = DUK_DBG_IB_OBJECT;
- buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj);
- buf[2] = sizeof(pu);
- duk_debug_write_bytes(thr, buf, 3);
- pu.p = (void *) obj;
-#if defined(DUK_USE_INTEGER_LE)
- duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
-#endif
- duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
-}
-
-DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
- duk_c_function lf_func;
- duk_small_uint_t lf_flags;
- duk_uint8_t buf[4];
- duk_double_union du1;
- duk_double_union du2;
- duk_int32_t i32;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(tv != NULL);
-
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED:
- duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
- break;
- case DUK_TAG_UNUSED:
- duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
- break;
- case DUK_TAG_NULL:
- duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
- break;
- case DUK_TAG_BOOLEAN:
- DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 ||
- DUK_TVAL_GET_BOOLEAN(tv) == 1);
- duk_debug_write_boolean(thr, DUK_TVAL_GET_BOOLEAN(tv));
- break;
- case DUK_TAG_POINTER:
- duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv));
- break;
- case DUK_TAG_LIGHTFUNC:
- DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags);
- buf[0] = DUK_DBG_IB_LIGHTFUNC;
- buf[1] = (duk_uint8_t) (lf_flags >> 8);
- buf[2] = (duk_uint8_t) (lf_flags & 0xff);
- buf[3] = sizeof(lf_func);
- duk_debug_write_bytes(thr, buf, 4);
- duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func));
- break;
- case DUK_TAG_STRING:
- duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv));
- break;
- case DUK_TAG_OBJECT:
- duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv));
- break;
- case DUK_TAG_BUFFER:
- duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv));
- break;
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default:
- /* Numbers are normalized to big (network) endian. We can
- * (but are not required) to use integer dvalues when there's
- * no loss of precision.
- *
- * XXX: share check with other code; this check is slow but
- * reliable and doesn't require careful exponent/mantissa
- * mask tricks as in the fastint downgrade code.
- */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- du1.d = DUK_TVAL_GET_NUMBER(tv);
- i32 = (duk_int32_t) du1.d;
- du2.d = (duk_double_t) i32;
-
- DUK_DD(DUK_DDPRINT("i32=%ld du1=%02x%02x%02x%02x%02x%02x%02x%02x "
- "du2=%02x%02x%02x%02x%02x%02x%02x%02x",
- (long) i32,
- (unsigned int) du1.uc[0], (unsigned int) du1.uc[1],
- (unsigned int) du1.uc[2], (unsigned int) du1.uc[3],
- (unsigned int) du1.uc[4], (unsigned int) du1.uc[5],
- (unsigned int) du1.uc[6], (unsigned int) du1.uc[7],
- (unsigned int) du2.uc[0], (unsigned int) du2.uc[1],
- (unsigned int) du2.uc[2], (unsigned int) du2.uc[3],
- (unsigned int) du2.uc[4], (unsigned int) du2.uc[5],
- (unsigned int) du2.uc[6], (unsigned int) du2.uc[7]));
-
- if (DUK_MEMCMP((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) {
- duk_debug_write_int(thr, i32);
- } else {
- DUK_DBLUNION_DOUBLE_HTON(&du1);
- duk_debug_write_byte(thr, DUK_DBG_IB_NUMBER);
- duk_debug_write_bytes(thr, (const duk_uint8_t *) du1.uc, sizeof(du1.uc));
- }
- }
-}
-
-#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
-/* Variant for writing duk_tvals so that any heap allocated values are
- * written out as tagged heap pointers.
- */
-DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) {
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- duk_debug_write_heapptr(thr, h);
- } else {
- duk_debug_write_tval(thr, tv);
- }
-}
-#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
-
-/*
- * Debug connection message write helpers
- */
-
-#if 0 /* unused */
-DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) {
- duk_debug_write_byte(thr, DUK_DBG_IB_REQUEST);
- duk_debug_write_int(thr, command);
-}
-#endif
-
-DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) {
- duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
-}
-
-DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) {
- /* Allow NULL 'msg' */
- duk_debug_write_byte(thr, DUK_DBG_IB_ERROR);
- duk_debug_write_int(thr, (duk_int32_t) err_code);
- duk_debug_write_cstring(thr, msg);
- duk_debug_write_eom(thr);
-}
-
-DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
- duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY);
- duk_debug_write_int(thr, command);
-}
-
-DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
- duk_debug_write_byte(thr, DUK_DBG_IB_EOM);
-
- /* As an initial implementation, write flush after every EOM (and the
- * version identifier). A better implementation would flush only when
- * Duktape is finished processing messages so that a flush only happens
- * after all outbound messages are finished on that occasion.
- */
- duk_debug_write_flush(thr);
-}
-
-/*
- * Status message and helpers
- */
-
-DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_uint_fast32_t line;
- duk_uint_fast32_t pc;
-
- act = duk_hthread_get_current_activation(thr); /* may be NULL */
- if (act == NULL) {
- return 0;
- }
-
- /* We're conceptually between two opcodes; act->pc indicates the next
- * instruction to be executed. This is usually the correct pc/line to
- * indicate in Status. (For the 'debugger' statement this now reports
- * the pc/line after the debugger statement because the debugger opcode
- * has already been executed.)
- */
-
- pc = duk_hthread_get_act_curr_pc(thr, act);
-
- /* XXX: this should be optimized to be a raw query and avoid valstack
- * operations if possible.
- */
- duk_push_tval(ctx, &act->tv_func);
- line = duk_hobject_pc2line_query(ctx, -1, pc);
- duk_pop(ctx);
- return line;
-}
-
-DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
-
- duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
- duk_debug_write_int(thr, thr->heap->dbg_paused);
-
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */
- if (thr->callstack_top == 0) {
- duk_debug_write_undefined(thr);
- duk_debug_write_undefined(thr);
- duk_debug_write_int(thr, 0);
- duk_debug_write_int(thr, 0);
- } else {
- act = thr->callstack + thr->callstack_top - 1;
- duk_push_tval(ctx, &act->tv_func);
- duk_get_prop_string(ctx, -1, "fileName");
- duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_string(ctx, -2, "name");
- duk__debug_write_hstring_safe_top(thr);
- duk_pop_3(ctx);
- /* Report next pc/line to be executed. */
- duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
- duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
- }
-
- duk_debug_write_eom(thr);
-}
-
-#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
-DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
- /*
- * NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM
- */
-
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_uint32_t pc;
-
- DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */
-
- duk_debug_write_notify(thr, DUK_DBG_CMD_THROW);
- duk_debug_write_int(thr, fatal);
-
- /* Report thrown value to client coerced to string */
- duk_dup(ctx, -1);
- duk__debug_write_hstring_safe_top(thr);
- duk_pop(ctx);
-
- if (duk_is_error(ctx, -1)) {
- /* Error instance, use augmented error data directly */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
- duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER);
- duk_debug_write_uint(thr, duk_get_uint(ctx, -1));
- } else {
- /* For anything other than an Error instance, we calculate the error
- * location directly from the current activation.
- */
- act = thr->callstack + thr->callstack_top - 1;
- duk_push_tval(ctx, &act->tv_func);
- duk_get_prop_string(ctx, -1, "fileName");
- duk__debug_write_hstring_safe_top(thr);
- pc = duk_hthread_get_act_prev_pc(thr, act);
- duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc));
- }
- duk_pop_2(ctx); /* shared pop */
-
- duk_debug_write_eom(thr);
-}
-#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY */
-
-/*
- * Debug message processing
- */
-
-/* Skip dvalue. */
-DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
- duk_uint8_t x;
- duk_uint32_t len;
-
- x = duk_debug_read_byte(thr);
-
- if (x >= 0xc0) {
- duk_debug_skip_byte(thr);
- return 0;
- }
- if (x >= 0x80) {
- return 0;
- }
- if (x >= 0x60) {
- duk_debug_skip_bytes(thr, x - 0x60);
- return 0;
- }
- switch(x) {
- case DUK_DBG_IB_EOM:
- return 1; /* Return 1: got EOM */
- case DUK_DBG_IB_REQUEST:
- case DUK_DBG_IB_REPLY:
- case DUK_DBG_IB_ERROR:
- case DUK_DBG_IB_NOTIFY:
- break;
- case DUK_DBG_IB_INT4:
- (void) duk__debug_read_uint32_raw(thr);
- break;
- case DUK_DBG_IB_STR4:
- case DUK_DBG_IB_BUF4:
- len = duk__debug_read_uint32_raw(thr);
- duk_debug_skip_bytes(thr, len);
- break;
- case DUK_DBG_IB_STR2:
- case DUK_DBG_IB_BUF2:
- len = duk__debug_read_uint16_raw(thr);
- duk_debug_skip_bytes(thr, len);
- break;
- case DUK_DBG_IB_UNUSED:
- case DUK_DBG_IB_UNDEFINED:
- case DUK_DBG_IB_NULL:
- case DUK_DBG_IB_TRUE:
- case DUK_DBG_IB_FALSE:
- break;
- case DUK_DBG_IB_NUMBER:
- duk_debug_skip_bytes(thr, 8);
- break;
- case DUK_DBG_IB_OBJECT:
- duk_debug_skip_byte(thr);
- len = duk_debug_read_byte(thr);
- duk_debug_skip_bytes(thr, len);
- break;
- case DUK_DBG_IB_POINTER:
- case DUK_DBG_IB_HEAPPTR:
- len = duk_debug_read_byte(thr);
- duk_debug_skip_bytes(thr, len);
- break;
- case DUK_DBG_IB_LIGHTFUNC:
- duk_debug_skip_bytes(thr, 2);
- len = duk_debug_read_byte(thr);
- duk_debug_skip_bytes(thr, len);
- break;
- default:
- goto fail;
- }
-
- return 0;
-
- fail:
- DUK__SET_CONN_BROKEN(thr, 1);
- return 1; /* Pretend like we got EOM */
-}
-
-/* Skip dvalues to EOM. */
-DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
- for (;;) {
- if (duk__debug_skip_dvalue(thr)) {
- break;
- }
- }
-}
-
-/*
- * Simple commands
- */
-
-DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) {
- DUK_UNREF(heap);
- DUK_D(DUK_DPRINT("debug command Version"));
-
- duk_debug_write_reply(thr);
- duk_debug_write_int(thr, DUK_VERSION);
- duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE);
- duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO);
-#if defined(DUK_USE_DOUBLE_LE)
- duk_debug_write_int(thr, 1);
-#elif defined(DUK_USE_DOUBLE_ME)
- duk_debug_write_int(thr, 2);
-#elif defined(DUK_USE_DOUBLE_BE)
- duk_debug_write_int(thr, 3);
-#else
- duk_debug_write_int(thr, 0);
-#endif
- duk_debug_write_int(thr, (duk_int_t) sizeof(void *));
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) {
- DUK_UNREF(heap);
- DUK_D(DUK_DPRINT("debug command TriggerStatus"));
-
- duk_debug_write_reply(thr);
- duk_debug_write_eom(thr);
- heap->dbg_state_dirty = 1;
-}
-
-DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
- DUK_D(DUK_DPRINT("debug command Pause"));
-
- DUK_HEAP_SET_PAUSED(heap);
- duk_debug_write_reply(thr);
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
- DUK_D(DUK_DPRINT("debug command Resume"));
-
- DUK_HEAP_CLEAR_PAUSED(heap);
- duk_debug_write_reply(thr);
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
- duk_small_uint_t step_type;
- duk_uint_fast32_t line;
-
- DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd));
-
- if (cmd == DUK_DBG_CMD_STEPINTO) {
- step_type = DUK_STEP_TYPE_INTO;
- } else if (cmd == DUK_DBG_CMD_STEPOVER) {
- step_type = DUK_STEP_TYPE_OVER;
- } else {
- DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
- step_type = DUK_STEP_TYPE_OUT;
- }
-
- line = duk_debug_curr_line(thr);
- if (line > 0) {
- heap->dbg_paused = 0;
- heap->dbg_step_type = step_type;
- heap->dbg_step_thread = thr;
- heap->dbg_step_csindex = thr->callstack_top - 1;
- heap->dbg_step_startline = line;
- heap->dbg_state_dirty = 1;
- } else {
- DUK_D(DUK_DPRINT("cannot determine current line, stepinto/stepover/stepout ignored"));
- }
- duk_debug_write_reply(thr);
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) {
- duk_small_int_t i;
-
- DUK_D(DUK_DPRINT("debug command ListBreak"));
- duk_debug_write_reply(thr);
- for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) {
- duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename);
- duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line);
- }
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
- duk_hstring *filename;
- duk_uint32_t linenumber;
- duk_small_int_t idx;
-
- DUK_UNREF(heap);
-
- filename = duk_debug_read_hstring(thr);
- linenumber = (duk_uint32_t) duk_debug_read_int(thr);
- DUK_D(DUK_DPRINT("debug command AddBreak: %!O:%ld", (duk_hobject *) filename, (long) linenumber));
- idx = duk_debug_add_breakpoint(thr, filename, linenumber);
- if (idx >= 0) {
- duk_debug_write_reply(thr);
- duk_debug_write_int(thr, (duk_int32_t) idx);
- duk_debug_write_eom(thr);
- } else {
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint");
- }
-}
-
-DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
- duk_small_uint_t idx;
-
- DUK_UNREF(heap);
-
- DUK_D(DUK_DPRINT("debug command DelBreak"));
- idx = (duk_small_uint_t) duk_debug_read_int(thr);
- if (duk_debug_remove_breakpoint(thr, idx)) {
- duk_debug_write_reply(thr);
- duk_debug_write_eom(thr);
- } else {
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index");
- }
-}
-
-DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
- duk_hstring *str;
- duk_bool_t rc;
- duk_int32_t level;
-
- DUK_UNREF(heap);
- DUK_D(DUK_DPRINT("debug command GetVar"));
-
- str = duk_debug_read_hstring(thr); /* push to stack */
- DUK_ASSERT(str != NULL);
- if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- level = duk_debug_read_int(thr); /* optional callstack level */
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for GetVar"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
- return;
- }
- } else {
- level = -1;
- }
-
- if (thr->callstack_top > 0) {
- rc = duk_js_getvar_activation(thr,
- thr->callstack + thr->callstack_top + level,
- str,
- 0);
- } else {
- /* No activation, no variable access. Could also pretend
- * we're in the global program context and read stuff off
- * the global object.
- */
- DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore getvar"));
- rc = 0;
- }
-
- duk_debug_write_reply(thr);
- if (rc) {
- duk_debug_write_int(thr, 1);
- DUK_ASSERT(duk_get_tval(ctx, -2) != NULL);
- duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
- } else {
- duk_debug_write_int(thr, 0);
- duk_debug_write_unused(thr);
- }
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
- duk_hstring *str;
- duk_tval *tv;
- duk_int32_t level;
-
- DUK_UNREF(heap);
- DUK_D(DUK_DPRINT("debug command PutVar"));
-
- str = duk_debug_read_hstring(thr); /* push to stack */
- DUK_ASSERT(str != NULL);
- tv = duk_debug_read_tval(thr);
- if (tv == NULL) {
- /* detached */
- return;
- }
- if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- level = duk_debug_read_int(thr); /* optional callstack level */
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for PutVar"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
- return;
- }
- } else {
- level = -1;
- }
-
- if (thr->callstack_top > 0) {
- duk_js_putvar_activation(thr,
- thr->callstack + thr->callstack_top + level,
- str,
- tv,
- 0);
- } else {
- DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
- }
-
- /* XXX: Current putvar implementation doesn't have a success flag,
- * add one and send to debug client?
- */
- duk_debug_write_reply(thr);
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
- duk_hthread *curr_thr = thr;
- duk_activation *curr_act;
- duk_uint_fast32_t pc;
- duk_uint_fast32_t line;
- duk_size_t i;
-
- DUK_ASSERT(thr != NULL);
- DUK_UNREF(heap);
-
- duk_debug_write_reply(thr);
- while (curr_thr != NULL) {
- i = curr_thr->callstack_top;
- while (i > 0) {
- i--;
- curr_act = curr_thr->callstack + i;
-
- /* PC/line semantics here are:
- * - For callstack top we're conceptually between two
- * opcodes and current PC indicates next line to
- * execute, so report that (matches Status).
- * - For other activations we're conceptually still
- * executing the instruction at PC-1, so report that
- * (matches error stacktrace behavior).
- * - See: https://github.com/svaarala/duktape/issues/281
- */
-
- /* XXX: optimize to use direct reads, i.e. avoid
- * value stack operations.
- */
- duk_push_tval(ctx, &curr_act->tv_func);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
- duk__debug_write_hstring_safe_top(thr);
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME);
- duk__debug_write_hstring_safe_top(thr);
- pc = duk_hthread_get_act_curr_pc(thr, curr_act);
- if (i != curr_thr->callstack_top - 1 && pc > 0) {
- pc--;
- }
- line = duk_hobject_pc2line_query(ctx, -3, pc);
- duk_debug_write_uint(thr, (duk_uint32_t) line);
- duk_debug_write_uint(thr, (duk_uint32_t) pc);
- duk_pop_3(ctx);
- }
- curr_thr = curr_thr->resumer;
- }
- /* SCANBUILD: warning about 'thr' potentially being NULL here,
- * warning is incorrect because thr != NULL always here.
- */
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *curr_act;
- duk_int32_t level;
- duk_hstring *varname;
-
- DUK_UNREF(heap);
-
- if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- level = duk_debug_read_int(thr); /* optional callstack level */
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for GetLocals"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
- return;
- }
- duk_debug_write_reply(thr);
- } else {
- duk_debug_write_reply(thr);
- if (thr->callstack_top == 0) {
- goto callstack_empty;
- }
- level = -1;
- }
-
- curr_act = thr->callstack + thr->callstack_top + level;
-
- /* XXX: several nice-to-have improvements here:
- * - Use direct reads avoiding value stack operations
- * - Avoid triggering getters, indicate getter values to debug client
- * - If side effects are possible, add error catching
- */
-
- duk_push_tval(ctx, &curr_act->tv_func);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP);
- if (duk_is_object(ctx, -1)) {
- duk_enum(ctx, -1, 0 /*enum_flags*/);
- while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
- varname = duk_get_hstring(ctx, -1);
- DUK_ASSERT(varname != NULL);
-
- duk_js_getvar_activation(thr, curr_act, varname, 0 /*throw_flag*/);
- /* [ ... func varmap enum key value this ] */
- duk_debug_write_hstring(thr, duk_get_hstring(ctx, -3));
- duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
- duk_pop_3(ctx); /* -> [ ... func varmap enum ] */
- }
- } else {
- DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
- }
-
- callstack_empty:
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_t call_flags;
- duk_int_t call_ret;
- duk_small_int_t eval_err;
- duk_int32_t level;
-
- DUK_UNREF(heap);
-
- DUK_D(DUK_DPRINT("debug command Eval"));
-
- /* The eval code is executed within the lexical environment of a specified
- * activation. For now, use global object eval() function, with the eval
- * considered a 'direct call to eval'.
- *
- * Callstack level for debug commands only affects scope -- the callstack
- * as seen by, e.g. Duktape.act() will be the same regardless.
- */
-
- /* nargs == 2 so we can pass a callstack level to eval(). */
- duk_push_c_function(ctx, duk_bi_global_object_eval, 2 /*nargs*/);
- duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */
-
- (void) duk_debug_read_hstring(thr);
- if (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- level = duk_debug_read_int(thr); /* optional callstack level */
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for Eval"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
- return;
- }
- }
- else {
- level = -1;
- }
- DUK_ASSERT(level < 0 && -level <= (duk_int32_t) thr->callstack_top);
- duk_push_int(ctx, level - 1); /* compensate for eval() call */
-
- /* [ ... eval "eval" eval_input level ] */
-
- call_flags = 0;
- if (thr->callstack_top >= (duk_size_t) -level) {
- duk_activation *act;
- duk_hobject *fun;
-
- act = thr->callstack + thr->callstack_top + level;
- fun = DUK_ACT_GET_FUNC(act);
- if (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(fun)) {
- /* Direct eval requires that there's a current
- * activation and it is an Ecmascript function.
- * When Eval is executed from e.g. cooperate API
- * call we'll need to do an indirect eval instead.
- */
- call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
- }
- }
-
- call_ret = duk_handle_call_protected(thr, 2 /*num_stack_args*/, call_flags);
-
- if (call_ret == DUK_EXEC_SUCCESS) {
- eval_err = 0;
- /* Use result value as is. */
- } else {
- /* For errors a string coerced result is most informative
- * right now, as the debug client doesn't have the capability
- * to traverse the error object.
- */
- eval_err = 1;
- duk_safe_to_string(ctx, -1);
- }
-
- /* [ ... result ] */
-
- duk_debug_write_reply(thr);
- duk_debug_write_int(thr, (duk_int32_t) eval_err);
- DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
- duk_debug_write_tval(thr, duk_get_tval(ctx, -1));
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
- DUK_UNREF(heap);
- DUK_D(DUK_DPRINT("debug command Detach"));
-
- duk_debug_write_reply(thr);
- duk_debug_write_eom(thr);
-
- DUK_D(DUK_DPRINT("debug connection detached, mark broken"));
- DUK__SET_CONN_BROKEN(thr, 0); /* not an error */
-}
-
-DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
- duk_context *ctx = (duk_context *) thr;
- duk_idx_t old_top;
-
- DUK_D(DUK_DPRINT("debug command AppRequest"));
-
- old_top = duk_get_top(ctx); /* save stack top */
-
- if (heap->dbg_request_cb != NULL) {
- duk_idx_t nrets;
- duk_idx_t nvalues = 0;
- duk_idx_t top, idx;
-
- /* Read tvals from the message and push them onto the valstack,
- * then call the request callback to process the request.
- */
- while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
- duk_tval *tv;
- if (!duk_check_stack(ctx, 1)) {
- DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)"));
- goto fail;
- }
- tv = duk_debug_read_tval(thr); /* push to stack */
- if (tv == NULL) {
- /* detached */
- return;
- }
- nvalues++;
- }
- DUK_ASSERT(duk_get_top(ctx) == old_top + nvalues);
-
- /* Request callback should push values for reply to client onto valstack */
- DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld",
- (long) nvalues, (long) old_top, (long) duk_get_top(ctx)));
- nrets = heap->dbg_request_cb(ctx, heap->dbg_udata, nvalues);
- DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld",
- (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(ctx)));
- if (nrets >= 0) {
- DUK_ASSERT(duk_get_top(ctx) >= old_top + nrets);
- if (duk_get_top(ctx) < old_top + nrets) {
- DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, "
- "top=%ld < old_top=%ld + nrets=%ld; "
- "this might mean it's unsafe to continue!",
- (long) duk_get_top(ctx), (long) old_top, (long) nrets));
- goto fail;
- }
-
- /* Reply with tvals pushed by request callback */
- duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
- top = duk_get_top(ctx);
- for (idx = top - nrets; idx < top; idx++) {
- duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(ctx, idx));
- }
- duk_debug_write_eom(thr);
- } else {
- DUK_ASSERT(duk_get_top(ctx) >= old_top + 1);
- if (duk_get_top(ctx) < old_top + 1) {
- DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration"));
- goto fail;
- }
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(ctx, -1));
- }
-
- duk_set_top(ctx, old_top); /* restore stack top */
- } else {
- DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported"));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target");
- }
-
- return;
-
- fail:
- duk_set_top(ctx, old_top); /* restore stack top */
- DUK__SET_CONN_BROKEN(thr, 1);
-}
-
-/*
- * DumpHeap command
- */
-
-#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
-/* XXX: this has some overlap with object inspection; remove this and make
- * DumpHeap return lists of heapptrs instead?
- */
-DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) {
- DUK_UNREF(heap);
-
- duk_debug_write_heapptr(thr, hdr);
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr));
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr));
-#if defined(DUK_USE_REFERENCE_COUNTING)
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr));
-#else
- duk_debug_write_int(thr, (duk_int32_t) -1);
-#endif
-
- switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
- case DUK_HTYPE_STRING: {
- duk_hstring *h = (duk_hstring *) hdr;
-
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_BYTELEN(h));
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_CHARLEN(h));
- duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_HASH(h));
- duk_debug_write_hstring(thr, h);
- break;
- }
- case DUK_HTYPE_OBJECT: {
- duk_hobject *h = (duk_hobject *) hdr;
- duk_hstring *k;
- duk_uint_fast32_t i;
-
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h));
- duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h));
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h));
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h));
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h));
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i));
- k = DUK_HOBJECT_E_GET_KEY(heap, h, i);
- duk_debug_write_heapptr(thr, (duk_heaphdr *) k);
- if (k == NULL) {
- duk_debug_write_int(thr, 0); /* isAccessor */
- duk_debug_write_unused(thr);
- continue;
- }
- if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
- duk_debug_write_int(thr, 1); /* isAccessor */
- duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
- duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
- } else {
- duk_debug_write_int(thr, 0); /* isAccessor */
-
- duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
- }
- }
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
- /* Note: array dump will include elements beyond
- * 'length'.
- */
- duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
- }
- break;
- }
- case DUK_HTYPE_BUFFER: {
- duk_hbuffer *h = (duk_hbuffer *) hdr;
-
- duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h));
- duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
- break;
- }
- default: {
- DUK_D(DUK_DPRINT("invalid htype: %d", (int) DUK_HEAPHDR_GET_TYPE(hdr)));
- }
- }
-}
-
-DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) {
- duk_heaphdr *hdr;
-
- hdr = heap->heap_allocated;
- while (hdr != NULL) {
- duk__debug_dump_heaphdr(thr, heap, hdr);
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-}
-
-#if defined(DUK_USE_STRTAB_CHAIN)
-DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) {
- duk_uint_fast32_t i, j;
- duk_strtab_entry *e;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *lst;
-#else
- duk_hstring **lst;
-#endif
- duk_hstring *h;
-
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
- e = heap->strtable + i;
- if (e->listlen > 0) {
-#if defined(DUK_USE_HEAPPTR16)
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
-#else
- lst = e->u.strlist;
-#endif
- DUK_ASSERT(lst != NULL);
-
- for (j = 0; j < e->listlen; j++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
-#else
- h = lst[j];
-#endif
- if (h != NULL) {
- duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
- }
- }
- } else {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
-#else
- h = e->u.str;
-#endif
- if (h != NULL) {
- duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
- }
- }
- }
-}
-#endif /* DUK_USE_STRTAB_CHAIN */
-
-#if defined(DUK_USE_STRTAB_PROBE)
-DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) {
- duk_uint32_t i;
- duk_hstring *h;
-
- for (i = 0; i < heap->st_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]);
-#else
- h = heap->strtable[i];
-#endif
- if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
- continue;
- }
-
- duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
- }
-}
-#endif /* DUK_USE_STRTAB_PROBE */
-
-DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) {
- DUK_D(DUK_DPRINT("debug command DumpHeap"));
-
- duk_debug_write_reply(thr);
- duk__debug_dump_heap_allocated(thr, heap);
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk__debug_dump_strtab_chain(thr, heap);
-#endif
-#if defined(DUK_USE_STRTAB_PROBE)
- duk__debug_dump_strtab_probe(thr, heap);
-#endif
- duk_debug_write_eom(thr);
-}
-#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
-
-DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) {
- duk_activation *act;
- duk_hcompiledfunction *fun = NULL;
- duk_size_t i, n;
- duk_tval *tv;
- duk_hobject **fn;
- duk_int32_t level = -1;
- duk_uint8_t ibyte;
-
- DUK_UNREF(heap);
-
- DUK_D(DUK_DPRINT("debug command GetBytecode"));
-
- ibyte = duk_debug_peek_byte(thr);
- if (ibyte != DUK_DBG_IB_EOM) {
- tv = duk_debug_read_tval(thr);
- if (tv == NULL) {
- /* detached */
- return;
- }
- if (DUK_TVAL_IS_OBJECT(tv)) {
- /* tentative, checked later */
- fun = (duk_hcompiledfunction *) DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(fun != NULL);
- } else if (DUK_TVAL_IS_NUMBER(tv)) {
- level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv);
- } else {
- DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!T", tv));
- goto fail_args;
- }
- }
-
- if (fun == NULL) {
- if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
- DUK_D(DUK_DPRINT("invalid callstack level for GetBytecode"));
- goto fail_level;
- }
- act = thr->callstack + thr->callstack_top + level;
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
- }
-
- if (fun == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)) {
- DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O", fun));
- goto fail_args;
- }
- DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun));
-
- duk_debug_write_reply(thr);
- n = DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap, fun);
- duk_debug_write_int(thr, (duk_int32_t) n);
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, fun);
- for (i = 0; i < n; i++) {
- duk_debug_write_tval(thr, tv);
- tv++;
- }
- n = DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap, fun);
- duk_debug_write_int(thr, (duk_int32_t) n);
- fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, fun);
- for (i = 0; i < n; i++) {
- duk_debug_write_hobject(thr, *fn);
- fn++;
- }
- duk_debug_write_string(thr,
- (const char *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap, fun),
- (duk_size_t) DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap, fun));
- duk_debug_write_eom(thr);
- return;
-
- fail_args:
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument");
- return;
-
- fail_level:
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack level");
- return;
-}
-
-/*
- * Object inspection commands: GetHeapObjInfo, GetObjPropDesc,
- * GetObjPropDescRange
- */
-
-#if defined(DUK_USE_DEBUGGER_INSPECT)
-
-#if 0 /* pruned */
-DUK_LOCAL const char * const duk__debug_getinfo_heaphdr_keys[] = {
- "reachable",
- "temproot",
- "finalizable",
- "finalized",
- "readonly"
- /* NULL not needed here */
-};
-DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = {
- DUK_HEAPHDR_FLAG_REACHABLE,
- DUK_HEAPHDR_FLAG_TEMPROOT,
- DUK_HEAPHDR_FLAG_FINALIZABLE,
- DUK_HEAPHDR_FLAG_FINALIZED,
- DUK_HEAPHDR_FLAG_READONLY,
- 0 /* terminator */
-};
-#endif
-DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = {
-#if 0
- "arridx",
- "internal",
- "reserved_word",
- "strict_reserved_word",
- "eval_or_arguments",
-#endif
- "extdata"
- /* NULL not needed here */
-};
-DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
-#if 0
- DUK_HSTRING_FLAG_ARRIDX,
- DUK_HSTRING_FLAG_INTERNAL,
- DUK_HSTRING_FLAG_RESERVED_WORD,
- DUK_HSTRING_FLAG_STRICT_RESERVED_WORD,
- DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS,
-#endif
- DUK_HSTRING_FLAG_EXTDATA,
- 0 /* terminator */
-};
-DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
- "extensible",
- "constructable",
- "bound",
- "compiledfunction",
- "nativefunction",
- "bufferobject",
- "thread",
- "array_part",
- "strict",
- "notail",
- "newenv",
- "namebinding",
- "createargs",
- "envrecclosed",
- "exotic_array",
- "exotic_stringobj",
- "exotic_arguments",
- "exotic_dukfunc",
- "exotic_proxyobj"
- /* NULL not needed here */
-};
-DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
- DUK_HOBJECT_FLAG_EXTENSIBLE,
- DUK_HOBJECT_FLAG_CONSTRUCTABLE,
- DUK_HOBJECT_FLAG_BOUND,
- DUK_HOBJECT_FLAG_COMPILEDFUNCTION,
- DUK_HOBJECT_FLAG_NATIVEFUNCTION,
- DUK_HOBJECT_FLAG_BUFFEROBJECT,
- DUK_HOBJECT_FLAG_THREAD,
- DUK_HOBJECT_FLAG_ARRAY_PART,
- DUK_HOBJECT_FLAG_STRICT,
- DUK_HOBJECT_FLAG_NOTAIL,
- DUK_HOBJECT_FLAG_NEWENV,
- DUK_HOBJECT_FLAG_NAMEBINDING,
- DUK_HOBJECT_FLAG_CREATEARGS,
- DUK_HOBJECT_FLAG_ENVRECCLOSED,
- DUK_HOBJECT_FLAG_EXOTIC_ARRAY,
- DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ,
- DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS,
- DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC,
- DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ,
- 0 /* terminator */
-};
-DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = {
- "dynamic",
- "external"
- /* NULL not needed here */
-};
-DUK_LOCAL duk_uint_t duk__debug_getinfo_hbuffer_masks[] = {
- DUK_HBUFFER_FLAG_DYNAMIC,
- DUK_HBUFFER_FLAG_EXTERNAL,
- 0 /* terminator */
-};
-
-DUK_LOCAL void duk__debug_getinfo_flags_key(duk_hthread *thr, const char *key) {
- duk_debug_write_uint(thr, 0);
- duk_debug_write_cstring(thr, key);
-}
-
-DUK_LOCAL void duk__debug_getinfo_prop_uint(duk_hthread *thr, const char *key, duk_uint_t val) {
- duk_debug_write_uint(thr, 0);
- duk_debug_write_cstring(thr, key);
- duk_debug_write_uint(thr, val);
-}
-
-DUK_LOCAL void duk__debug_getinfo_prop_int(duk_hthread *thr, const char *key, duk_int_t val) {
- duk_debug_write_uint(thr, 0);
- duk_debug_write_cstring(thr, key);
- duk_debug_write_int(thr, val);
-}
-
-DUK_LOCAL void duk__debug_getinfo_prop_bool(duk_hthread *thr, const char *key, duk_bool_t val) {
- duk_debug_write_uint(thr, 0);
- duk_debug_write_cstring(thr, key);
- duk_debug_write_boolean(thr, val);
-}
-
-DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const * keys, duk_uint_t *masks, duk_uint_t flags) {
- const char *key;
- duk_uint_t mask;
-
- for (;;) {
- mask = *masks++;
- if (!mask) {
- break;
- }
- key = *keys++;
- DUK_ASSERT(key != NULL);
-
- DUK_DD(DUK_DDPRINT("inspect bitmask: key=%s, mask=0x%08lx, flags=0x%08lx", key, (unsigned long) mask, (unsigned long) flags));
- duk__debug_getinfo_prop_bool(thr, key, flags & mask);
- }
-}
-
-/* Inspect a property using a virtual index into a conceptual property list
- * consisting of (1) all array part items from [0,a_size[ (even when above
- * .length) and (2) all entry part items from [0,e_next[. Unused slots are
- * indicated using dvalue 'unused'.
- */
-DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap, duk_hobject *h_obj, duk_uint_t idx) {
- duk_uint_t a_size;
- duk_tval *tv;
- duk_hstring *h_key;
- duk_hobject *h_getset;
- duk_uint_t flags;
-
- DUK_UNREF(heap);
-
- a_size = DUK_HOBJECT_GET_ASIZE(h_obj);
- if (idx < a_size) {
- duk_debug_write_uint(thr, DUK_PROPDESC_FLAGS_WEC);
- duk_debug_write_uint(thr, idx);
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, h_obj, idx);
- duk_debug_write_tval(thr, tv);
- return 1;
- }
-
- idx -= a_size;
- if (idx >= DUK_HOBJECT_GET_ENEXT(h_obj)) {
- return 0;
- }
-
- h_key = DUK_HOBJECT_E_GET_KEY(heap, h_obj, idx);
- if (h_key == NULL) {
- duk_debug_write_uint(thr, 0);
- duk_debug_write_null(thr);
- duk_debug_write_unused(thr);
- return 1;
- }
-
- flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx);
- if (DUK_HSTRING_HAS_INTERNAL(h_key)) {
- flags |= DUK_DBG_PROPFLAG_INTERNAL;
- }
- duk_debug_write_uint(thr, flags);
- duk_debug_write_hstring(thr, h_key);
- if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- h_getset = DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h_obj, idx);
- if (h_getset) {
- duk_debug_write_hobject(thr, h_getset);
- } else {
- duk_debug_write_null(thr);
- }
- h_getset = DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h_obj, idx);
- if (h_getset) {
- duk_debug_write_hobject(thr, h_getset);
- } else {
- duk_debug_write_null(thr);
- }
- } else {
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h_obj, idx);
- duk_debug_write_tval(thr, tv);
- }
- return 1;
-}
-
-DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *heap) {
- duk_heaphdr *h;
-
- DUK_D(DUK_DPRINT("debug command GetHeapObjInfo"));
- DUK_UNREF(heap);
-
- h = duk_debug_read_any_ptr(thr);
- if (!h) {
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
- return;
- }
-
- duk_debug_write_reply(thr);
-
- /* As with all inspection code, we rely on the debug client providing
- * a valid, non-stale pointer: there's no portable way to safely
- * validate the pointer here.
- */
-
- duk__debug_getinfo_flags_key(thr, "heapptr");
- duk_debug_write_heapptr(thr, h);
-
- /* XXX: comes out as signed now */
- duk__debug_getinfo_prop_uint(thr, "heaphdr_flags", (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
- duk__debug_getinfo_prop_uint(thr, "heaphdr_type", (duk_uint_t) DUK_HEAPHDR_GET_TYPE(h));
-#if defined(DUK_USE_REFERENCE_COUNTING)
- duk__debug_getinfo_prop_uint(thr, "refcount", (duk_uint_t) DUK_HEAPHDR_GET_REFCOUNT(h));
-#endif
-#if 0 /* pruned */
- duk__debug_getinfo_bitmask(thr,
- duk__debug_getinfo_heaphdr_keys,
- duk__debug_getinfo_heaphdr_masks,
- DUK_HEAPHDR_GET_FLAGS_RAW(h));
-#endif
-
- switch (DUK_HEAPHDR_GET_TYPE(h)) {
- case DUK_HTYPE_STRING: {
- duk_hstring *h_str;
-
- h_str = (duk_hstring *) h;
- duk__debug_getinfo_bitmask(thr,
- duk__debug_getinfo_hstring_keys,
- duk__debug_getinfo_hstring_masks,
- DUK_HEAPHDR_GET_FLAGS_RAW(h));
- duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str));
- duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str));
- duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str));
- duk__debug_getinfo_flags_key(thr, "data");
- duk_debug_write_hstring(thr, h_str);
- break;
- }
- case DUK_HTYPE_OBJECT: {
- duk_hobject *h_obj;
- duk_hobject *h_proto;
-
- h_obj = (duk_hobject *) h;
- h_proto = DUK_HOBJECT_GET_PROTOTYPE(heap, h_obj);
-
- /* duk_hobject specific fields. */
- duk__debug_getinfo_bitmask(thr,
- duk__debug_getinfo_hobject_keys,
- duk__debug_getinfo_hobject_masks,
- DUK_HEAPHDR_GET_FLAGS_RAW(h));
- duk__debug_getinfo_prop_uint(thr, "class_number", DUK_HOBJECT_GET_CLASS_NUMBER(h_obj));
- duk__debug_getinfo_flags_key(thr, "class_name");
- duk_debug_write_hstring(thr, DUK_HOBJECT_GET_CLASS_STRING(heap, h_obj));
- duk__debug_getinfo_flags_key(thr, "prototype");
- if (h_proto != NULL) {
- duk_debug_write_hobject(thr, h_proto);
- } else {
- duk_debug_write_null(thr);
- }
- duk__debug_getinfo_flags_key(thr, "props");
- duk_debug_write_pointer(thr, (void *) DUK_HOBJECT_GET_PROPS(heap, h_obj));
- duk__debug_getinfo_prop_uint(thr, "e_size", (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
- duk__debug_getinfo_prop_uint(thr, "e_next", (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
- duk__debug_getinfo_prop_uint(thr, "a_size", (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
- duk__debug_getinfo_prop_uint(thr, "h_size", (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
-
- /* duk_hnativefunction specific fields. */
- if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj)) {
- duk_hnativefunction *h_fun;
- h_fun = (duk_hnativefunction *) h_obj;
-
- duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
- duk__debug_getinfo_prop_int(thr, "magic", h_fun->magic);
- duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATIVEFUNCTION_NARGS_VARARGS);
- /* Native function pointer may be different from a void pointer,
- * and we serialize it from memory directly now (no byte swapping etc).
- */
- duk__debug_getinfo_flags_key(thr, "funcptr");
- duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func));
- }
-
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj)) {
- duk_hcompiledfunction *h_fun;
- duk_hbuffer *h_buf;
- h_fun = (duk_hcompiledfunction *) h_obj;
-
- duk__debug_getinfo_prop_int(thr, "nregs", h_fun->nregs);
- duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
- duk__debug_getinfo_prop_uint(thr, "start_line", h_fun->start_line);
- duk__debug_getinfo_prop_uint(thr, "end_line", h_fun->end_line);
- h_buf = (duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, h_fun);
- if (h_buf != NULL) {
- duk__debug_getinfo_flags_key(thr, "data");
- duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf);
- }
- }
-
- if (DUK_HOBJECT_IS_THREAD(h_obj)) {
- /* XXX: Currently no inspection of threads, e.g. value stack, call
- * stack, catch stack, etc.
- */
- duk_hthread *h_thr;
- h_thr = (duk_hthread *) h_obj;
- DUK_UNREF(h_thr);
- }
-
- if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj)) {
- duk_hbufferobject *h_bufobj;
- h_bufobj = (duk_hbufferobject *) h_obj;
-
- duk__debug_getinfo_prop_uint(thr, "slice_offset", h_bufobj->offset);
- duk__debug_getinfo_prop_uint(thr, "slice_length", h_bufobj->length);
- duk__debug_getinfo_prop_uint(thr, "elem_shift", (duk_uint_t) h_bufobj->shift);
- duk__debug_getinfo_prop_uint(thr, "elem_type", (duk_uint_t) h_bufobj->elem_type);
- duk__debug_getinfo_prop_bool(thr, "is_view", (duk_uint_t) h_bufobj->is_view);
- if (h_bufobj->buf != NULL) {
- duk__debug_getinfo_flags_key(thr, "buffer");
- duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf);
- }
- }
- break;
- }
- case DUK_HTYPE_BUFFER: {
- duk_hbuffer *h_buf;
-
- h_buf = (duk_hbuffer *) h;
- duk__debug_getinfo_bitmask(thr,
- duk__debug_getinfo_hbuffer_keys,
- duk__debug_getinfo_hbuffer_masks,
- DUK_HEAPHDR_GET_FLAGS_RAW(h));
- duk__debug_getinfo_prop_uint(thr, "size", (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
- duk__debug_getinfo_flags_key(thr, "dataptr");
- duk_debug_write_pointer(thr, (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf));
- duk__debug_getinfo_flags_key(thr, "data");
- duk_debug_write_hbuffer(thr, h_buf); /* tolerates NULL h_buf */
- break;
- }
- default: {
- /* Since we already started writing the reply, just emit nothing. */
- DUK_D(DUK_DPRINT("inspect target pointer has invalid heaphdr type"));
- }
- }
-
- duk_debug_write_eom(thr);
-}
-
-DUK_LOCAL void duk__debug_handle_get_obj_prop_desc(duk_hthread *thr, duk_heap *heap) {
- duk_heaphdr *h;
- duk_hobject *h_obj;
- duk_hstring *h_key;
- duk_propdesc desc;
-
- DUK_D(DUK_DPRINT("debug command GetObjPropDesc"));
- DUK_UNREF(heap);
-
- h = duk_debug_read_any_ptr(thr);
- if (!h) {
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
- return;
- }
- h_key = duk_debug_read_hstring(thr);
- if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT || h_key == NULL) {
- goto fail_args;
- }
- h_obj = (duk_hobject *) h;
-
- if (duk_hobject_get_own_propdesc(thr, h_obj, h_key, &desc, 0 /*flags*/)) {
- duk_int_t virtual_idx;
- duk_bool_t rc;
-
- /* To use the shared helper need the virtual index. */
- DUK_ASSERT(desc.e_idx >= 0 || desc.a_idx >= 0);
- virtual_idx = (desc.a_idx >= 0 ? desc.a_idx :
- (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj) + desc.e_idx);
-
- duk_debug_write_reply(thr);
- rc = duk__debug_getprop_index(thr, heap, h_obj, (duk_uint_t) virtual_idx);
- DUK_ASSERT(rc == 1);
- DUK_UNREF(rc);
- duk_debug_write_eom(thr);
- } else {
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "not found");
- }
- return;
-
- fail_args:
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
-}
-
-DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_heap *heap) {
- duk_heaphdr *h;
- duk_hobject *h_obj;
- duk_uint_t idx, idx_start, idx_end;
-
- DUK_D(DUK_DPRINT("debug command GetObjPropDescRange"));
- DUK_UNREF(heap);
-
- h = duk_debug_read_any_ptr(thr);
- idx_start = duk_debug_read_int(thr);
- idx_end = duk_debug_read_int(thr);
- if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) {
- goto fail_args;
- }
- h_obj = (duk_hobject *) h;
-
- /* The index range space is conceptually the array part followed by the
- * entry part. Unlike normal enumeration all slots are exposed here as
- * is and return 'unused' if the slots are not in active use. In particular
- * the array part is included for the full a_size regardless of what the
- * array .length is.
- */
-
- duk_debug_write_reply(thr);
- for (idx = idx_start; idx < idx_end; idx++) {
- if (!duk__debug_getprop_index(thr, heap, h_obj, idx)) {
- break;
- }
- }
- duk_debug_write_eom(thr);
- return;
-
- fail_args:
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
-}
-
-#endif /* DUK_USE_DEBUGGER_INSPECT */
-
-/*
- * Process incoming debug requests
- *
- * Individual request handlers can push temporaries on the value stack and
- * rely on duk__debug_process_message() to restore the value stack top
- * automatically.
- */
-
-/* Process one debug message. Automatically restore value stack top to its
- * entry value, so that individual message handlers don't need exact value
- * stack handling which is convenient.
- */
-DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_heap *heap;
- duk_uint8_t x;
- duk_int32_t cmd;
- duk_idx_t entry_top;
-
- DUK_ASSERT(thr != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
- DUK_UNREF(ctx);
-
- entry_top = duk_get_top(ctx);
-
- x = duk_debug_read_byte(thr);
- switch (x) {
- case DUK_DBG_IB_REQUEST: {
- cmd = duk_debug_read_int(thr);
- switch (cmd) {
- case DUK_DBG_CMD_BASICINFO: {
- duk__debug_handle_basic_info(thr, heap);
- break;
- }
- case DUK_DBG_CMD_TRIGGERSTATUS: {
- duk__debug_handle_trigger_status(thr, heap);
- break;
- }
- case DUK_DBG_CMD_PAUSE: {
- duk__debug_handle_pause(thr, heap);
- break;
- }
- case DUK_DBG_CMD_RESUME: {
- duk__debug_handle_resume(thr, heap);
- break;
- }
- case DUK_DBG_CMD_STEPINTO:
- case DUK_DBG_CMD_STEPOVER:
- case DUK_DBG_CMD_STEPOUT: {
- duk__debug_handle_step(thr, heap, cmd);
- break;
- }
- case DUK_DBG_CMD_LISTBREAK: {
- duk__debug_handle_list_break(thr, heap);
- break;
- }
- case DUK_DBG_CMD_ADDBREAK: {
- duk__debug_handle_add_break(thr, heap);
- break;
- }
- case DUK_DBG_CMD_DELBREAK: {
- duk__debug_handle_del_break(thr, heap);
- break;
- }
- case DUK_DBG_CMD_GETVAR: {
- duk__debug_handle_get_var(thr, heap);
- break;
- }
- case DUK_DBG_CMD_PUTVAR: {
- duk__debug_handle_put_var(thr, heap);
- break;
- }
- case DUK_DBG_CMD_GETCALLSTACK: {
- duk__debug_handle_get_call_stack(thr, heap);
- break;
- }
- case DUK_DBG_CMD_GETLOCALS: {
- duk__debug_handle_get_locals(thr, heap);
- break;
- }
- case DUK_DBG_CMD_EVAL: {
- duk__debug_handle_eval(thr, heap);
- break;
- }
- case DUK_DBG_CMD_DETACH: {
- /* The actual detached_cb call is postponed to message loop so
- * we don't need any special precautions here (just skip to EOM
- * on the already closed connection).
- */
- duk__debug_handle_detach(thr, heap);
- break;
- }
-#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
- case DUK_DBG_CMD_DUMPHEAP: {
- duk__debug_handle_dump_heap(thr, heap);
- break;
- }
-#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
- case DUK_DBG_CMD_GETBYTECODE: {
- duk__debug_handle_get_bytecode(thr, heap);
- break;
- }
- case DUK_DBG_CMD_APPREQUEST: {
- duk__debug_handle_apprequest(thr, heap);
- break;
- }
-#if defined(DUK_USE_DEBUGGER_INSPECT)
- case DUK_DBG_CMD_GETHEAPOBJINFO: {
- duk__debug_handle_get_heap_obj_info(thr, heap);
- break;
- }
- case DUK_DBG_CMD_GETOBJPROPDESC: {
- duk__debug_handle_get_obj_prop_desc(thr, heap);
- break;
- }
- case DUK_DBG_CMD_GETOBJPROPDESCRANGE: {
- duk__debug_handle_get_obj_prop_desc_range(thr, heap);
- break;
- }
-#endif /* DUK_USE_DEBUGGER_INSPECT */
- default: {
- DUK_D(DUK_DPRINT("debug command unsupported: %d", (int) cmd));
- duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command");
- }
- } /* switch cmd */
- break;
- }
- case DUK_DBG_IB_REPLY: {
- DUK_D(DUK_DPRINT("debug reply, skipping"));
- break;
- }
- case DUK_DBG_IB_ERROR: {
- DUK_D(DUK_DPRINT("debug error, skipping"));
- break;
- }
- case DUK_DBG_IB_NOTIFY: {
- DUK_D(DUK_DPRINT("debug notify, skipping"));
- break;
- }
- default: {
- DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x));
- goto fail;
- }
- } /* switch initial byte */
-
- DUK_ASSERT(duk_get_top(ctx) >= entry_top);
- duk_set_top(ctx, entry_top);
- duk__debug_skip_to_eom(thr);
- return;
-
- fail:
- DUK_ASSERT(duk_get_top(ctx) >= entry_top);
- duk_set_top(ctx, entry_top);
- DUK__SET_CONN_BROKEN(thr, 1);
- return;
-}
-
-DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) {
- if (thr->heap->dbg_read_cb != NULL && thr->heap->dbg_state_dirty) {
- duk_debug_send_status(thr);
- thr->heap->dbg_state_dirty = 0;
- }
-}
-
-DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
- duk_context *ctx = (duk_context *) thr;
-#if defined(DUK_USE_ASSERTIONS)
- duk_idx_t entry_top;
-#endif
- duk_bool_t retval = 0;
-
- DUK_ASSERT(thr != NULL);
- DUK_UNREF(ctx);
- DUK_ASSERT(thr->heap != NULL);
-#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
-#endif
-
- DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld",
- thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block,
- (long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing));
- DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(ctx)));
-
- /* thr->heap->dbg_detaching may be != 0 if a debugger write outside
- * the message loop caused a transport error and detach1() to run.
- */
- DUK_ASSERT(thr->heap->dbg_detaching == 0 || thr->heap->dbg_detaching == 1);
- DUK_ASSERT(thr->heap->dbg_processing == 0);
- thr->heap->dbg_processing = 1;
-
- /* Ensure dirty state causes a Status even if never process any
- * messages. This is expected by the bytecode executor when in
- * the running state.
- */
- duk__check_resend_status(thr);
-
- for (;;) {
- /* Process messages until we're no longer paused or we peek
- * and see there's nothing to read right now.
- */
- DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(ctx)));
- DUK_ASSERT(thr->heap->dbg_processing == 1);
-
- while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) {
- /* Detach is pending; can be triggered from outside the
- * debugger loop (e.g. Status notify write error) or by
- * previous message handling. Call detached callback
- * here, in a controlled state, to ensure a possible
- * reattach inside the detached_cb is handled correctly.
- *
- * Recheck for detach in a while loop: an immediate
- * reattach involves a call to duk_debugger_attach()
- * which writes a debugger handshake line immediately
- * inside the API call. If the transport write fails
- * for that handshake, we can immediately end up in a
- * "transport broken, detaching" case several times here.
- * Loop back until we're either cleanly attached or
- * fully detached.
- *
- * NOTE: Reset dbg_processing = 1 forcibly, in case we
- * re-attached; duk_debugger_attach() sets dbg_processing
- * to 0 at the moment.
- */
-
- DUK_D(DUK_DPRINT("detach pending (dbg_read_cb == NULL, dbg_detaching != 0), call detach2"));
-
- duk__debug_do_detach2(thr->heap);
- thr->heap->dbg_processing = 1; /* may be set to 0 by duk_debugger_attach() inside callback */
-
- DUK_D(DUK_DPRINT("after detach2 (and possible reattach): dbg_read_cb=%s, dbg_detaching=%ld",
- thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) thr->heap->dbg_detaching));
- }
- DUK_ASSERT(thr->heap->dbg_detaching == 0); /* true even with reattach */
- DUK_ASSERT(thr->heap->dbg_processing == 1); /* even after a detach and possible reattach */
-
- if (thr->heap->dbg_read_cb == NULL) {
- DUK_D(DUK_DPRINT("debug connection broken (and not detaching), stop processing messages"));
- break;
- }
-
- if (!thr->heap->dbg_paused || no_block) {
- if (!duk_debug_read_peek(thr)) {
- /* Note: peek cannot currently trigger a detach
- * so the dbg_detaching == 0 assert outside the
- * loop is correct.
- */
- DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing messages"));
- break;
- }
- DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it"));
- } else {
- DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary"));
- }
-
- duk__check_resend_status(thr);
- duk__debug_process_message(thr);
- duk__check_resend_status(thr);
-
- retval = 1; /* processed one or more messages */
- }
-
- DUK_ASSERT(thr->heap->dbg_detaching == 0);
- DUK_ASSERT(thr->heap->dbg_processing == 1);
- thr->heap->dbg_processing = 0;
-
- /* As an initial implementation, read flush after exiting the message
- * loop. If transport is broken, this is a no-op (with debug logs).
- */
- duk_debug_read_flush(thr); /* this cannot initiate a detach */
- DUK_ASSERT(thr->heap->dbg_detaching == 0);
-
- DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(ctx)));
-
-#if defined(DUK_USE_ASSERTIONS)
- /* Easy to get wrong, so assert for it. */
- DUK_ASSERT(entry_top == duk_get_top(ctx));
-#endif
-
- return retval;
-}
-
-/*
- * Halt execution helper
- */
-
-/* Halt execution and enter a debugger message loop until execution is resumed
- * by the client. PC for the current activation may be temporarily decremented
- * so that the "current" instruction will be shown by the client. This helper
- * is callable from anywhere, also outside bytecode executor.
- */
-
-DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) {
- duk_activation *act;
- duk_hcompiledfunction *fun;
- duk_instr_t *old_pc = NULL;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
- DUK_ASSERT(thr->heap->dbg_processing == 0);
-
- DUK_HEAP_SET_PAUSED(thr->heap);
-
- act = duk_hthread_get_current_activation(thr);
-
- /* NOTE: act may be NULL if an error is thrown outside of any activation,
- * which may happen in the case of, e.g. syntax errors.
- */
-
- /* Decrement PC if that was requested, this requires a PC sync. */
- if (act != NULL) {
- duk_hthread_sync_currpc(thr);
- old_pc = act->curr_pc;
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
-
- /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is
- * guaranteed to be a non-NULL Ecmascript function.
- */
- DUK_ASSERT(act->curr_pc == NULL ||
- (fun != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun)));
- if (use_prev_pc &&
- act->curr_pc != NULL &&
- act->curr_pc > DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, fun)) {
- act->curr_pc--;
- }
- }
-
- /* Process debug messages until we are no longer paused. */
-
- /* NOTE: This is a bit fragile. It's important to ensure that
- * duk_debug_process_messages() never throws an error or
- * act->curr_pc will never be reset.
- */
-
- thr->heap->dbg_state_dirty = 1;
- while (thr->heap->dbg_paused) {
- DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
- DUK_ASSERT(thr->heap->dbg_processing);
- duk_debug_process_messages(thr, 0 /*no_block*/);
- }
-
- /* XXX: Decrementing and restoring act->curr_pc works now, but if the
- * debugger message loop gains the ability to adjust the current PC
- * (e.g. a forced jump) restoring the PC here will break. Another
- * approach would be to use a state flag for the "decrement 1 from
- * topmost activation's PC" and take it into account whenever dealing
- * with PC values.
- */
- if (act != NULL) {
- act->curr_pc = old_pc; /* restore PC */
- }
-}
-
-/*
- * Breakpoint management
- */
-
-DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) {
- duk_heap *heap;
- duk_breakpoint *b;
-
- /* Caller must trigger recomputation of active breakpoint list. To
- * ensure stale values are not used if that doesn't happen, clear the
- * active breakpoint list here.
- */
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(filename != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) {
- DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used",
- (duk_heaphdr *) filename, (long) line));
- return -1;
- }
- heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
- b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++);
- b->filename = filename;
- b->line = line;
- DUK_HSTRING_INCREF(thr, filename);
-
- return heap->dbg_breakpoint_count - 1; /* index */
-}
-
-DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
- duk_heap *heap;
- duk_hstring *h;
- duk_breakpoint *b;
- duk_size_t move_size;
-
- /* Caller must trigger recomputation of active breakpoint list. To
- * ensure stale values are not used if that doesn't happen, clear the
- * active breakpoint list here.
- */
-
- DUK_ASSERT(thr != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
- DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */
-
- if (breakpoint_index >= heap->dbg_breakpoint_count) {
- DUK_D(DUK_DPRINT("invalid breakpoint index: %ld", (long) breakpoint_index));
- return 0;
- }
- b = heap->dbg_breakpoints + breakpoint_index;
-
- h = b->filename;
- DUK_ASSERT(h != NULL);
-
- move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
- if (move_size > 0) {
- DUK_MEMMOVE((void *) b,
- (const void *) (b + 1),
- (size_t) move_size);
- }
- heap->dbg_breakpoint_count--;
- heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
-
- DUK_HSTRING_DECREF(thr, h); /* side effects */
- DUK_UNREF(h); /* w/o refcounting */
-
- /* Breakpoint entries above the used area are left as garbage. */
-
- return 1;
-}
-
-#undef DUK__SET_CONN_BROKEN
-
-#else /* DUK_USE_DEBUGGER_SUPPORT */
-
-/* No debugger support. */
-
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-#line 1 "duk_error_augment.c"
-/*
- * Augmenting errors at their creation site and their throw site.
- *
- * When errors are created, traceback data is added by built-in code
- * and a user error handler (if defined) can process or replace the
- * error. Similarly, when errors are thrown, a user error handler
- * (if defined) can process or replace the error.
- *
- * Augmentation and other processing at error creation time is nice
- * because an error is only created once, but it may be thrown and
- * rethrown multiple times. User error handler registered for processing
- * an error at its throw site must be careful to handle rethrowing in
- * a useful manner.
- *
- * Error augmentation may throw an internal error (e.g. alloc error).
- *
- * Ecmascript allows throwing any values, so all values cannot be
- * augmented. Currently, the built-in augmentation at error creation
- * only augments error values which are Error instances (= have the
- * built-in Error.prototype in their prototype chain) and are also
- * extensible. User error handlers have no limitations in this respect.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Helper for calling a user error handler.
- *
- * 'thr' must be the currently active thread; the error handler is called
- * in its context. The valstack of 'thr' must have the error value on
- * top, and will be replaced by another error value based on the return
- * value of the error handler.
- *
- * The helper calls duk_handle_call() recursively in protected mode.
- * Before that call happens, no longjmps should happen; as a consequence,
- * we must assume that the valstack contains enough temporary space for
- * arguments and such.
- *
- * While the error handler runs, any errors thrown will not trigger a
- * recursive error handler call (this is implemented using a heap level
- * flag which will "follow" through any coroutines resumed inside the
- * error handler). If the error handler is not callable or throws an
- * error, the resulting error replaces the original error (for Duktape
- * internal errors, duk_error_throw.c further substitutes this error with
- * a DoubleError which is not ideal). This would be easy to change and
- * even signal to the caller.
- *
- * The user error handler is stored in 'Duktape.errCreate' or
- * 'Duktape.errThrow' depending on whether we're augmenting the error at
- * creation or throw time. There are several alternatives to this approach,
- * see doc/error-objects.rst for discussion.
- *
- * Note: since further longjmp()s may occur while calling the error handler
- * (for many reasons, e.g. a labeled 'break' inside the handler), the
- * caller can make no assumptions on the thr->heap->lj state after the
- * call (this affects especially duk_error_throw.c). This is not an issue
- * as long as the caller writes to the lj state only after the error handler
- * finishes.
- */
-
-#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
-DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_hnd;
- duk_small_uint_t call_flags;
- duk_int_t rc;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT_DISABLE(stridx_cb >= 0); /* unsigned */
- DUK_ASSERT(stridx_cb < DUK_HEAP_NUM_STRINGS);
-
- if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) {
- DUK_DD(DUK_DDPRINT("recursive call to error handler, ignore"));
- return;
- }
-
- /*
- * Check whether or not we have an error handler.
- *
- * We must be careful of not triggering an error when looking up the
- * property. For instance, if the property is a getter, we don't want
- * to call it, only plain values are allowed. The value, if it exists,
- * is not checked. If the value is not a function, a TypeError happens
- * when it is called and that error replaces the original one.
- */
-
- DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */
-
- /* [ ... errval ] */
-
- if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
- /* When creating built-ins, some of the built-ins may not be set
- * and we want to tolerate that when throwing errors.
- */
- DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring"));
- return;
- }
- tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->heap,
- thr->builtins[DUK_BIDX_DUKTAPE],
- DUK_HTHREAD_GET_STRING(thr, stridx_cb));
- if (tv_hnd == NULL) {
- DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T",
- (duk_tval *) tv_hnd));
- return;
- }
- DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
- (duk_tval *) tv_hnd));
- duk_push_tval(ctx, tv_hnd);
-
- /* [ ... errval errhandler ] */
-
- duk_insert(ctx, -2); /* -> [ ... errhandler errval ] */
- duk_push_undefined(ctx);
- duk_insert(ctx, -2); /* -> [ ... errhandler undefined(= this) errval ] */
-
- /* [ ... errhandler undefined errval ] */
-
- /*
- * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C
- * recursion depth limit (and won't increase it either). This is
- * dangerous, but useful because it allows the error handler to run
- * even if the original error is caused by C recursion depth limit.
- *
- * The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the
- * duration of the error handler and cleared afterwards. This flag
- * prevents the error handler from running recursively. The flag is
- * heap level so that the flag properly controls even coroutines
- * launched by an error handler. Since the flag is heap level, it is
- * critical to restore it correctly.
- *
- * We ignore errors now: a success return and an error value both
- * replace the original error value. (This would be easy to change.)
- */
-
- 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_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
-
- 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));
- DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap);
-
- /* [ ... errval ] */
-}
-#endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */
-
-/*
- * Add ._Tracedata to an error on the stack top.
- */
-
-#if defined(DUK_USE_TRACEBACKS)
-DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_t depth;
- duk_int_t i, i_min;
- duk_uarridx_t arr_idx;
- duk_double_t d;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr_callstack != NULL);
- DUK_ASSERT(ctx != NULL);
-
- /* [ ... error ] */
-
- /*
- * The traceback format is pretty arcane in an attempt to keep it compact
- * and cheap to create. It may change arbitrarily from version to version.
- * It should be decoded/accessed through version specific accessors only.
- *
- * See doc/error-objects.rst.
- */
-
- DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk_push_array(ctx); /* XXX: specify array size, as we know it */
- arr_idx = 0;
-
- /* Compiler SyntaxErrors (and other errors) come first, and are
- * blamed by default (not flagged "noblame").
- */
- if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
- duk_push_hstring(ctx, thr->compile_ctx->h_filename);
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
-
- duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line); /* (flags<<32) + (line), flags = 0 */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
- }
-
- /* Filename/line from C macros (__FILE__, __LINE__) are added as an
- * entry with a special format: (string, number). The number contains
- * the line and flags.
- */
-
- /* XXX: optimize: allocate an array part to the necessary size (upwards
- * estimate) and fill in the values directly into the array part; finally
- * update 'length'.
- */
-
- /* XXX: using duk_put_prop_index() would cause obscure error cases when Array.prototype
- * has write-protected array index named properties. This was seen as DoubleErrors
- * in e.g. some test262 test cases. Using duk_xdef_prop_index() is better but heavier.
- * The best fix is to fill in the tracedata directly into the array part. There are
- * no side effect concerns if the array part is allocated directly and only INCREFs
- * happen after that.
- */
-
- /* [ ... error arr ] */
-
- if (c_filename) {
- duk_push_string(ctx, c_filename);
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
-
- d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
- (duk_double_t) c_line;
- duk_push_number(ctx, d);
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
- }
-
- /* traceback depth doesn't take into account the filename/line
- * special handling above (intentional)
- */
- depth = DUK_USE_TRACEBACK_DEPTH;
- i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
- DUK_ASSERT(i_min >= 0);
-
- /* [ ... error arr ] */
-
- DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
- for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
- duk_uint32_t pc;
-
- /*
- * Note: each API operation potentially resizes the callstack,
- * so be careful to re-lookup after every operation. Currently
- * these is no issue because we don't store a temporary 'act'
- * pointer at all. (This would be a non-issue if we operated
- * directly on the array part.)
- */
-
- /* [... arr] */
-
- DUK_ASSERT_DISABLE(thr_callstack->callstack[i].pc >= 0); /* unsigned */
-
- /* Add function object. */
- duk_push_tval(ctx, &(thr_callstack->callstack + i)->tv_func);
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
-
- /* Add a number containing: pc, activation flags.
- *
- * PC points to next instruction, find offending PC. Note that
- * PC == 0 for native code.
- */
- pc = duk_hthread_get_act_prev_pc(thr_callstack, thr_callstack->callstack + i);
- DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
- DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
- d = ((duk_double_t) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
- duk_push_number(ctx, d); /* -> [... arr num] */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx);
- arr_idx++;
- }
-
- /* XXX: set with duk_hobject_set_length() when tracedata is filled directly */
- duk_push_uint(ctx, (duk_uint_t) arr_idx);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
-
- /* [ ... error arr ] */
-
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
-}
-#endif /* DUK_USE_TRACEBACKS */
-
-/*
- * Add .fileName and .lineNumber to an error on the stack top.
- */
-
-#if !defined(DUK_USE_TRACEBACKS)
-DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
- duk_context *ctx;
-#if defined(DUK_USE_ASSERTIONS)
- duk_int_t entry_top;
-#endif
-
- ctx = (duk_context *) thr;
-#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
-#endif
-
- /*
- * If tracebacks are disabled, 'fileName' and 'lineNumber' are added
- * as plain own properties. Since Error.prototype has accessors of
- * the same name, we need to define own properties directly (cannot
- * just use e.g. duk_put_prop_stridx). Existing properties are not
- * overwritten in case they already exist.
- */
-
- if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
- /* Compiler SyntaxError (or other error) gets the primary blame.
- * Currently no flag to prevent blaming.
- */
- duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
- duk_push_hstring(ctx, thr->compile_ctx->h_filename);
- } else if (c_filename && !noblame_fileline) {
- /* C call site gets blamed next, unless flagged not to do so.
- * XXX: file/line is disabled in minimal builds, so disable this
- * too when appropriate.
- */
- duk_push_int(ctx, c_line);
- duk_push_string(ctx, c_filename);
- } else {
- /* Finally, blame the innermost callstack entry which has a
- * .fileName property.
- */
- duk_small_uint_t depth;
- duk_int_t i, i_min;
- duk_uint32_t ecma_line;
-
- depth = DUK_USE_TRACEBACK_DEPTH;
- i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
- DUK_ASSERT(i_min >= 0);
-
- DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
- for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
- duk_activation *act;
- duk_hobject *func;
- duk_uint32_t pc;
-
- DUK_UNREF(pc);
- act = thr_callstack->callstack + i;
- DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
-
- func = DUK_ACT_GET_FUNC(act);
- if (func == NULL) {
- /* Lightfunc, not blamed now. */
- continue;
- }
-
- /* PC points to next instruction, find offending PC,
- * PC == 0 for native code.
- */
- pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
- DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
- DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
- act = NULL; /* invalidated by pushes, so get out of the way */
-
- duk_push_hobject(ctx, func);
-
- /* [ ... error func ] */
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_FILE_NAME);
- if (!duk_is_string(ctx, -1)) {
- duk_pop_2(ctx);
- continue;
- }
-
- /* [ ... error func fileName ] */
-
- ecma_line = 0;
-#if defined(DUK_USE_PC2LINE)
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc);
- } else {
- /* Native function, no relevant lineNumber. */
- }
-#endif /* DUK_USE_PC2LINE */
- duk_push_u32(ctx, ecma_line);
-
- /* [ ... error func fileName lineNumber ] */
-
- duk_replace(ctx, -3);
-
- /* [ ... error lineNumber fileName ] */
- goto define_props;
- }
-
- /* No activation matches, use undefined for both .fileName and
- * .lineNumber (matches what we do with a _Tracedata based
- * no-match lookup.
- */
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
- }
-
- define_props:
- /* [ ... error lineNumber fileName ] */
-#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(duk_get_top(ctx) == entry_top + 2);
-#endif
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_WC | DUK_PROPDESC_FLAG_NO_OVERWRITE);
-}
-#endif /* !DUK_USE_TRACEBACKS */
-
-/*
- * Add line number to a compiler error.
- */
-
-DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
- duk_context *ctx;
-
- /* Append a "(line NNN)" to the "message" property of any error
- * thrown during compilation. Usually compilation errors are
- * SyntaxErrors but they can also be out-of-memory errors and
- * the like.
- */
-
- /* [ ... error ] */
-
- ctx = (duk_context *) thr;
- DUK_ASSERT(duk_is_object(ctx, -1));
-
- if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
- return;
- }
-
- DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_MESSAGE)) {
- duk_push_sprintf(ctx, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
- duk_concat(ctx, 2);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_MESSAGE);
- } else {
- duk_pop(ctx);
- }
-
- DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
-}
-
-/*
- * Augment an error being created using Duktape specific properties
- * like _Tracedata or .fileName/.lineNumber.
- */
-
-#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_int_t noblame_fileline, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
-#if defined(DUK_USE_ASSERTIONS)
- duk_int_t entry_top;
-#endif
-
-#if defined(DUK_USE_ASSERTIONS)
- entry_top = duk_get_top(ctx);
-#endif
- DUK_ASSERT(obj != NULL);
-
- DUK_UNREF(obj); /* unreferenced w/o tracebacks */
- DUK_UNREF(ctx); /* unreferenced w/o asserts */
-
- duk__add_compiler_error_line(thr);
-
-#if defined(DUK_USE_TRACEBACKS)
- /* If tracebacks are enabled, the '_Tracedata' property is the only
- * thing we need: 'fileName' and 'lineNumber' are virtual properties
- * which use '_Tracedata'.
- */
- if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) {
- DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
- } else {
- duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline);
- }
-#else
- /* Without tracebacks the concrete .fileName and .lineNumber need
- * to be added directly.
- */
- duk__add_fileline(thr, thr_callstack, c_filename, c_line, noblame_fileline);
-#endif
-
-#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(duk_get_top(ctx) == entry_top);
-#endif
-}
-#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
-
-/*
- * Augment an error at creation time with _Tracedata/fileName/lineNumber
- * and allow a user error handler (if defined) to process/replace the error.
- * The error to be augmented is at the stack top.
- *
- * thr: thread containing the error value
- * thr_callstack: thread which should be used for generating callstack etc.
- * c_filename: C __FILE__ related to the error
- * c_line: C __LINE__ related to the error
- * noblame_fileline: if true, don't fileName/line as error source, otherwise use traceback
- * (needed because user code filename/line are reported but internal ones
- * are not)
- *
- * XXX: rename noblame_fileline to flags field; combine it to some existing
- * field (there are only a few call sites so this may not be worth it).
- */
-
-#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
-DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *obj;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr_callstack != NULL);
- DUK_ASSERT(ctx != NULL);
-
- /* [ ... error ] */
-
- /*
- * Criteria for augmenting:
- *
- * - augmentation enabled in build (naturally)
- * - error value internal prototype chain contains the built-in
- * Error prototype object (i.e. 'val instanceof Error')
- *
- * Additional criteria for built-in augmenting:
- *
- * - error value is an extensible object
- */
-
- obj = duk_get_hobject(ctx, -1);
- if (!obj) {
- DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
- return;
- }
- if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
- /* If the value has a prototype loop, it's critical not to
- * throw here. Instead, assume the value is not to be
- * augmented.
- */
- DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment"));
- return;
- }
- if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
- DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
- duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj);
- } else {
- DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
- }
-
- /* [ ... error ] */
-
-#if defined(DUK_USE_ERRCREATE)
- duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE);
-#endif
-}
-#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
-
-/*
- * Augment an error at throw time; allow a user error handler (if defined)
- * to process/replace the error. The error to be augmented is at the
- * stack top.
- */
-
-#if defined(DUK_USE_AUGMENT_ERROR_THROW)
-DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
-#if defined(DUK_USE_ERRTHROW)
- duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW);
-#endif /* DUK_USE_ERRTHROW */
-}
-#endif /* DUK_USE_AUGMENT_ERROR_THROW */
-#line 1 "duk_error_longjmp.c"
-/*
- * Do a longjmp call, calling the fatal error handler if no
- * catchpoint exists.
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
- DUK_ASSERT(thr != NULL);
-
- DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T",
- (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
- &thr->heap->lj.value1, &thr->heap->lj.value2));
-
-#if !defined(DUK_USE_CPP_EXCEPTIONS)
- /* If we don't have a jmpbuf_ptr, there is little we can do
- * except panic. The caller's expectation is that we never
- * return.
- *
- * With C++ exceptions we now just propagate an uncaught error
- * instead of invoking the fatal error handler. Because there's
- * a dummy jmpbuf for C++ exceptions now, this could be changed.
- */
- if (!thr->heap->lj.jmpbuf_ptr) {
-
- DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
- (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
- &thr->heap->lj.value1, &thr->heap->lj.value2));
-
- duk_fatal((duk_context *) thr, DUK_ERR_UNCAUGHT_ERROR, "uncaught error");
- DUK_UNREACHABLE();
- }
-#endif /* DUK_USE_CPP_EXCEPTIONS */
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- {
- duk_internal_exception exc; /* dummy */
- throw exc;
- }
-#else /* DUK_USE_CPP_EXCEPTIONS */
- DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
-#endif /* DUK_USE_CPP_EXCEPTIONS */
-
- DUK_UNREACHABLE();
-}
-#line 1 "duk_error_misc.c"
-/*
- * Error helpers
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Helper to walk the thread chain and see if there is an active error
- * catcher. Protected calls or finally blocks aren't considered catching.
- */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT) && \
- (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT))
-DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
- /*
- * XXX: As noted above, a protected API call won't be counted as a
- * catcher. This is usually convenient, e.g. in the case of a top-
- * level duk_pcall(), but may not always be desirable. Perhaps add an
- * argument to treat them as catchers?
- */
-
- duk_size_t i;
-
- DUK_ASSERT(thr != NULL);
-
- while (thr != NULL) {
- for (i = 0; i < thr->catchstack_top; i++) {
- duk_catcher *cat = thr->catchstack + i;
- if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
- return 1; /* all we need to know */
- }
- }
- thr = thr->resumer;
- }
- return 0;
-}
-#endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */
-
-/*
- * Get prototype object for an integer error code.
- */
-
-DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) {
- switch (code) {
- case DUK_ERR_EVAL_ERROR:
- return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE];
- case DUK_ERR_RANGE_ERROR:
- return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE];
- case DUK_ERR_REFERENCE_ERROR:
- return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE];
- case DUK_ERR_SYNTAX_ERROR:
- return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE];
- case DUK_ERR_TYPE_ERROR:
- return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
- case DUK_ERR_URI_ERROR:
- return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
-
- /* XXX: more specific error classes? */
- case DUK_ERR_UNIMPLEMENTED_ERROR:
- case DUK_ERR_INTERNAL_ERROR:
- case DUK_ERR_ALLOC_ERROR:
- case DUK_ERR_ASSERTION_ERROR:
- case DUK_ERR_API_ERROR:
- case DUK_ERR_ERROR:
- default:
- return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
- }
-}
-
-/*
- * Exposed helper for setting up heap longjmp state.
- */
-
-DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) {
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- /* If something is thrown with the debugger attached and nobody will
- * catch it, execution is paused before the longjmp, turning over
- * control to the debug client. This allows local state to be examined
- * before the stack is unwound. Errors are not intercepted when debug
- * message loop is active (e.g. for Eval).
- */
-
- /* XXX: Allow customizing the pause and notify behavior at runtime
- * using debugger runtime flags. For now the behavior is fixed using
- * config options.
- */
-#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) &&
- !thr->heap->dbg_processing &&
- lj_type == DUK_LJ_TYPE_THROW) {
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t fatal;
- duk_hobject *h_obj;
-
- /* Don't intercept a DoubleError, we may have caused the initial double
- * fault and attempting to intercept it will cause us to be called
- * recursively and exhaust the C stack.
- */
- h_obj = duk_get_hobject(ctx, -1);
- if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
- DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting"));
- goto skip_throw_intercept;
- }
-
- DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
-
- fatal = !duk__have_active_catcher(thr);
-
-#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
- /* Report it to the debug client */
- duk_debug_send_throw(thr, fatal);
-#endif
-
-#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
- if (fatal) {
- DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp"));
- duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
- }
-#endif
- }
-
- skip_throw_intercept:
-#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
- thr->heap->lj.type = lj_type;
-
- DUK_ASSERT(thr->valstack_top > thr->valstack);
- DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */
-
- duk_pop((duk_context *) thr);
-}
-#line 1 "duk_error_throw.c"
-/*
- * Create and throw an Ecmascript error object based on a code and a message.
- *
- * Used when we throw errors internally. Ecmascript generated error objects
- * are created by Ecmascript code, and the throwing is handled by the bytecode
- * executor.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Create and throw an error (originating from Duktape internally)
- *
- * Push an error object on top of the stack, possibly throw augmenting
- * the error, and finally longjmp.
- *
- * If an error occurs while we're dealing with the current error, we might
- * enter an infinite recursion loop. This is prevented by detecting a
- * "double fault" through the heap->handling_error flag; the recursion
- * then stops at the second level.
- */
-
-#ifdef DUK_USE_VERBOSE_ERRORS
-DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) {
-#else
-DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
-#endif
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t double_error = thr->heap->handling_error;
-
-#ifdef DUK_USE_VERBOSE_ERRORS
- DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
- (long) code, (const char *) msg,
- (const char *) filename, (long) line));
-#else
- DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code));
-#endif
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
-
- thr->heap->handling_error = 1;
-
- if (!double_error) {
- /* Allow headroom for calls during error handling (see GH-191).
- * We allow space for 10 additional recursions, with one extra
- * for, e.g. a print() call at the deepest level.
- */
- DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX);
- thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11;
- }
-
- DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */
-
- /* Sync so that augmentation sees up-to-date activations, NULL
- * thr->ptr_curr_pc so that it's not used if side effects occur
- * in augmentation or longjmp handling.
- */
- duk_hthread_sync_and_null_currpc(thr);
-
- /*
- * Create and push an error object onto the top of stack.
- * If a "double error" occurs, use a fixed error instance
- * to avoid further trouble.
- */
-
- /* XXX: if attempt to push beyond allocated valstack, this double fault
- * handling fails miserably. We should really write the double error
- * directly to thr->heap->lj.value1 and avoid valstack use entirely.
- */
-
- if (double_error) {
- if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
- DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance"));
- duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR);
- } else {
- DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
- "-> push the error code as a number"));
- duk_push_int(ctx, (duk_int_t) code);
- }
- } else {
- /* Error object is augmented at its creation here. */
- duk_require_stack(ctx, 1);
- /* XXX: unnecessary '%s' formatting here, but cannot use
- * 'msg' as a format string directly.
- */
-#ifdef DUK_USE_VERBOSE_ERRORS
- duk_push_error_object_raw(ctx,
- code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
- filename,
- line,
- "%s",
- (const char *) msg);
-#else
- duk_push_error_object_raw(ctx,
- code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
- NULL,
- 0,
- NULL);
-#endif
- }
-
- /*
- * Augment error (throw time), unless alloc/double error
- */
-
- if (double_error || code == DUK_ERR_ALLOC_ERROR) {
- DUK_D(DUK_DPRINT("alloc or double error: skip throw augmenting to avoid further trouble"));
- } else {
-#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_err_augment_error_throw(thr);
-#endif
- }
-
- /*
- * Finally, longjmp
- */
-
- duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
-
- thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */
- thr->heap->handling_error = 0;
-
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
- (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2));
-
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
-}
-
-/*
- * Helper for C function call negative return values.
- */
-
-DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
- duk_context *ctx = (duk_context *) thr;
- const char *msg;
- duk_errcode_t code;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(rc < 0);
-
- /* XXX: this generates quite large code - perhaps select the error
- * class based on the code and then just use the error 'name'?
- */
- /* XXX: shared strings */
-
- code = -rc;
-
- switch (rc) {
- case DUK_RET_UNIMPLEMENTED_ERROR: msg = "unimplemented"; break;
- case DUK_RET_UNSUPPORTED_ERROR: msg = "unsupported"; break;
- case DUK_RET_INTERNAL_ERROR: msg = "internal"; break;
- case DUK_RET_ALLOC_ERROR: msg = "alloc"; break;
- case DUK_RET_ASSERTION_ERROR: msg = "assertion"; break;
- case DUK_RET_API_ERROR: msg = "api"; break;
- case DUK_RET_UNCAUGHT_ERROR: msg = "uncaught"; break;
- case DUK_RET_ERROR: msg = "error"; break;
- case DUK_RET_EVAL_ERROR: msg = "eval"; break;
- case DUK_RET_RANGE_ERROR: msg = "range"; break;
- case DUK_RET_REFERENCE_ERROR: msg = "reference"; break;
- case DUK_RET_SYNTAX_ERROR: msg = "syntax"; break;
- case DUK_RET_TYPE_ERROR: msg = "type"; break;
- case DUK_RET_URI_ERROR: msg = "uri"; break;
- default: msg = "unknown"; break;
- }
-
- DUK_ASSERT(msg != NULL);
-
- /*
- * The __FILE__ and __LINE__ information is intentionally not used in the
- * creation of the error object, as it isn't useful in the tracedata. The
- * tracedata still contains the function which returned the negative return
- * code, and having the file/line of this function isn't very useful.
- */
-
- duk_error_raw(ctx, code, NULL, 0, "%s error (rc %ld)", (const char *) msg, (long) rc);
- DUK_UNREACHABLE();
-}
-#line 1 "duk_hbuffer_alloc.c"
-/*
- * duk_hbuffer allocation and freeing.
- */
-
-/* include removed: duk_internal.h */
-
-/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
- * (NULL on error). Write buffer data pointer to 'out_bufdata' (only if
- * allocation successful).
- */
-DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
- duk_hbuffer *res = NULL;
- duk_size_t header_size;
- duk_size_t alloc_size;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(out_bufdata != NULL);
-
- DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));
-
- /* Size sanity check. Should not be necessary because caller is
- * required to check this, but we don't want to cause a segfault
- * if the size wraps either in duk_size_t computation or when
- * storing the size in a 16-bit field.
- */
- if (size > DUK_HBUFFER_MAX_BYTELEN) {
- DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
- return NULL; /* no need to write 'out_bufdata' */
- }
-
- if (flags & DUK_BUF_FLAG_EXTERNAL) {
- header_size = sizeof(duk_hbuffer_external);
- alloc_size = sizeof(duk_hbuffer_external);
- } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
- header_size = sizeof(duk_hbuffer_dynamic);
- alloc_size = sizeof(duk_hbuffer_dynamic);
- } else {
- header_size = sizeof(duk_hbuffer_fixed);
- alloc_size = sizeof(duk_hbuffer_fixed) + size;
- DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */
- }
-
- res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
- if (!res) {
- goto error;
- }
-
- /* zero everything unless requested not to do so */
-#if defined(DUK_USE_ZERO_BUFFER_DATA)
- DUK_MEMZERO((void *) res,
- (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
-#else
- DUK_MEMZERO((void *) res, header_size);
-#endif
-
- if (flags & DUK_BUF_FLAG_EXTERNAL) {
- duk_hbuffer_external *h;
- h = (duk_hbuffer_external *) res;
- DUK_UNREF(h);
- *out_bufdata = NULL;
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
-#if defined(DUK_USE_HEAPPTR16)
-/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
-#else
- DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
-#endif
-#endif
- DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
- } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
- duk_hbuffer_dynamic *h = (duk_hbuffer_dynamic *) res;
- void *ptr;
-
- if (size > 0) {
- DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */
- DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
-#ifdef DUK_USE_ZERO_BUFFER_DATA
- ptr = DUK_ALLOC_ZEROED(heap, size);
-#else
- ptr = DUK_ALLOC(heap, size);
-#endif
- if (!ptr) {
- /* Because size > 0, NULL check is correct */
- goto error;
- }
- *out_bufdata = ptr;
-
- DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
- } else {
- *out_bufdata = NULL;
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
-#if defined(DUK_USE_HEAPPTR16)
-/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
-#else
- DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
-#endif
-#endif
- DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
- }
- } else {
- *out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1);
- }
-
- DUK_HBUFFER_SET_SIZE(res, size);
-
- DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
- if (flags & DUK_BUF_FLAG_DYNAMIC) {
- DUK_HBUFFER_SET_DYNAMIC(res);
- if (flags & DUK_BUF_FLAG_EXTERNAL) {
- DUK_HBUFFER_SET_EXTERNAL(res);
- }
- } else {
- DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
- }
- DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
-
- DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
- return res;
-
- error:
- DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
-
- DUK_FREE(heap, res);
- return NULL; /* no need to write 'out_bufdata' */
-}
-
-/* For indirect allocs. */
-
-DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
- duk_hbuffer_dynamic *buf = (duk_hbuffer_dynamic *) ud;
- DUK_UNREF(heap);
- return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
-}
-#line 1 "duk_hbuffer_ops.c"
-/*
- * duk_hbuffer operations such as resizing and inserting/appending data to
- * a dynamic buffer.
- *
- * Append operations append to the end of the buffer and they are relatively
- * efficient: the buffer is grown with a "spare" part relative to the buffer
- * size to minimize reallocations. Insert operations need to move existing
- * data forward in the buffer with memmove() and are not very efficient.
- * They are used e.g. by the regexp compiler to "backpatch" regexp bytecode.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Resizing
- */
-
-DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) {
- void *res;
- duk_size_t prev_size;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(buf != NULL);
- DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
- DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
-
- /*
- * Maximum size check
- */
-
- if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
- DUK_ERROR_RANGE(thr, "buffer too long");
- }
-
- /*
- * Note: use indirect realloc variant just in case mark-and-sweep
- * (finalizers) might resize this same buffer during garbage
- * collection.
- */
-
- res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size);
- if (res != NULL || new_size == 0) {
- /* 'res' may be NULL if new allocation size is 0. */
-
- DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld",
- (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf),
- (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf),
- (void *) res,
- (long) new_size));
-
- /*
- * The entire allocated buffer area, regardless of actual used
- * size, is kept zeroed in resizes for simplicity. If the buffer
- * is grown, zero the new part.
- */
-
- prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf);
- if (new_size > prev_size) {
- DUK_ASSERT(new_size - prev_size > 0);
-#ifdef DUK_USE_ZERO_BUFFER_DATA
- DUK_MEMZERO((void *) ((char *) res + prev_size),
- (duk_size_t) (new_size - prev_size));
-#endif
- }
-
- DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size);
- DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
- } else {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
-
- DUK_ASSERT(res != NULL || new_size == 0);
-}
-
-DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(buf != NULL);
- DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
- DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
-
- duk_hbuffer_resize(thr, buf, 0);
-}
-/* include removed: duk_internal.h */
-#line 2 "duk_hbufferobject_misc.c"
-
-#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
-DUK_INTERNAL duk_uint_t duk_hbufferobject_clamp_bytelength(duk_hbufferobject *h_bufobj, duk_uint_t len) {
- duk_uint_t buf_size;
- duk_uint_t buf_avail;
-
- DUK_ASSERT(h_bufobj != NULL);
- DUK_ASSERT(h_bufobj->buf != NULL);
-
- buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf);
- if (h_bufobj->offset > buf_size) {
- /* Slice starting point is beyond current length. */
- return 0;
- }
- buf_avail = buf_size - h_bufobj->offset;
-
- return buf_avail >= len ? len : buf_avail;
-}
-#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
-#line 1 "duk_heap_alloc.c"
-/*
- * duk_heap allocation and freeing.
- */
-
-/* include removed: duk_internal.h */
-
-/* Constants for built-in string data depacking. */
-#define DUK__BITPACK_LETTER_LIMIT 26
-#define DUK__BITPACK_UNDERSCORE 26
-#define DUK__BITPACK_FF 27
-#define DUK__BITPACK_SWITCH1 29
-#define DUK__BITPACK_SWITCH 30
-#define DUK__BITPACK_SEVENBIT 31
-
-#if defined(DUK_USE_ROM_STRINGS)
-/* Fixed seed value used with ROM strings. */
-#define DUK__FIXED_HASH_SEED 0xabcd1234
-#endif
-
-/*
- * Free a heap object.
- *
- * Free heap object and its internal (non-heap) pointers. Assumes that
- * caller has removed the object from heap allocated list or the string
- * intern table, and any weak references (which strings may have) have
- * been already dealt with.
- */
-
-DUK_INTERNAL void duk_free_hobject_inner(duk_heap *heap, duk_hobject *h) {
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
-
- DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
-
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
- DUK_UNREF(f);
- /* Currently nothing to free; 'data' is a heap object */
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_hnativefunction *f = (duk_hnativefunction *) h;
- DUK_UNREF(f);
- /* Currently nothing to free */
- } else if (DUK_HOBJECT_IS_THREAD(h)) {
- duk_hthread *t = (duk_hthread *) h;
- DUK_FREE(heap, t->valstack);
- DUK_FREE(heap, t->callstack);
- DUK_FREE(heap, t->catchstack);
- /* Don't free h->resumer because it exists in the heap.
- * Callstack entries also contain function pointers which
- * are not freed for the same reason.
- */
-
- /* XXX: with 'caller' property the callstack would need
- * to be unwound to update the 'caller' properties of
- * functions in the callstack.
- */
- }
-}
-
-DUK_INTERNAL void duk_free_hbuffer_inner(duk_heap *heap, duk_hbuffer *h) {
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
-
- if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) {
- duk_hbuffer_dynamic *g = (duk_hbuffer_dynamic *) h;
- DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
- DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g));
- }
-}
-
-DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h) {
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
-
- DUK_UNREF(heap);
- DUK_UNREF(h);
-
-#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
- if (DUK_HSTRING_HAS_EXTDATA(h)) {
- DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
- h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)));
- DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
- }
-#endif
-}
-
-DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
- DUK_ASSERT(heap);
- DUK_ASSERT(hdr);
-
- DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
-
- switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
- case DUK_HTYPE_STRING:
- duk_free_hstring_inner(heap, (duk_hstring *) hdr);
- break;
- case DUK_HTYPE_OBJECT:
- duk_free_hobject_inner(heap, (duk_hobject *) hdr);
- break;
- case DUK_HTYPE_BUFFER:
- duk_free_hbuffer_inner(heap, (duk_hbuffer *) hdr);
- break;
- default:
- DUK_UNREACHABLE();
- }
-
- DUK_FREE(heap, hdr);
-}
-
-/*
- * Free the heap.
- *
- * Frees heap-related non-heap-tracked allocations such as the
- * string intern table; then frees the heap allocated objects;
- * and finally frees the heap structure itself. Reference counts
- * and GC markers are ignored (and not updated) in this process,
- * and finalizers won't be called.
- *
- * The heap pointer and heap object pointers must not be used
- * after this call.
- */
-
-DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
- duk_heaphdr *curr;
- duk_heaphdr *next;
-
- curr = heap->heap_allocated;
- while (curr) {
- /* We don't log or warn about freeing zero refcount objects
- * because they may happen with finalizer processing.
- */
-
- DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
- (duk_heaphdr *) curr));
- next = DUK_HEAPHDR_GET_NEXT(heap, curr);
- duk_heap_free_heaphdr_raw(heap, curr);
- curr = next;
- }
-}
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
-DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) {
- duk_heaphdr *curr;
- duk_heaphdr *next;
-
- curr = heap->refzero_list;
- while (curr) {
- DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO",
- (duk_heaphdr *) curr));
- next = DUK_HEAPHDR_GET_NEXT(heap, curr);
- duk_heap_free_heaphdr_raw(heap, curr);
- curr = next;
- }
-}
-#endif
-
-#if defined(DUK_USE_MARK_AND_SWEEP)
-DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) {
- duk_heaphdr *curr;
- duk_heaphdr *next;
-
- curr = heap->finalize_list;
- while (curr) {
- DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
- (duk_heaphdr *) curr));
- next = DUK_HEAPHDR_GET_NEXT(heap, curr);
- duk_heap_free_heaphdr_raw(heap, curr);
- curr = next;
- }
-}
-#endif
-
-DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
- /* strings are only tracked by stringtable */
- duk_heap_free_strtab(heap);
-}
-
-DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
- duk_hthread *thr;
- duk_heaphdr *curr;
- duk_uint_t round_no;
- duk_size_t count_all;
- duk_size_t count_finalized;
- duk_size_t curr_limit;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(heap->heap_thread != NULL);
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
-#endif
-#if defined(DUK_USE_MARK_AND_SWEEP)
- DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */
-#endif
-
- /* XXX: here again finalizer thread is the heap_thread which needs
- * to be coordinated with finalizer thread fixes.
- */
- thr = heap->heap_thread;
- DUK_ASSERT(thr != NULL);
-
- /* Prevent mark-and-sweep for the pending finalizers, also prevents
- * refzero handling from moving objects away from the heap_allocated
- * list. (The flag meaning is slightly abused here.)
- */
- DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
- DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
-
- curr_limit = 0; /* suppress warning, not used */
- for (round_no = 0; ; round_no++) {
- curr = heap->heap_allocated;
- count_all = 0;
- count_finalized = 0;
- while (curr) {
- count_all++;
- if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
- /* Only objects in heap_allocated may have finalizers. Check that
- * the object itself has a _Finalizer property (own or inherited)
- * so that we don't execute finalizers for e.g. Proxy objects.
- */
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(curr != NULL);
-
- if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
- if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
- DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */
- duk_hobject_run_finalizer(thr, (duk_hobject *) curr);
- count_finalized++;
- }
- }
- }
- curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
- }
-
- /* Each round of finalizer execution may spawn new finalizable objects
- * which is normal behavior for some applications. Allow multiple
- * rounds of finalization, but use a shrinking limit based on the
- * first round to detect the case where a runaway finalizer creates
- * an unbounded amount of new finalizable objects. Finalizer rescue
- * is not supported: the semantics are unclear because most of the
- * objects being finalized here are already reachable. The finalizer
- * is given a boolean to indicate that rescue is not possible.
- *
- * See discussion in: https://github.com/svaarala/duktape/pull/473
- */
-
- if (round_no == 0) {
- /* Cannot wrap: each object is at least 8 bytes so count is
- * at most 1/8 of that.
- */
- curr_limit = count_all * 2;
- } else {
- curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */
- }
- DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld",
- (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit));
-
- if (count_finalized == 0) {
- DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished"));
- break;
- }
- if (count_finalized >= curr_limit) {
- DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers"));
- break;
- }
- }
-
- DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
- DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
-}
-
-DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
- DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
-
-#if defined(DUK_USE_DEBUG)
- duk_heap_dump_strtab(heap);
-#endif
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- /* Detach a debugger if attached (can be called multiple times)
- * safely.
- */
- /* XXX: Add a flag to reject an attempt to re-attach? Otherwise
- * the detached callback may immediately reattach.
- */
- duk_debug_do_detach(heap);
-#endif
-
- /* Execute finalizers before freeing the heap, even for reachable
- * objects, and regardless of whether or not mark-and-sweep is
- * enabled. This gives finalizers the chance to free any native
- * resources like file handles, allocations made outside Duktape,
- * etc. This is quite tricky to get right, so that all finalizer
- * guarantees are honored.
- *
- * XXX: this perhaps requires an execution time limit.
- */
- DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
-#if defined(DUK_USE_MARK_AND_SWEEP)
- /* Run mark-and-sweep a few times just in case (unreachable object
- * finalizers run already here). The last round must rescue objects
- * from the previous round without running any more finalizers. This
- * ensures rescued objects get their FINALIZED flag cleared so that
- * their finalizer is called once more in forced finalization to
- * satisfy finalizer guarantees. However, we don't want to run any
- * more finalizer because that'd required one more loop, and so on.
- */
- DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
- duk_heap_mark_and_sweep(heap, 0);
- DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
- duk_heap_mark_and_sweep(heap, 0);
- DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
- duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */
-#endif
-
- DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */
- duk__free_run_finalizers(heap);
-
- /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
- * are on the heap allocated list.
- */
-
- DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap));
- duk__free_allocated(heap);
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap));
- duk__free_refzero_list(heap);
-#endif
-
-#if defined(DUK_USE_MARK_AND_SWEEP)
- DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap));
- duk__free_markandsweep_finalize_list(heap);
-#endif
-
- DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
- duk__free_stringtable(heap);
-
- DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap));
- heap->free_func(heap->heap_udata, heap);
-}
-
-/*
- * Allocate a heap.
- *
- * String table is initialized with built-in strings from genbuiltins.py,
- * either by dynamically creating the strings or by referring to ROM strings.
- */
-
-#if defined(DUK_USE_ROM_STRINGS)
-DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
-#if defined(DUK_USE_ASSERTIONS)
- duk_small_uint_t i;
-#endif
-
- /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted
- * so nothing to initialize for strs[].
- */
-
-#if defined(DUK_USE_ASSERTIONS)
- for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) {
- duk_uint32_t hash;
- const duk_hstring *h;
- h = duk_rom_strings[i];
- DUK_ASSERT(h != NULL);
- hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
- DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx",
- (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
- DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
- }
-#endif
- return 1;
-}
-#else /* DUK_USE_ROM_STRINGS */
-DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
- duk_bitdecoder_ctx bd_ctx;
- duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
- duk_small_uint_t i, j;
-
- DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
- bd->data = (const duk_uint8_t *) duk_strings_data;
- bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
-
- for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
- duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
- duk_hstring *h;
- duk_small_uint_t len;
- duk_small_uint_t mode;
- duk_small_uint_t t;
-
- len = duk_bd_decode(bd, 5);
- mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
- for (j = 0; j < len; j++) {
- t = duk_bd_decode(bd, 5);
- if (t < DUK__BITPACK_LETTER_LIMIT) {
- t = t + DUK_ASC_UC_A + mode;
- } else if (t == DUK__BITPACK_UNDERSCORE) {
- t = DUK_ASC_UNDERSCORE;
- } else if (t == DUK__BITPACK_FF) {
- /* Internal keys are prefixed with 0xFF in the stringtable
- * (which makes them invalid UTF-8 on purpose).
- */
- t = 0xff;
- } else if (t == DUK__BITPACK_SWITCH1) {
- t = duk_bd_decode(bd, 5);
- DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
- DUK_ASSERT(t <= 25);
- t = t + DUK_ASC_UC_A + (mode ^ 32);
- } else if (t == DUK__BITPACK_SWITCH) {
- mode = mode ^ 32;
- t = duk_bd_decode(bd, 5);
- DUK_ASSERT_DISABLE(t >= 0);
- DUK_ASSERT(t <= 25);
- t = t + DUK_ASC_UC_A + mode;
- } else if (t == DUK__BITPACK_SEVENBIT) {
- t = duk_bd_decode(bd, 7);
- }
- tmp[j] = (duk_uint8_t) t;
- }
-
- /* No need to length check string: it will never exceed even
- * the 16-bit length maximum.
- */
- DUK_ASSERT(len <= 0xffffUL);
- DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
- h = duk_heap_string_intern(heap, tmp, len);
- if (!h) {
- goto error;
- }
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
-
- /* Special flags checks. Since these strings are always
- * reachable and a string cannot appear twice in the string
- * table, there's no need to check/set these flags elsewhere.
- * The 'internal' flag is set by string intern code.
- */
- if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
- DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
- }
- if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
- DUK_HSTRING_SET_RESERVED_WORD(h);
- if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
- DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
- }
- }
-
- DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));
-
- /* XXX: The incref macro takes a thread pointer but doesn't
- * use it right now.
- */
- DUK_HSTRING_INCREF(_never_referenced_, h);
-
-#if defined(DUK_USE_HEAPPTR16)
- heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-#else
- heap->strs[i] = h;
-#endif
- }
-
- return 1;
-
- error:
- return 0;
-}
-#endif /* DUK_USE_ROM_STRINGS */
-
-DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
- duk_hthread *thr;
-
- DUK_DD(DUK_DDPRINT("heap init: alloc heap thread"));
- thr = duk_hthread_alloc(heap,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_THREAD |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
- if (!thr) {
- DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
- return 0;
- }
- thr->state = DUK_HTHREAD_STATE_INACTIVE;
-#if defined(DUK_USE_ROM_STRINGS)
- /* No strs[] pointer. */
-#else /* DUK_USE_ROM_STRINGS */
-#if defined(DUK_USE_HEAPPTR16)
- thr->strs16 = heap->strs16;
-#else
- thr->strs = heap->strs;
-#endif
-#endif /* DUK_USE_ROM_STRINGS */
-
- heap->heap_thread = thr;
- DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */
-
- /* 'thr' is now reachable */
-
- if (!duk_hthread_init_stacks(heap, thr)) {
- return 0;
- }
-
- /* XXX: this may now fail, and is not handled correctly */
- duk_hthread_create_builtin_objects(thr);
-
- /* default prototype (Note: 'thr' must be reachable) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
-
- return 1;
-}
-
-#if defined(DUK_USE_DEBUG)
-#define DUK__DUMPSZ(t) do { \
- DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
- } while (0)
-
-/* These is not 100% because format would need to be non-portable "long long".
- * Also print out as doubles to catch cases where the "long" type is not wide
- * enough; the limits will then not be printed accurately but the magnitude
- * will be correct.
- */
-#define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \
- DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
- (long) (a), (long) (b), \
- (double) (a), (double) (b))); \
- } while (0)
-#define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
- DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
- (unsigned long) (a), (unsigned long) (b), \
- (double) (a), (double) (b))); \
- } while (0)
-#define DUK__DUMPLM_SIGNED(t) do { \
- DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
- } while (0)
-#define DUK__DUMPLM_UNSIGNED(t) do { \
- DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
- } while (0)
-
-DUK_LOCAL void duk__dump_type_sizes(void) {
- DUK_D(DUK_DPRINT("sizeof()"));
-
- /* basic platform types */
- DUK__DUMPSZ(char);
- DUK__DUMPSZ(short);
- DUK__DUMPSZ(int);
- DUK__DUMPSZ(long);
- DUK__DUMPSZ(double);
- DUK__DUMPSZ(void *);
- DUK__DUMPSZ(size_t);
-
- /* basic types from duk_features.h */
- DUK__DUMPSZ(duk_uint8_t);
- DUK__DUMPSZ(duk_int8_t);
- DUK__DUMPSZ(duk_uint16_t);
- DUK__DUMPSZ(duk_int16_t);
- DUK__DUMPSZ(duk_uint32_t);
- DUK__DUMPSZ(duk_int32_t);
- DUK__DUMPSZ(duk_uint64_t);
- DUK__DUMPSZ(duk_int64_t);
- DUK__DUMPSZ(duk_uint_least8_t);
- DUK__DUMPSZ(duk_int_least8_t);
- DUK__DUMPSZ(duk_uint_least16_t);
- DUK__DUMPSZ(duk_int_least16_t);
- DUK__DUMPSZ(duk_uint_least32_t);
- DUK__DUMPSZ(duk_int_least32_t);
-#if defined(DUK_USE_64BIT_OPS)
- DUK__DUMPSZ(duk_uint_least64_t);
- DUK__DUMPSZ(duk_int_least64_t);
-#endif
- DUK__DUMPSZ(duk_uint_fast8_t);
- DUK__DUMPSZ(duk_int_fast8_t);
- DUK__DUMPSZ(duk_uint_fast16_t);
- DUK__DUMPSZ(duk_int_fast16_t);
- DUK__DUMPSZ(duk_uint_fast32_t);
- DUK__DUMPSZ(duk_int_fast32_t);
-#if defined(DUK_USE_64BIT_OPS)
- DUK__DUMPSZ(duk_uint_fast64_t);
- DUK__DUMPSZ(duk_int_fast64_t);
-#endif
- DUK__DUMPSZ(duk_uintptr_t);
- DUK__DUMPSZ(duk_intptr_t);
- DUK__DUMPSZ(duk_uintmax_t);
- DUK__DUMPSZ(duk_intmax_t);
- DUK__DUMPSZ(duk_double_t);
-
- /* important chosen base types */
- DUK__DUMPSZ(duk_int_t);
- DUK__DUMPSZ(duk_uint_t);
- DUK__DUMPSZ(duk_int_fast_t);
- DUK__DUMPSZ(duk_uint_fast_t);
- DUK__DUMPSZ(duk_small_int_t);
- DUK__DUMPSZ(duk_small_uint_t);
- DUK__DUMPSZ(duk_small_int_fast_t);
- DUK__DUMPSZ(duk_small_uint_fast_t);
-
- /* some derived types */
- DUK__DUMPSZ(duk_codepoint_t);
- DUK__DUMPSZ(duk_ucodepoint_t);
- DUK__DUMPSZ(duk_idx_t);
- DUK__DUMPSZ(duk_errcode_t);
- DUK__DUMPSZ(duk_uarridx_t);
-
- /* tval */
- DUK__DUMPSZ(duk_double_union);
- DUK__DUMPSZ(duk_tval);
-
- /* structs from duk_forwdecl.h */
- DUK__DUMPSZ(duk_jmpbuf); /* just one 'int' for C++ exceptions */
- DUK__DUMPSZ(duk_heaphdr);
- DUK__DUMPSZ(duk_heaphdr_string);
- DUK__DUMPSZ(duk_hstring);
- DUK__DUMPSZ(duk_hstring_external);
- DUK__DUMPSZ(duk_hobject);
- DUK__DUMPSZ(duk_hcompiledfunction);
- DUK__DUMPSZ(duk_hnativefunction);
- DUK__DUMPSZ(duk_hthread);
- DUK__DUMPSZ(duk_hbuffer);
- DUK__DUMPSZ(duk_hbuffer_fixed);
- DUK__DUMPSZ(duk_hbuffer_dynamic);
- DUK__DUMPSZ(duk_hbuffer_external);
- DUK__DUMPSZ(duk_propaccessor);
- DUK__DUMPSZ(duk_propvalue);
- DUK__DUMPSZ(duk_propdesc);
- DUK__DUMPSZ(duk_heap);
-#if defined(DUK_USE_STRTAB_CHAIN)
- DUK__DUMPSZ(duk_strtab_entry);
-#endif
- DUK__DUMPSZ(duk_activation);
- DUK__DUMPSZ(duk_catcher);
- DUK__DUMPSZ(duk_strcache);
- DUK__DUMPSZ(duk_ljstate);
- DUK__DUMPSZ(duk_fixedbuffer);
- DUK__DUMPSZ(duk_bitdecoder_ctx);
- DUK__DUMPSZ(duk_bitencoder_ctx);
- DUK__DUMPSZ(duk_token);
- DUK__DUMPSZ(duk_re_token);
- DUK__DUMPSZ(duk_lexer_point);
- DUK__DUMPSZ(duk_lexer_ctx);
- DUK__DUMPSZ(duk_compiler_instr);
- DUK__DUMPSZ(duk_compiler_func);
- DUK__DUMPSZ(duk_compiler_ctx);
- DUK__DUMPSZ(duk_re_matcher_ctx);
- DUK__DUMPSZ(duk_re_compiler_ctx);
-}
-DUK_LOCAL void duk__dump_type_limits(void) {
- DUK_D(DUK_DPRINT("limits"));
-
- /* basic types */
- DUK__DUMPLM_SIGNED(INT8);
- DUK__DUMPLM_UNSIGNED(UINT8);
- DUK__DUMPLM_SIGNED(INT_FAST8);
- DUK__DUMPLM_UNSIGNED(UINT_FAST8);
- DUK__DUMPLM_SIGNED(INT_LEAST8);
- DUK__DUMPLM_UNSIGNED(UINT_LEAST8);
- DUK__DUMPLM_SIGNED(INT16);
- DUK__DUMPLM_UNSIGNED(UINT16);
- DUK__DUMPLM_SIGNED(INT_FAST16);
- DUK__DUMPLM_UNSIGNED(UINT_FAST16);
- DUK__DUMPLM_SIGNED(INT_LEAST16);
- DUK__DUMPLM_UNSIGNED(UINT_LEAST16);
- DUK__DUMPLM_SIGNED(INT32);
- DUK__DUMPLM_UNSIGNED(UINT32);
- DUK__DUMPLM_SIGNED(INT_FAST32);
- DUK__DUMPLM_UNSIGNED(UINT_FAST32);
- DUK__DUMPLM_SIGNED(INT_LEAST32);
- DUK__DUMPLM_UNSIGNED(UINT_LEAST32);
-#if defined(DUK_USE_64BIT_OPS)
- DUK__DUMPLM_SIGNED(INT64);
- DUK__DUMPLM_UNSIGNED(UINT64);
- DUK__DUMPLM_SIGNED(INT_FAST64);
- DUK__DUMPLM_UNSIGNED(UINT_FAST64);
- DUK__DUMPLM_SIGNED(INT_LEAST64);
- DUK__DUMPLM_UNSIGNED(UINT_LEAST64);
-#endif
- DUK__DUMPLM_SIGNED(INTPTR);
- DUK__DUMPLM_UNSIGNED(UINTPTR);
- DUK__DUMPLM_SIGNED(INTMAX);
- DUK__DUMPLM_UNSIGNED(UINTMAX);
-
- /* derived types */
- DUK__DUMPLM_SIGNED(INT);
- DUK__DUMPLM_UNSIGNED(UINT);
- DUK__DUMPLM_SIGNED(INT_FAST);
- DUK__DUMPLM_UNSIGNED(UINT_FAST);
- DUK__DUMPLM_SIGNED(SMALL_INT);
- DUK__DUMPLM_UNSIGNED(SMALL_UINT);
- DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
- DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
-}
-#undef DUK__DUMPSZ
-#undef DUK__DUMPLM_SIGNED_RAW
-#undef DUK__DUMPLM_UNSIGNED_RAW
-#undef DUK__DUMPLM_SIGNED
-#undef DUK__DUMPLM_UNSIGNED
-
-DUK_LOCAL void duk__dump_misc_options(void) {
- DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
- DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
- DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
- DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
- DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
-#if defined(DUK_USE_PACKED_TVAL)
- DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
-#else
- DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
-#endif
-#if defined(DUK_USE_VARIADIC_MACROS)
- DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes"));
-#else
- DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no"));
-#endif
-#if defined(DUK_USE_INTEGER_LE)
- DUK_D(DUK_DPRINT("integer endianness: little"));
-#elif defined(DUK_USE_INTEGER_ME)
- DUK_D(DUK_DPRINT("integer endianness: mixed"));
-#elif defined(DUK_USE_INTEGER_BE)
- DUK_D(DUK_DPRINT("integer endianness: big"));
-#else
- DUK_D(DUK_DPRINT("integer endianness: ???"));
-#endif
-#if defined(DUK_USE_DOUBLE_LE)
- DUK_D(DUK_DPRINT("IEEE double endianness: little"));
-#elif defined(DUK_USE_DOUBLE_ME)
- DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
-#elif defined(DUK_USE_DOUBLE_BE)
- DUK_D(DUK_DPRINT("IEEE double endianness: big"));
-#else
- DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
-#endif
-}
-#endif /* DUK_USE_DEBUG */
-
-DUK_INTERNAL
-duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
- duk_realloc_function realloc_func,
- duk_free_function free_func,
- void *heap_udata,
- duk_fatal_function fatal_func) {
- duk_heap *res = NULL;
-
- /* Silence a few global unused warnings here. */
- DUK_UNREF(duk_str_unsupported);
-
- DUK_D(DUK_DPRINT("allocate heap"));
-
- /*
- * Debug dump type sizes
- */
-
-#if defined(DUK_USE_DEBUG)
- duk__dump_misc_options();
- duk__dump_type_sizes();
- duk__dump_type_limits();
-#endif
-
- /*
- * If selftests enabled, run them as early as possible
- */
-#if defined(DUK_USE_SELF_TESTS)
- DUK_D(DUK_DPRINT("running self tests"));
- duk_selftest_run_tests();
- DUK_D(DUK_DPRINT("self tests passed"));
-#endif
-
- /*
- * Computed values (e.g. INFINITY)
- */
-
-#if defined(DUK_USE_COMPUTED_NAN)
- do {
- /* Workaround for some exotic platforms where NAN is missing
- * and the expression (0.0 / 0.0) does NOT result in a NaN.
- * Such platforms use the global 'duk_computed_nan' which must
- * be initialized at runtime. Use 'volatile' to ensure that
- * the compiler will actually do the computation and not try
- * to do constant folding which might result in the original
- * problem.
- */
- volatile double dbl1 = 0.0;
- volatile double dbl2 = 0.0;
- duk_computed_nan = dbl1 / dbl2;
- } while (0);
-#endif
-
-#if defined(DUK_USE_COMPUTED_INFINITY)
- do {
- /* Similar workaround for INFINITY. */
- volatile double dbl1 = 1.0;
- volatile double dbl2 = 0.0;
- duk_computed_infinity = dbl1 / dbl2;
- } while (0);
-#endif
-
- /*
- * Allocate heap struct
- *
- * Use a raw call, all macros expect the heap to be initialized
- */
-
- res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
- if (!res) {
- goto error;
- }
-
- /*
- * Zero the struct, and start initializing roughly in order
- */
-
- DUK_MEMZERO(res, sizeof(*res));
-
- /* explicit NULL inits */
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
- res->heap_udata = NULL;
- res->heap_allocated = NULL;
-#if defined(DUK_USE_REFERENCE_COUNTING)
- res->refzero_list = NULL;
- res->refzero_list_tail = NULL;
-#endif
-#if defined(DUK_USE_MARK_AND_SWEEP)
- res->finalize_list = NULL;
-#endif
- res->heap_thread = NULL;
- res->curr_thread = NULL;
- res->heap_object = NULL;
-#if defined(DUK_USE_STRTAB_CHAIN)
- /* nothing to NULL */
-#elif defined(DUK_USE_STRTAB_PROBE)
-#if defined(DUK_USE_HEAPPTR16)
- res->strtable16 = (duk_uint16_t *) NULL;
-#else
- res->strtable = (duk_hstring **) NULL;
-#endif
-#endif
-#if defined(DUK_USE_ROM_STRINGS)
- /* no res->strs[] */
-#else /* DUK_USE_ROM_STRINGS */
-#if defined(DUK_USE_HEAPPTR16)
- /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
-#else
- {
- duk_small_uint_t i;
- for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
- res->strs[i] = NULL;
- }
- }
-#endif
-#endif /* DUK_USE_ROM_STRINGS */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- res->dbg_read_cb = NULL;
- res->dbg_write_cb = NULL;
- res->dbg_peek_cb = NULL;
- res->dbg_read_flush_cb = NULL;
- res->dbg_write_flush_cb = NULL;
- res->dbg_request_cb = NULL;
- res->dbg_udata = NULL;
- res->dbg_step_thread = NULL;
-#endif
-#endif /* DUK_USE_EXPLICIT_NULL_INIT */
-
- res->alloc_func = alloc_func;
- res->realloc_func = realloc_func;
- res->free_func = free_func;
- res->heap_udata = heap_udata;
- res->fatal_func = fatal_func;
-
-#if defined(DUK_USE_HEAPPTR16)
- /* XXX: zero assumption */
- res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL);
- res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res));
-#endif
-
- /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
-
- res->call_recursion_depth = 0;
- res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT;
-
- /* XXX: use the pointer as a seed for now: mix in time at least */
-
- /* The casts through duk_intr_pt is to avoid the following GCC warning:
- *
- * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
- *
- * This still generates a /Wp64 warning on VS2010 when compiling for x86.
- */
-#if defined(DUK_USE_ROM_STRINGS)
- /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */
- DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED));
- res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
-#else /* DUK_USE_ROM_STRINGS */
- res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
- res->rnd_state = (duk_uint32_t) (duk_intptr_t) res;
-#if !defined(DUK_USE_STRHASH_DENSE)
- res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
-#endif
-#endif /* DUK_USE_ROM_STRINGS */
-
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
- res->lj.jmpbuf_ptr = NULL;
-#endif
- DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
-
- DUK_TVAL_SET_UNDEFINED(&res->lj.value1);
- DUK_TVAL_SET_UNDEFINED(&res->lj.value2);
-
-#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
-#error initial heap stringtable size is defined incorrectly
-#endif
-
- /*
- * Init stringtable: fixed variant
- */
-
-#if defined(DUK_USE_STRTAB_CHAIN)
- DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE);
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
- {
- duk_small_uint_t i;
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- res->strtable[i].u.str16 = res->heapptr_null16;
-#else
- res->strtable[i].u.str = NULL;
-#endif
- }
- }
-#endif /* DUK_USE_EXPLICIT_NULL_INIT */
-#endif /* DUK_USE_STRTAB_CHAIN */
-
- /*
- * Init stringtable: probe variant
- */
-
-#if defined(DUK_USE_STRTAB_PROBE)
-#if defined(DUK_USE_HEAPPTR16)
- res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
- if (!res->strtable16) {
- goto error;
- }
-#else /* DUK_USE_HEAPPTR16 */
- res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
- if (!res->strtable) {
- goto error;
- }
-#endif /* DUK_USE_HEAPPTR16 */
- res->st_size = DUK_STRTAB_INITIAL_SIZE;
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
- {
- duk_small_uint_t i;
- DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE);
- for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- res->strtable16[i] = res->heapptr_null16;
-#else
- res->strtable[i] = NULL;
-#endif
- }
- }
-#else /* DUK_USE_EXPLICIT_NULL_INIT */
-#if defined(DUK_USE_HEAPPTR16)
- DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
-#else
- DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
-#endif
-#endif /* DUK_USE_EXPLICIT_NULL_INIT */
-#endif /* DUK_USE_STRTAB_PROBE */
-
- /*
- * Init stringcache
- */
-
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
- {
- duk_small_uint_t i;
- for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- res->strcache[i].h = NULL;
- }
- }
-#endif
-
- /* XXX: error handling is incomplete. It would be cleanest if
- * there was a setjmp catchpoint, so that all init code could
- * freely throw errors. If that were the case, the return code
- * passing here could be removed.
- */
-
- /*
- * Init built-in strings
- */
-
- DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS"));
- if (!duk__init_heap_strings(res)) {
- goto error;
- }
-
- /*
- * Init the heap thread
- */
-
- DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD"));
- if (!duk__init_heap_thread(res)) {
- goto error;
- }
-
- /*
- * Init the heap object
- */
-
- DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT"));
- DUK_ASSERT(res->heap_thread != NULL);
- res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
- if (!res->heap_object) {
- goto error;
- }
- DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
-
- /*
- * All done
- */
-
- DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
- return res;
-
- error:
- DUK_D(DUK_DPRINT("heap allocation failed"));
-
- if (res) {
- /* assumes that allocated pointers and alloc funcs are valid
- * if res exists
- */
- DUK_ASSERT(res->alloc_func != NULL);
- DUK_ASSERT(res->realloc_func != NULL);
- DUK_ASSERT(res->free_func != NULL);
- duk_heap_free(res);
- }
- return NULL;
-}
-
-#undef DUK__BITPACK_LETTER_LIMIT
-#undef DUK__BITPACK_UNDERSCORE
-#undef DUK__BITPACK_FF
-#undef DUK__BITPACK_SWITCH1
-#undef DUK__BITPACK_SWITCH
-#undef DUK__BITPACK_SEVENBIT
-#undef DUK__FIXED_HASH_SEED
-#line 1 "duk_heap_hashstring.c"
-/*
- * String hash computation (interning).
- *
- * String hashing is performance critical because a string hash is computed
- * for all new strings which are candidates to be added to the string table.
- * However, strings actually added to the string table go through a codepoint
- * length calculation which dominates performance because it goes through
- * every byte of the input string (but only for strings added).
- *
- * The string hash algorithm should be fast, but on the other hand provide
- * good enough hashes to ensure both string table and object property table
- * hash tables work reasonably well (i.e., there aren't too many collisions
- * with real world inputs). Unless the hash is cryptographic, it's always
- * possible to craft inputs with maximal hash collisions.
- *
- * NOTE: The hash algorithms must match src/dukutil.py:duk_heap_hashstring()
- * for ROM string support!
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_STRHASH_DENSE)
-/* Constants for duk_hashstring(). */
-#define DUK__STRHASH_SHORTSTRING 4096L
-#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L)
-#define DUK__STRHASH_BLOCKSIZE 256L
-
-DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
- duk_uint32_t hash;
-
- /* Use Murmurhash2 directly for short strings, and use "block skipping"
- * for long strings: hash an initial part and then sample the rest of
- * the string with reasonably sized chunks. An initial offset for the
- * sampling is computed based on a hash of the initial part of the string;
- * this is done to (usually) avoid the case where all long strings have
- * certain offset ranges which are never sampled.
- *
- * Skip should depend on length and bound the total time to roughly
- * logarithmic. With current values:
- *
- * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
- * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
- *
- * XXX: It would be better to compute the skip offset more "smoothly"
- * instead of having a few boundary values.
- */
-
- /* note: mixing len into seed improves hashing when skipping */
- duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len);
-
- if (len <= DUK__STRHASH_SHORTSTRING) {
- hash = duk_util_hashbytes(str, len, str_seed);
- } else {
- duk_size_t off;
- duk_size_t skip;
-
- if (len <= DUK__STRHASH_MEDIUMSTRING) {
- skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
- } else {
- skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
- }
-
- hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed);
- off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256;
-
- /* XXX: inefficient loop */
- while (off < len) {
- duk_size_t left = len - off;
- duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left);
- hash ^= duk_util_hashbytes(str + off, now, str_seed);
- off += skip;
- }
- }
-
-#if defined(DUK_USE_STRHASH16)
- /* Truncate to 16 bits here, so that a computed hash can be compared
- * against a hash stored in a 16-bit field.
- */
- hash &= 0x0000ffffUL;
-#endif
- return hash;
-}
-
-#undef DUK__STRHASH_SHORTSTRING
-#undef DUK__STRHASH_MEDIUMSTRING
-#undef DUK__STRHASH_BLOCKSIZE
-#else /* DUK_USE_STRHASH_DENSE */
-DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
- duk_uint32_t hash;
- duk_size_t step;
- duk_size_t off;
-
- /* Slightly modified "Bernstein hash" from:
- *
- * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
- *
- * Modifications: string skipping and reverse direction similar to
- * Lua 5.1.5, and different hash initializer.
- *
- * The reverse direction ensures last byte it always included in the
- * hash which is a good default as changing parts of the string are
- * more often in the suffix than in the prefix.
- */
-
- hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */
- step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1;
- for (off = len; off >= step; off -= step) {
- DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */
- hash = (hash * 33) + str[off - 1];
- }
-
-#if defined(DUK_USE_STRHASH16)
- /* Truncate to 16 bits here, so that a computed hash can be compared
- * against a hash stored in a 16-bit field.
- */
- hash &= 0x0000ffffUL;
-#endif
- return hash;
-}
-#endif /* DUK_USE_STRHASH_DENSE */
-#line 1 "duk_heap_markandsweep.c"
-/*
- * Mark-and-sweep garbage collection.
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_MARK_AND_SWEEP
-
-DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
-DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv);
-
-/*
- * Misc
- */
-
-/* Select a thread for mark-and-sweep use.
- *
- * XXX: This needs to change later.
- */
-DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) {
- if (heap->curr_thread) {
- return heap->curr_thread;
- }
- return heap->heap_thread; /* may be NULL, too */
-}
-
-/*
- * Marking functions for heap types: mark children recursively
- */
-
-DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) {
- DUK_UNREF(heap);
- DUK_UNREF(h);
-
- DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h));
- DUK_ASSERT(h);
-
- /* nothing to process */
-}
-
-DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
- duk_uint_fast32_t i;
-
- DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));
-
- DUK_ASSERT(h);
-
- /* XXX: use advancing pointers instead of index macros -> faster and smaller? */
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
- duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
- if (!key) {
- continue;
- }
- duk__mark_heaphdr(heap, (duk_heaphdr *) key);
- if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
- duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
- duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
- } else {
- duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
- }
- }
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
- duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
- }
-
- /* hash part is a 'weak reference' and does not contribute */
-
- duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
-
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
- duk_tval *tv, *tv_end;
- duk_hobject **fn, **fn_end;
-
- /* 'data' is reachable through every compiled function which
- * contains a reference.
- */
-
- duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(heap, f));
-
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, f);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, f);
- while (tv < tv_end) {
- duk__mark_tval(heap, tv);
- tv++;
- }
-
- fn = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, f);
- fn_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, f);
- while (fn < fn_end) {
- duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
- fn++;
- }
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_hnativefunction *f = (duk_hnativefunction *) h;
- DUK_UNREF(f);
- /* nothing to mark */
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- duk_hbufferobject *b = (duk_hbufferobject *) h;
- duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
- } else if (DUK_HOBJECT_IS_THREAD(h)) {
- duk_hthread *t = (duk_hthread *) h;
- duk_tval *tv;
-
- tv = t->valstack;
- while (tv < t->valstack_top) {
- duk__mark_tval(heap, tv);
- tv++;
- }
-
- for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
- duk_activation *act = t->callstack + i;
- duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
- duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
- duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
-#endif
- }
-
-#if 0 /* nothing now */
- for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
- duk_catcher *cat = t->catchstack + i;
- }
-#endif
-
- duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
-
- /* XXX: duk_small_uint_t would be enough for this loop */
- for (i = 0; i < DUK_NUM_BUILTINS; i++) {
- duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
- }
- }
-}
-
-/* recursion tracking happens here only */
-DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
- DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
- (void *) h,
- (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
- if (!h) {
- return;
- }
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY(h)) {
- DUK_DDD(DUK_DDDPRINT("readonly object %p, skip", (void *) h));
- return;
- }
-#endif
- if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
- DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
- return;
- }
- DUK_HEAPHDR_SET_REACHABLE(h);
-
- if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
- /* log this with a normal debug level because this should be relatively rare */
- DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h));
- DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap);
- DUK_HEAPHDR_SET_TEMPROOT(h);
- return;
- }
-
- heap->mark_and_sweep_recursion_depth++;
-
- switch ((int) DUK_HEAPHDR_GET_TYPE(h)) {
- case DUK_HTYPE_STRING:
- duk__mark_hstring(heap, (duk_hstring *) h);
- break;
- case DUK_HTYPE_OBJECT:
- duk__mark_hobject(heap, (duk_hobject *) h);
- break;
- case DUK_HTYPE_BUFFER:
- /* nothing to mark */
- break;
- default:
- DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h)));
- DUK_UNREACHABLE();
- }
-
- heap->mark_and_sweep_recursion_depth--;
-}
-
-DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
- DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv));
- if (!tv) {
- return;
- }
- if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
- duk__mark_heaphdr(heap, DUK_TVAL_GET_HEAPHDR(tv));
- }
-}
-
-/*
- * Mark the heap.
- */
-
-DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) {
- duk_small_uint_t i;
-
- DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap));
-
- duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread);
- duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object);
-
- for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
- duk_hstring *h = DUK_HEAP_GET_STRING(heap, i);
- duk__mark_heaphdr(heap, (duk_heaphdr *) h);
- }
-
- duk__mark_tval(heap, &heap->lj.value1);
- duk__mark_tval(heap, &heap->lj.value2);
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- for (i = 0; i < heap->dbg_breakpoint_count; i++) {
- duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename);
- }
-#endif
-}
-
-/*
- * Mark refzero_list objects.
- *
- * Objects on the refzero_list have no inbound references. They might have
- * outbound references to objects that we might free, which would invalidate
- * any references held by the refzero objects. A refzero object might also
- * be rescued by refcount finalization. Refzero objects are treated as
- * reachability roots to ensure they (or anything they point to) are not
- * freed in mark-and-sweep.
- */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
-DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) {
- duk_heaphdr *hdr;
-
- DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap));
-
- hdr = heap->refzero_list;
- while (hdr) {
- duk__mark_heaphdr(heap, hdr);
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-}
-#endif
-
-/*
- * Mark unreachable, finalizable objects.
- *
- * Such objects will be moved aside and their finalizers run later. They have
- * to be treated as reachability roots for their properties etc to remain
- * allocated. This marking is only done for unreachable values which would
- * be swept later (refzero_list is thus excluded).
- *
- * Objects are first marked FINALIZABLE and only then marked as reachability
- * roots; otherwise circular references might be handled inconsistently.
- */
-
-DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
- duk_hthread *thr;
- duk_heaphdr *hdr;
- duk_size_t count_finalizable = 0;
-
- DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap));
-
- thr = duk__get_temp_hthread(heap);
- DUK_ASSERT(thr != NULL);
-
- hdr = heap->heap_allocated;
- while (hdr) {
- /* A finalizer is looked up from the object and up its prototype chain
- * (which allows inherited finalizers). A prototype loop must not cause
- * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a
- * prototype loop silently and indicate that the property doesn't exist.
- */
-
- if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
- DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT &&
- !DUK_HEAPHDR_HAS_FINALIZED(hdr) &&
- duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
-
- /* heaphdr:
- * - is not reachable
- * - is an object
- * - is not a finalized object
- * - has a finalizer
- */
-
- DUK_DD(DUK_DDPRINT("unreachable heap object will be "
- "finalized -> mark as finalizable "
- "and treat as a reachability root: %p",
- (void *) hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
- DUK_HEAPHDR_SET_FINALIZABLE(hdr);
- count_finalizable ++;
- }
-
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-
- if (count_finalizable == 0) {
- return;
- }
-
- DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable",
- (long) count_finalizable));
-
- hdr = heap->heap_allocated;
- while (hdr) {
- if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
- duk__mark_heaphdr(heap, hdr);
- }
-
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-
- /* Caller will finish the marking process if we hit a recursion limit. */
-}
-
-/*
- * Mark objects on finalize_list.
- *
- */
-
-DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
- duk_heaphdr *hdr;
-#ifdef DUK_USE_DEBUG
- duk_size_t count_finalize_list = 0;
-#endif
-
- DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap));
-
- hdr = heap->finalize_list;
- while (hdr) {
- duk__mark_heaphdr(heap, hdr);
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
-#ifdef DUK_USE_DEBUG
- count_finalize_list++;
-#endif
- }
-
-#ifdef DUK_USE_DEBUG
- if (count_finalize_list > 0) {
- DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)",
- (long) count_finalize_list));
- }
-#endif
-}
-
-/*
- * Fallback marking handler if recursion limit is reached.
- *
- * Iterates 'temproots' until recursion limit is no longer hit. Note
- * that temproots may reside either in heap allocated list or the
- * refzero work list. This is a slow scan, but guarantees that we
- * finish with a bounded C stack.
- *
- * Note that nodes may have been marked as temproots before this
- * scan begun, OR they may have been marked during the scan (as
- * we process nodes recursively also during the scan). This is
- * intended behavior.
- */
-
-#ifdef DUK_USE_DEBUG
-DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) {
-#else
-DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
-#endif
- if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
- DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
- return;
- }
-
- DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr));
- DUK_HEAPHDR_CLEAR_TEMPROOT(hdr);
- DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */
- duk__mark_heaphdr(heap, hdr);
-
-#ifdef DUK_USE_DEBUG
- (*count)++;
-#endif
-}
-
-DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
- duk_heaphdr *hdr;
-#ifdef DUK_USE_DEBUG
- duk_size_t count;
-#endif
-
- DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap));
-
- while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) {
- DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots"));
-
-#ifdef DUK_USE_DEBUG
- count = 0;
-#endif
- DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap);
-
- hdr = heap->heap_allocated;
- while (hdr) {
-#ifdef DUK_USE_DEBUG
- duk__handle_temproot(heap, hdr, &count);
-#else
- duk__handle_temproot(heap, hdr);
-#endif
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-
- /* must also check refzero_list */
-#ifdef DUK_USE_REFERENCE_COUNTING
- hdr = heap->refzero_list;
- while (hdr) {
-#ifdef DUK_USE_DEBUG
- duk__handle_temproot(heap, hdr, &count);
-#else
- duk__handle_temproot(heap, hdr);
-#endif
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-#endif /* DUK_USE_REFERENCE_COUNTING */
-
-#ifdef DUK_USE_DEBUG
- DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count));
-#endif
- }
-}
-
-/*
- * Finalize refcounts for heap elements just about to be freed.
- * This must be done for all objects before freeing to avoid any
- * stale pointer dereferences.
- *
- * Note that this must deduce the set of objects to be freed
- * identically to duk__sweep_heap().
- */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
-DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
- duk_hthread *thr;
- duk_heaphdr *hdr;
-
- thr = duk__get_temp_hthread(heap);
- DUK_ASSERT(thr != NULL);
-
- DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p",
- (void *) heap, (void *) thr));
-
- hdr = heap->heap_allocated;
- while (hdr) {
- if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) {
- /*
- * Unreachable object about to be swept. Finalize target refcounts
- * (objects which the unreachable object points to) without doing
- * refzero processing. Recursive decrefs are also prevented when
- * refzero processing is disabled.
- *
- * Value cannot be a finalizable object, as they have been made
- * temporarily reachable for this round.
- */
-
- DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
- duk_heaphdr_refcount_finalize(thr, hdr);
- }
-
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-}
-#endif /* DUK_USE_REFERENCE_COUNTING */
-
-/*
- * Clear (reachable) flags of refzero work list.
- */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
-DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) {
- duk_heaphdr *hdr;
-
- DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap));
-
- hdr = heap->refzero_list;
- while (hdr) {
- DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-}
-#endif /* DUK_USE_REFERENCE_COUNTING */
-
-/*
- * Clear (reachable) flags of finalize_list
- *
- * We could mostly do in the sweep phase when we move objects from the
- * heap into the finalize_list. However, if a finalizer run is skipped
- * during a mark-and-sweep, the objects on the finalize_list will be marked
- * reachable during the next mark-and-sweep. Since they're already on the
- * finalize_list, no-one will be clearing their REACHABLE flag so we do it
- * here. (This now overlaps with the sweep handling in a harmless way.)
- */
-
-DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
- duk_heaphdr *hdr;
-
- DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap));
-
- hdr = heap->finalize_list;
- while (hdr) {
- DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-}
-
-/*
- * Sweep stringtable
- */
-
-#if defined(DUK_USE_STRTAB_CHAIN)
-
-/* XXX: skip count_free w/o debug? */
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) {
- duk_uint16_t h16 = *slot;
- duk_hstring *h;
- duk_uint16_t null16 = heap->heapptr_null16;
-
- if (h16 == null16) {
- /* nop */
- return;
- }
- h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16);
- DUK_ASSERT(h != NULL);
-
- if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
- DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
- (*count_keep)++;
- } else {
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
-#endif
- /* deal with weak references first */
- duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
- *slot = null16;
-
- /* free inner references (these exist e.g. when external
- * strings are enabled)
- */
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
- (*count_free)++;
- }
-}
-#else /* DUK_USE_HEAPPTR16 */
-DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) {
- duk_hstring *h = *slot;
-
- if (h == NULL) {
- /* nop */
- return;
- }
-
- if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
- DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
- (*count_keep)++;
- } else {
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
-#endif
- /* deal with weak references first */
- duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
- *slot = NULL;
-
- /* free inner references (these exist e.g. when external
- * strings are enabled)
- */
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
- (*count_free)++;
- }
-}
-#endif /* DUK_USE_HEAPPTR16 */
-
-DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) {
- duk_strtab_entry *e;
- duk_uint_fast32_t i;
- duk_size_t count_free = 0;
- duk_size_t count_keep = 0;
- duk_size_t j, n;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *lst;
-#else
- duk_hstring **lst;
-#endif
-
- DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
-
- /* Non-zero refcounts should not happen for unreachable strings,
- * because we refcount finalize all unreachable objects which
- * should have decreased unreachable string refcounts to zero
- * (even for cycles).
- */
-
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
- e = heap->strtable + i;
- if (e->listlen == 0) {
-#if defined(DUK_USE_HEAPPTR16)
- duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free);
-#else
- duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free);
-#endif
- } else {
-#if defined(DUK_USE_HEAPPTR16)
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
-#else
- lst = e->u.strlist;
-#endif
- for (j = 0, n = e->listlen; j < n; j++) {
-#if defined(DUK_USE_HEAPPTR16)
- duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free);
-#else
- duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free);
-#endif
- }
- }
- }
-
- DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
- (long) count_free, (long) count_keep));
- *out_count_keep = count_keep;
-}
-#endif /* DUK_USE_STRTAB_CHAIN */
-
-#if defined(DUK_USE_STRTAB_PROBE)
-DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) {
- duk_hstring *h;
- duk_uint_fast32_t i;
-#ifdef DUK_USE_DEBUG
- duk_size_t count_free = 0;
-#endif
- duk_size_t count_keep = 0;
-
- DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
-
- for (i = 0; i < heap->st_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]);
-#else
- h = heap->strtable[i];
-#endif
- if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
- continue;
- } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
- DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
- count_keep++;
- continue;
- }
-
-#ifdef DUK_USE_DEBUG
- count_free++;
-#endif
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
- /* Non-zero refcounts should not happen for unreachable strings,
- * because we refcount finalize all unreachable objects which
- * should have decreased unreachable string refcounts to zero
- * (even for cycles).
- */
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
-#endif
-
- DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h));
-
- /* deal with weak references first */
- duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
-
- /* remove the string (mark DELETED), could also call
- * duk_heap_string_remove() but that would be slow and
- * pointless because we already know the slot.
- */
-#if defined(DUK_USE_HEAPPTR16)
- heap->strtable16[i] = heap->heapptr_deleted16;
-#else
- heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap);
-#endif
-
- /* free inner references (these exist e.g. when external
- * strings are enabled)
- */
- duk_free_hstring_inner(heap, (duk_hstring *) h);
-
- /* finally free the struct itself */
- DUK_FREE(heap, h);
- }
-
-#ifdef DUK_USE_DEBUG
- DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
- (long) count_free, (long) count_keep));
-#endif
- *out_count_keep = count_keep;
-}
-#endif /* DUK_USE_STRTAB_PROBE */
-
-/*
- * Sweep heap
- */
-
-DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) {
- duk_heaphdr *prev; /* last element that was left in the heap */
- duk_heaphdr *curr;
- duk_heaphdr *next;
-#ifdef DUK_USE_DEBUG
- duk_size_t count_free = 0;
- duk_size_t count_finalize = 0;
- duk_size_t count_rescue = 0;
-#endif
- duk_size_t count_keep = 0;
-
- DUK_UNREF(flags);
- DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
-
- prev = NULL;
- curr = heap->heap_allocated;
- heap->heap_allocated = NULL;
- while (curr) {
- /* Strings and ROM objects are never placed on the heap allocated list. */
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING);
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr));
-
- next = DUK_HEAPHDR_GET_NEXT(heap, curr);
-
- if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
- /*
- * Reachable object, keep
- */
-
- DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr));
-
- if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) {
- /*
- * If object has been marked finalizable, move it to the
- * "to be finalized" work list. It will be collected on
- * the next mark-and-sweep if it is still unreachable
- * after running the finalizer.
- */
-
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
- DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr));
-
-#ifdef DUK_USE_DOUBLE_LINKED_HEAP
- if (heap->finalize_list) {
- DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr);
- }
- DUK_HEAPHDR_SET_PREV(heap, curr, NULL);
-#endif
- DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list);
- DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
- heap->finalize_list = curr;
-#ifdef DUK_USE_DEBUG
- count_finalize++;
-#endif
- } else {
- /*
- * Object will be kept; queue object back to heap_allocated (to tail)
- */
-
- if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
- /*
- * Object's finalizer was executed on last round, and
- * object has been happily rescued.
- */
-
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
- DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr));
-#ifdef DUK_USE_DEBUG
- count_rescue++;
-#endif
- } else {
- /*
- * Plain, boring reachable object.
- */
- DUK_DD(DUK_DDPRINT("keep object: %!iO", curr));
- count_keep++;
- }
-
- if (!heap->heap_allocated) {
- heap->heap_allocated = curr;
- }
- if (prev) {
- DUK_HEAPHDR_SET_NEXT(heap, prev, curr);
- }
-#ifdef DUK_USE_DOUBLE_LINKED_HEAP
- DUK_HEAPHDR_SET_PREV(heap, curr, prev);
-#endif
- DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
- DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
- prev = curr;
- }
-
- DUK_HEAPHDR_CLEAR_REACHABLE(curr);
- DUK_HEAPHDR_CLEAR_FINALIZED(curr);
- DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
-
- DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
-
- curr = next;
- } else {
- /*
- * Unreachable object, free
- */
-
- DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr));
-
-#if defined(DUK_USE_REFERENCE_COUNTING)
- /* Non-zero refcounts should not happen because we refcount
- * finalize all unreachable objects which should cancel out
- * refcounts (even for cycles).
- */
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0);
-#endif
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
-
- if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
- DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr));
- }
-
- /* Note: object cannot be a finalizable unreachable object, as
- * they have been marked temporarily reachable for this round,
- * and are handled above.
- */
-
-#ifdef DUK_USE_DEBUG
- count_free++;
-#endif
-
- /* weak refs should be handled here, but no weak refs for
- * any non-string objects exist right now.
- */
-
- /* free object and all auxiliary (non-heap) allocs */
- duk_heap_free_heaphdr_raw(heap, curr);
-
- curr = next;
- }
- }
- if (prev) {
- DUK_HEAPHDR_SET_NEXT(heap, prev, NULL);
- }
- DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
-
-#ifdef DUK_USE_DEBUG
- DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization",
- (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize));
-#endif
- *out_count_keep = count_keep;
-}
-
-/*
- * Run (object) finalizers in the "to be finalized" work list.
- */
-
-DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) {
- duk_heaphdr *curr;
- duk_heaphdr *next;
-#ifdef DUK_USE_DEBUG
- duk_size_t count = 0;
-#endif
- duk_hthread *thr;
-
- DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap));
-
- thr = duk__get_temp_hthread(heap);
- DUK_ASSERT(thr != NULL);
-
- curr = heap->finalize_list;
- while (curr) {
- DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr));
-
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */
- DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */
- DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */
-
- if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) {
- /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED.
- * Next mark-and-sweep will collect the object unless it has
- * become reachable (i.e. rescued). FINALIZED prevents the
- * finalizer from being executed again before that.
- */
- duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */
- DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
- } else {
- /* Used during heap destruction: don't actually run finalizers
- * because we're heading into forced finalization. Instead,
- * queue finalizable objects back to the heap_allocated list.
- */
- DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
- }
-
- /* queue back to heap_allocated */
- next = DUK_HEAPHDR_GET_NEXT(heap, curr);
- DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
-
- curr = next;
-#ifdef DUK_USE_DEBUG
- count++;
-#endif
- }
-
- /* finalize_list will always be processed completely */
- heap->finalize_list = NULL;
-
-#ifdef DUK_USE_DEBUG
- DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count));
-#endif
-}
-
-/*
- * Object compaction.
- *
- * Compaction is assumed to never throw an error.
- */
-
-DUK_LOCAL int duk__protected_compact_object(duk_context *ctx) {
- /* XXX: for threads, compact value stack, call stack, catch stack? */
-
- duk_hobject *obj = duk_get_hobject(ctx, -1);
- DUK_ASSERT(obj != NULL);
- duk_hobject_compact_props((duk_hthread *) ctx, obj);
- return 0;
-}
-
-#ifdef DUK_USE_DEBUG
-DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start, duk_size_t *p_count_check, duk_size_t *p_count_compact, duk_size_t *p_count_bytes_saved) {
-#else
-DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) {
-#endif
- duk_heaphdr *curr;
-#ifdef DUK_USE_DEBUG
- duk_size_t old_size, new_size;
-#endif
- duk_hobject *obj;
-
- DUK_UNREF(heap);
-
- curr = start;
- while (curr) {
- DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr));
-
- if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) {
- goto next;
- }
- obj = (duk_hobject *) curr;
-
-#ifdef DUK_USE_DEBUG
- old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
- DUK_HOBJECT_GET_ASIZE(obj),
- DUK_HOBJECT_GET_HSIZE(obj));
-#endif
-
- DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
- duk_push_hobject((duk_context *) thr, obj);
- /* XXX: disable error handlers for duration of compaction? */
- duk_safe_call((duk_context *) thr, duk__protected_compact_object, 1, 0);
-
-#ifdef DUK_USE_DEBUG
- new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
- DUK_HOBJECT_GET_ASIZE(obj),
- DUK_HOBJECT_GET_HSIZE(obj));
-#endif
-
-#ifdef DUK_USE_DEBUG
- (*p_count_compact)++;
- (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size);
-#endif
-
- next:
- curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
-#ifdef DUK_USE_DEBUG
- (*p_count_check)++;
-#endif
- }
-}
-
-DUK_LOCAL void duk__compact_objects(duk_heap *heap) {
- /* XXX: which lists should participate? to be finalized? */
-#ifdef DUK_USE_DEBUG
- duk_size_t count_check = 0;
- duk_size_t count_compact = 0;
- duk_size_t count_bytes_saved = 0;
-#endif
- duk_hthread *thr;
-
- DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap));
-
- thr = duk__get_temp_hthread(heap);
- DUK_ASSERT(thr != NULL);
-
-#ifdef DUK_USE_DEBUG
- duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
- duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved);
-#endif
-#else
- duk__compact_object_list(heap, thr, heap->heap_allocated);
- duk__compact_object_list(heap, thr, heap->finalize_list);
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__compact_object_list(heap, thr, heap->refzero_list);
-#endif
-#endif
-
-#ifdef DUK_USE_DEBUG
- DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction",
- (long) count_check, (long) count_compact, (long) count_bytes_saved));
-#endif
-}
-
-/*
- * Assertion helpers.
- */
-
-#ifdef DUK_USE_ASSERTIONS
-DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) {
- duk_heaphdr *hdr;
-
- hdr = heap->heap_allocated;
- while (hdr) {
- DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
- /* may have FINALIZED */
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- hdr = heap->refzero_list;
- while (hdr) {
- DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-#endif /* DUK_USE_REFERENCE_COUNTING */
-}
-
-#ifdef DUK_USE_REFERENCE_COUNTING
-DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) {
- duk_heaphdr *hdr = heap->heap_allocated;
- while (hdr) {
- if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 &&
- DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
- /* An object may be in heap_allocated list with a zero
- * refcount if it has just been finalized and is waiting
- * to be collected by the next cycle.
- */
- } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) {
- /* An object may be in heap_allocated list with a zero
- * refcount also if it is a temporary object created by
- * a finalizer; because finalization now runs inside
- * mark-and-sweep, such objects will not be queued to
- * refzero_list and will thus appear here with refcount
- * zero.
- */
-#if 0 /* this case can no longer occur because refcount is unsigned */
- } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) {
- DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O",
- (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0),
- (void *) hdr, (duk_heaphdr *) hdr));
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0);
-#endif
- }
- hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
-}
-#endif /* DUK_USE_REFERENCE_COUNTING */
-#endif /* DUK_USE_ASSERTIONS */
-
-/*
- * Finalizer torture. Do one fake finalizer call which causes side effects
- * similar to one or more finalizers on actual objects.
- */
-
-#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
-DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) {
- DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed"));
-
- /* Require a lot of stack to force a value stack grow/shrink.
- * Recursive mark-and-sweep is prevented by allocation macros
- * so this won't trigger another mark-and-sweep.
- */
- duk_require_stack(ctx, 100000);
-
- /* XXX: do something to force a callstack grow/shrink, perhaps
- * just a manual forced resize or a forced relocating realloc?
- */
-
- return 0;
-}
-
-DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) {
- duk_context *ctx;
- duk_int_t rc;
-
- DUK_ASSERT(thr != NULL);
- ctx = (duk_context *) thr;
-
- /* Avoid fake finalization when callstack limit has been reached.
- * Otherwise a callstack limit error will be created, then refzero'ed.
- */
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
- thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
- DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer"));
- return;
- }
-
- /* Run fake finalizer. Avoid creating unnecessary garbage. */
- duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/);
- rc = duk_pcall(ctx, 0 /*nargs*/);
- DUK_UNREF(rc); /* ignored */
- duk_pop(ctx);
-}
-#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
-
-/*
- * Main mark-and-sweep function.
- *
- * 'flags' represents the features requested by the caller. The current
- * heap->mark_and_sweep_base_flags is ORed automatically into the flags;
- * the base flags mask typically prevents certain mark-and-sweep operations
- * to avoid trouble.
- */
-
-DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) {
- duk_hthread *thr;
- duk_size_t count_keep_obj;
- duk_size_t count_keep_str;
-#ifdef DUK_USE_VOLUNTARY_GC
- duk_size_t tmp;
-#endif
-
- /* XXX: thread selection for mark-and-sweep is currently a hack.
- * If we don't have a thread, the entire mark-and-sweep is now
- * skipped (although we could just skip finalizations).
- */
-
- /* If thr != NULL, the thr may still be in the middle of
- * initialization.
- * XXX: Improve the thread viability test.
- */
- thr = duk__get_temp_hthread(heap);
- if (thr == NULL) {
- DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread"));
-
- /* reset voluntary gc trigger count */
-#ifdef DUK_USE_VOLUNTARY_GC
- heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP;
-#endif
- return 0; /* OK */
- }
-
- /* If debugger is paused, garbage collection is disabled by default. */
- /* XXX: will need a force flag if garbage collection is triggered
- * explicitly during paused state.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_IS_PAUSED(heap)) {
- /* Checking this here rather that in memory alloc primitives
- * reduces checking code there but means a failed allocation
- * will go through a few retries before giving up. That's
- * fine because this only happens during debugging.
- */
- DUK_D(DUK_DPRINT("gc skipped because debugger is paused"));
- return 0;
- }
-#endif
-
- DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
- (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags)));
-
- flags |= heap->mark_and_sweep_base_flags;
-
- /*
- * Assertions before
- */
-
-#ifdef DUK_USE_ASSERTIONS
- DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
- DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
- DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
- duk__assert_heaphdr_flags(heap);
-#ifdef DUK_USE_REFERENCE_COUNTING
- /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
- * finalizer may trigger a mark-and-sweep.
- */
- duk__assert_valid_refcounts(heap);
-#endif /* DUK_USE_REFERENCE_COUNTING */
-#endif /* DUK_USE_ASSERTIONS */
-
- /*
- * Begin
- */
-
- DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
-
- /*
- * Mark roots, hoping that recursion limit is not normally hit.
- * If recursion limit is hit, run additional reachability rounds
- * starting from "temproots" until marking is complete.
- *
- * Marking happens in two phases: first we mark actual reachability
- * roots (and run "temproots" to complete the process). Then we
- * check which objects are unreachable and are finalizable; such
- * objects are marked as FINALIZABLE and marked as reachability
- * (and "temproots" is run again to complete the process).
- *
- * The heap finalize_list must also be marked as a reachability root.
- * There may be objects on the list from a previous round if the
- * previous run had finalizer skip flag.
- */
-
- duk__mark_roots_heap(heap); /* main reachability roots */
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */
-#endif
- duk__mark_temproots_by_heap_scan(heap); /* temproots */
-
- duk__mark_finalizable(heap); /* mark finalizable as reachability roots */
- duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */
- duk__mark_temproots_by_heap_scan(heap); /* temproots */
-
- /*
- * Sweep garbage and remove marking flags, and move objects with
- * finalizers to the finalizer work list.
- *
- * Objects to be swept need to get their refcounts finalized before
- * they are swept. In other words, their target object refcounts
- * need to be decreased. This has to be done before freeing any
- * objects to avoid decref'ing dangling pointers (which may happen
- * even without bugs, e.g. with reference loops)
- *
- * Because strings don't point to other heap objects, similar
- * finalization is not necessary for strings.
- */
-
- /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__finalize_refcounts(heap);
-#endif
- duk__sweep_heap(heap, flags, &count_keep_obj);
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk__sweep_stringtable_chain(heap, &count_keep_str);
-#elif defined(DUK_USE_STRTAB_PROBE)
- duk__sweep_stringtable_probe(heap, &count_keep_str);
-#else
-#error internal error, invalid strtab options
-#endif
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk__clear_refzero_list_flags(heap);
-#endif
- duk__clear_finalize_list_flags(heap);
-
- /*
- * Object compaction (emergency only).
- *
- * Object compaction is a separate step after sweeping, as there is
- * more free memory for it to work with. Also, currently compaction
- * may insert new objects into the heap allocated list and the string
- * table which we don't want to do during a sweep (the reachability
- * flags of such objects would be incorrect). The objects inserted
- * are currently:
- *
- * - a temporary duk_hbuffer for a new properties allocation
- * - if array part is abandoned, string keys are interned
- *
- * The object insertions go to the front of the list, so they do not
- * cause an infinite loop (they are not compacted).
- */
-
- if ((flags & DUK_MS_FLAG_EMERGENCY) &&
- !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) {
- duk__compact_objects(heap);
- }
-
- /*
- * String table resize check.
- *
- * Note: this may silently (and safely) fail if GC is caused by an
- * allocation call in stringtable resize_hash(). Resize_hash()
- * will prevent a recursive call to itself by setting the
- * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags.
- */
-
- /* XXX: stringtable emergency compaction? */
-
-#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
- if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) {
- DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap));
- duk_heap_force_strtab_resize(heap);
- } else {
- DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set"));
- }
-#endif
-
- /*
- * Finalize objects in the finalization work list. Finalized
- * objects are queued back to heap_allocated with FINALIZED set.
- *
- * Since finalizers may cause arbitrary side effects, they are
- * prevented during string table and object property allocation
- * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in
- * heap->mark_and_sweep_base_flags. In this case the objects
- * remain in the finalization work list after mark-and-sweep
- * exits and they may be finalized on the next pass.
- *
- * Finalization currently happens inside "MARKANDSWEEP_RUNNING"
- * protection (no mark-and-sweep may be triggered by the
- * finalizers). As a side effect:
- *
- * 1) an out-of-memory error inside a finalizer will not
- * cause a mark-and-sweep and may cause the finalizer
- * to fail unnecessarily
- *
- * 2) any temporary objects whose refcount decreases to zero
- * during finalization will not be put into refzero_list;
- * they can only be collected by another mark-and-sweep
- *
- * This is not optimal, but since the sweep for this phase has
- * already happened, this is probably good enough for now.
- */
-
-#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
- /* Cannot simulate individual finalizers because finalize_list only
- * contains objects with actual finalizers. But simulate side effects
- * from finalization by doing a bogus function call and resizing the
- * stacks.
- */
- if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
- DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set"));
- } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) {
- DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable"));
- } else {
- DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer"));
- duk__markandsweep_torture_finalizer(thr);
- }
-#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
-
- if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
- DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set"));
- } else {
- duk__run_object_finalizers(heap, flags);
- }
-
- /*
- * Finish
- */
-
- DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
-
- /*
- * Assertions after
- */
-
-#ifdef DUK_USE_ASSERTIONS
- DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
- DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
- DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
- duk__assert_heaphdr_flags(heap);
-#ifdef DUK_USE_REFERENCE_COUNTING
- /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
- * finalizer may trigger a mark-and-sweep.
- */
- duk__assert_valid_refcounts(heap);
-#endif /* DUK_USE_REFERENCE_COUNTING */
-#endif /* DUK_USE_ASSERTIONS */
-
- /*
- * Reset trigger counter
- */
-
-#ifdef DUK_USE_VOLUNTARY_GC
- tmp = (count_keep_obj + count_keep_str) / 256;
- heap->mark_and_sweep_trigger_counter = (duk_int_t) (
- (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) +
- DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD);
- DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld",
- (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter));
-#else
- DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger",
- (long) count_keep_obj, (long) count_keep_str));
-#endif
-
- return 0; /* OK */
-}
-
-#else /* DUK_USE_MARK_AND_SWEEP */
-
-/* no mark-and-sweep gc */
-
-#endif /* DUK_USE_MARK_AND_SWEEP */
-#line 1 "duk_heap_memory.c"
-/*
- * Memory allocation handling.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Helpers
- *
- * The fast path checks are done within a macro to ensure "inlining"
- * while the slow path actions use a helper (which won't typically be
- * inlined in size optimized builds).
- */
-
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
-#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \
- (heap)->mark_and_sweep_trigger_counter--; \
- if ((heap)->mark_and_sweep_trigger_counter <= 0) { \
- duk__run_voluntary_gc(heap); \
- } \
- } while (0)
-
-DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) {
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
- DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now"));
- } else {
- duk_small_uint_t flags;
- duk_bool_t rc;
-
- DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep"));
- flags = 0;
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
- }
-}
-#else
-#define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */
-#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
-
-/*
- * Allocate memory with garbage collection
- */
-
-#ifdef DUK_USE_MARK_AND_SWEEP
-DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
- void *res;
- duk_bool_t rc;
- duk_small_int_t i;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT_DISABLE(size >= 0);
-
- /*
- * Voluntary periodic GC (if enabled)
- */
-
- DUK__VOLUNTARY_PERIODIC_GC(heap);
-
- /*
- * First attempt
- */
-
-#ifdef DUK_USE_GC_TORTURE
- /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */
- if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
- DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
- res = NULL;
- DUK_UNREF(res);
- goto skip_attempt;
- }
-#endif
- res = heap->alloc_func(heap->heap_udata, size);
- if (res || size == 0) {
- /* for zero size allocations NULL is allowed */
- return res;
- }
-#ifdef DUK_USE_GC_TORTURE
- skip_attempt:
-#endif
-
- DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry"));
-
- /*
- * Avoid a GC if GC is already running. This can happen at a late
- * stage in a GC when we try to e.g. resize the stringtable
- * or compact objects.
- */
-
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
- DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size));
- return NULL;
- }
-
- /*
- * Retry with several GC attempts. Initial attempts are made without
- * emergency mode; later attempts use emergency mode which minimizes
- * memory allocations forcibly.
- */
-
- for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
- duk_small_uint_t flags;
-
- flags = 0;
- if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
- flags |= DUK_MS_FLAG_EMERGENCY;
- }
-
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
-
- res = heap->alloc_func(heap->heap_udata, size);
- if (res) {
- DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld",
- (long) (i + 1), (long) size));
- return res;
- }
- }
-
- DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size));
- return NULL;
-}
-#else /* DUK_USE_MARK_AND_SWEEP */
-/*
- * Compared to a direct macro expansion this wrapper saves a few
- * instructions because no heap dereferencing is required.
- */
-DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT_DISABLE(size >= 0);
-
- return heap->alloc_func(heap->heap_udata, size);
-}
-#endif /* DUK_USE_MARK_AND_SWEEP */
-
-DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
- void *res;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT_DISABLE(size >= 0);
-
- res = DUK_ALLOC(heap, size);
- if (res) {
- /* assume memset with zero size is OK */
- DUK_MEMZERO(res, size);
- }
- return res;
-}
-
-/*
- * Reallocate memory with garbage collection
- */
-
-#ifdef DUK_USE_MARK_AND_SWEEP
-DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
- void *res;
- duk_bool_t rc;
- duk_small_int_t i;
-
- DUK_ASSERT(heap != NULL);
- /* ptr may be NULL */
- DUK_ASSERT_DISABLE(newsize >= 0);
-
- /*
- * Voluntary periodic GC (if enabled)
- */
-
- DUK__VOLUNTARY_PERIODIC_GC(heap);
-
- /*
- * First attempt
- */
-
-#ifdef DUK_USE_GC_TORTURE
- /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
- if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
- DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails"));
- res = NULL;
- DUK_UNREF(res);
- goto skip_attempt;
- }
-#endif
- res = heap->realloc_func(heap->heap_udata, ptr, newsize);
- if (res || newsize == 0) {
- /* for zero size allocations NULL is allowed */
- return res;
- }
-#ifdef DUK_USE_GC_TORTURE
- skip_attempt:
-#endif
-
- DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
-
- /*
- * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
- */
-
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
- DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
- return NULL;
- }
-
- /*
- * Retry with several GC attempts. Initial attempts are made without
- * emergency mode; later attempts use emergency mode which minimizes
- * memory allocations forcibly.
- */
-
- for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
- duk_small_uint_t flags;
-
- flags = 0;
- if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
- flags |= DUK_MS_FLAG_EMERGENCY;
- }
-
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
-
- res = heap->realloc_func(heap->heap_udata, ptr, newsize);
- if (res || newsize == 0) {
- DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld",
- (long) (i + 1), (long) newsize));
- return res;
- }
- }
-
- DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize));
- return NULL;
-}
-#else /* DUK_USE_MARK_AND_SWEEP */
-/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
-DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
- DUK_ASSERT(heap != NULL);
- /* ptr may be NULL */
- DUK_ASSERT_DISABLE(newsize >= 0);
-
- return heap->realloc_func(heap->heap_udata, ptr, newsize);
-}
-#endif /* DUK_USE_MARK_AND_SWEEP */
-
-/*
- * Reallocate memory with garbage collection, using a callback to provide
- * the current allocated pointer. This variant is used when a mark-and-sweep
- * (e.g. finalizers) might change the original pointer.
- */
-
-#ifdef DUK_USE_MARK_AND_SWEEP
-DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
- void *res;
- duk_bool_t rc;
- duk_small_int_t i;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT_DISABLE(newsize >= 0);
-
- /*
- * Voluntary periodic GC (if enabled)
- */
-
- DUK__VOLUNTARY_PERIODIC_GC(heap);
-
- /*
- * First attempt
- */
-
-#ifdef DUK_USE_GC_TORTURE
- /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
- if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
- DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
- res = NULL;
- DUK_UNREF(res);
- goto skip_attempt;
- }
-#endif
- res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
- if (res || newsize == 0) {
- /* for zero size allocations NULL is allowed */
- return res;
- }
-#ifdef DUK_USE_GC_TORTURE
- skip_attempt:
-#endif
-
- DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
-
- /*
- * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
- */
-
- if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
- DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
- return NULL;
- }
-
- /*
- * Retry with several GC attempts. Initial attempts are made without
- * emergency mode; later attempts use emergency mode which minimizes
- * memory allocations forcibly.
- */
-
- for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
- duk_small_uint_t flags;
-
-#ifdef DUK_USE_ASSERTIONS
- void *ptr_pre; /* ptr before mark-and-sweep */
- void *ptr_post;
-#endif
-
-#ifdef DUK_USE_ASSERTIONS
- ptr_pre = cb(heap, ud);
-#endif
- flags = 0;
- if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
- flags |= DUK_MS_FLAG_EMERGENCY;
- }
-
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
-#ifdef DUK_USE_ASSERTIONS
- ptr_post = cb(heap, ud);
- if (ptr_pre != ptr_post) {
- /* useful for debugging */
- DUK_DD(DUK_DDPRINT("note: base pointer changed by mark-and-sweep: %p -> %p",
- (void *) ptr_pre, (void *) ptr_post));
- }
-#endif
-
- /* Note: key issue here is to re-lookup the base pointer on every attempt.
- * The pointer being reallocated may change after every mark-and-sweep.
- */
-
- res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
- if (res || newsize == 0) {
- DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld",
- (long) (i + 1), (long) newsize));
- return res;
- }
- }
-
- DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize));
- return NULL;
-}
-#else /* DUK_USE_MARK_AND_SWEEP */
-/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
-DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
- return heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
-}
-#endif /* DUK_USE_MARK_AND_SWEEP */
-
-/*
- * Free memory
- */
-
-#ifdef DUK_USE_MARK_AND_SWEEP
-DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
- DUK_ASSERT(heap != NULL);
- /* ptr may be NULL */
-
- /* Must behave like a no-op with NULL and any pointer returned from
- * malloc/realloc with zero size.
- */
- heap->free_func(heap->heap_udata, ptr);
-
- /* Count free operations toward triggering a GC but never actually trigger
- * a GC from a free. Otherwise code which frees internal structures would
- * need to put in NULLs at every turn to ensure the object is always in
- * consistent state for a mark-and-sweep.
- */
-#ifdef DUK_USE_VOLUNTARY_GC
- heap->mark_and_sweep_trigger_counter--;
-#endif
-}
-#else
-/* saves a few instructions to have this wrapper (see comment on duk_heap_mem_alloc) */
-DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
- DUK_ASSERT(heap != NULL);
- /* ptr may be NULL */
-
- /* Note: must behave like a no-op with NULL and any pointer
- * returned from malloc/realloc with zero size.
- */
- heap->free_func(heap->heap_udata, ptr);
-}
-#endif
-#line 1 "duk_heap_misc.c"
-/*
- * Support functions for duk_heap.
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
-/* arbitrary remove only works with double linked heap, and is only required by
- * reference counting so far.
- */
-DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
-
- if (DUK_HEAPHDR_GET_PREV(heap, hdr)) {
- DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr));
- } else {
- heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr);
- }
- if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) {
- DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr));
- } else {
- ;
- }
-
- /* The prev/next pointers of the removed duk_heaphdr are left as garbage.
- * It's up to the caller to ensure they're written before inserting the
- * object back.
- */
-}
-#endif
-
-DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
-
-#ifdef DUK_USE_DOUBLE_LINKED_HEAP
- if (heap->heap_allocated) {
- DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL);
- DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr);
- }
- DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
-#endif
- DUK_HEAPHDR_SET_NEXT(heap, hdr, heap->heap_allocated);
- heap->heap_allocated = hdr;
-}
-
-#ifdef DUK_USE_INTERRUPT_COUNTER
-DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
- duk_hthread *curr_thr;
-
- DUK_ASSERT(heap != NULL);
-
- if (new_thr != NULL) {
- curr_thr = heap->curr_thread;
- if (curr_thr == NULL) {
- /* For initial entry use default value; zero forces an
- * interrupt before executing the first insturction.
- */
- DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter"));
- new_thr->interrupt_counter = 0;
- new_thr->interrupt_init = 0;
- } else {
- /* Copy interrupt counter/init value state to new thread (if any).
- * It's OK for new_thr to be the same as curr_thr.
- */
-#if defined(DUK_USE_DEBUG)
- if (new_thr != curr_thr) {
- DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter"));
- }
-#endif
- new_thr->interrupt_counter = curr_thr->interrupt_counter;
- new_thr->interrupt_init = curr_thr->interrupt_init;
- }
- } else {
- DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes"));
- }
-
- heap->curr_thread = new_thr; /* may be NULL */
-}
-#endif /* DUK_USE_INTERRUPT_COUNTER */
-#line 1 "duk_heap_refcount.c"
-/*
- * Reference counting implementation.
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
-
-#ifndef DUK_USE_DOUBLE_LINKED_HEAP
-#error internal error, reference counting requires a double linked heap
-#endif
-
-/*
- * Misc
- */
-
-DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) {
- /* tail insert: don't disturb head in case refzero is running */
-
- if (heap->refzero_list != NULL) {
- duk_heaphdr *hdr_prev;
-
- hdr_prev = heap->refzero_list_tail;
- DUK_ASSERT(hdr_prev != NULL);
- DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL);
-
- DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
- DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev);
- DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr);
- DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
- DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev);
- heap->refzero_list_tail = hdr;
- } else {
- DUK_ASSERT(heap->refzero_list_tail == NULL);
- DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
- DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
- DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
- heap->refzero_list = hdr;
- heap->refzero_list_tail = hdr;
- }
-}
-
-/*
- * Heap object refcount finalization.
- *
- * When an object is about to be freed, all other objects it refers to must
- * be decref'd. Refcount finalization does NOT free the object or its inner
- * allocations (mark-and-sweep shares these helpers), it just manipulates
- * the refcounts.
- *
- * Note that any of the decref's may cause a refcount to drop to zero, BUT
- * it will not be processed inline; instead, because refzero is already
- * running, the objects will just be queued to refzero list and processed
- * later. This eliminates C recursion.
- */
-
-DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) {
- duk_uint_fast32_t i;
-
- DUK_ASSERT(h);
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
-
- /* XXX: better to get base and walk forwards? */
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
- duk_hstring *key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
- if (!key) {
- continue;
- }
- duk_heaphdr_decref(thr, (duk_heaphdr *) key);
- if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i)) {
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, h, i));
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, h, i));
- } else {
- duk_tval_decref(thr, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i));
- }
- }
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
- duk_tval_decref(thr, DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i));
- }
-
- /* hash part is a 'weak reference' and does not contribute */
-
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h));
-
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) {
- duk_hcompiledfunction *f = (duk_hcompiledfunction *) h;
- duk_tval *tv, *tv_end;
- duk_hobject **funcs, **funcs_end;
-
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL); /* compiled functions must be created 'atomically' */
-
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
- while (tv < tv_end) {
- duk_tval_decref(thr, tv);
- tv++;
- }
-
- funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
- funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
- while (funcs < funcs_end) {
- duk_heaphdr_decref(thr, (duk_heaphdr *) *funcs);
- funcs++;
- }
-
- duk_heaphdr_decref(thr, (duk_heaphdr *) DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f));
- } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) {
- duk_hnativefunction *f = (duk_hnativefunction *) h;
- DUK_UNREF(f);
- /* nothing to finalize */
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h)) {
- duk_hbufferobject *b = (duk_hbufferobject *) h;
- if (b->buf) {
- duk_heaphdr_decref(thr, (duk_heaphdr *) b->buf);
- }
- } else if (DUK_HOBJECT_IS_THREAD(h)) {
- duk_hthread *t = (duk_hthread *) h;
- duk_tval *tv;
-
- tv = t->valstack;
- while (tv < t->valstack_top) {
- duk_tval_decref(thr, tv);
- tv++;
- }
-
- for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
- duk_activation *act = t->callstack + i;
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->var_env);
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->lex_env);
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) act->prev_caller);
-#endif
- }
-
-#if 0 /* nothing now */
- for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
- duk_catcher *cat = t->catchstack + i;
- }
-#endif
-
- for (i = 0; i < DUK_NUM_BUILTINS; i++) {
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->builtins[i]);
- }
-
- duk_heaphdr_decref_allownull(thr, (duk_heaphdr *) t->resumer);
- }
-}
-
-DUK_INTERNAL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr) {
- DUK_ASSERT(hdr);
-
- switch ((int) DUK_HEAPHDR_GET_TYPE(hdr)) {
- case DUK_HTYPE_OBJECT:
- duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr);
- break;
- case DUK_HTYPE_BUFFER:
- /* nothing to finalize */
- break;
- case DUK_HTYPE_STRING:
- /* cannot happen: strings are not put into refzero list (they don't even have the next/prev pointers) */
- default:
- DUK_UNREACHABLE();
- }
-}
-
-#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
-DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) {
- DUK_UNREF(ctx);
- DUK_D(DUK_DPRINT("fake refcount torture finalizer executed"));
-#if 0
- DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0)));
-#endif
- /* Require a lot of stack to force a value stack grow/shrink. */
- duk_require_stack(ctx, 100000);
-
- /* XXX: do something to force a callstack grow/shrink, perhaps
- * just a manual forced resize?
- */
- return 0;
-}
-
-DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx;
- duk_int_t rc;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
- ctx = (duk_context *) thr;
-
- /* Avoid fake finalization for the duk__refcount_fake_finalizer function
- * itself, otherwise we're in infinite recursion.
- */
- if (DUK_HOBJECT_HAS_NATIVEFUNCTION(obj)) {
- if (((duk_hnativefunction *) obj)->func == duk__refcount_fake_finalizer) {
- DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself"));
- return;
- }
- }
- /* Avoid fake finalization when callstack limit has been reached.
- * Otherwise a callstack limit error will be created, then refzero'ed,
- * and we're in an infinite loop.
- */
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
- thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
- DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer"));
- return;
- }
-
- /* Run fake finalizer. Avoid creating new refzero queue entries
- * so that we are not forced into a forever loop.
- */
- duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/);
- duk_push_hobject(ctx, obj);
- rc = duk_pcall(ctx, 1);
- DUK_UNREF(rc); /* ignored */
- duk_pop(ctx);
-}
-#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */
-
-/*
- * Refcount memory freeing loop.
- *
- * Frees objects in the refzero_pending list until the list becomes
- * empty. When an object is freed, its references get decref'd and
- * may cause further objects to be queued for freeing.
- *
- * This could be expanded to allow incremental freeing: just bail out
- * early and resume at a future alloc/decref/refzero.
- */
-
-DUK_LOCAL void duk__refzero_free_pending(duk_hthread *thr) {
- duk_heaphdr *h1, *h2;
- duk_heap *heap;
- duk_int_t count = 0;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- heap = thr->heap;
- DUK_ASSERT(heap != NULL);
-
- /*
- * Detect recursive invocation
- */
-
- if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) {
- DUK_DDD(DUK_DDDPRINT("refzero free running, skip run"));
- return;
- }
-
- /*
- * Churn refzero_list until empty
- */
-
- DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap);
- while (heap->refzero_list) {
- duk_hobject *obj;
- duk_bool_t rescued = 0;
-
- /*
- * Pick an object from the head (don't remove yet).
- */
-
- h1 = heap->refzero_list;
- obj = (duk_hobject *) h1;
- DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1));
- DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL);
- DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */
-
-#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
- /* Torture option to shake out finalizer side effect issues:
- * make a bogus function call for every finalizable object,
- * essentially simulating the case where everything has a
- * finalizer.
- */
- DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer"));
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
- DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
- duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */
- DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
- DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
-#endif
-
- /*
- * Finalizer check.
- *
- * Note: running a finalizer may have arbitrary side effects, e.g.
- * queue more objects on refzero_list (tail), or even trigger a
- * mark-and-sweep.
- *
- * Note: quick reject check should match vast majority of
- * objects and must be safe (not throw any errors, ever).
- */
-
- /* An object may have FINALIZED here if it was finalized by mark-and-sweep
- * on a previous run and refcount then decreased to zero. We won't run the
- * finalizer again here.
- */
-
- /* A finalizer is looked up from the object and up its prototype chain
- * (which allows inherited finalizers).
- */
- if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
- DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it"));
-
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
- DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
-
- duk_hobject_run_finalizer(thr, obj); /* must never longjmp */
- DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */
-
- DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
- DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
-
- if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) {
- DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued"));
- rescued = 1;
- } else {
- DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed"));
- }
- }
-
- /* Refzero head is still the same. This is the case even if finalizer
- * inserted more refzero objects; they are inserted to the tail.
- */
- DUK_ASSERT(h1 == heap->refzero_list);
-
- /*
- * Remove the object from the refzero list. This cannot be done
- * before a possible finalizer has been executed; the finalizer
- * may trigger a mark-and-sweep, and mark-and-sweep must be able
- * to traverse a complete refzero_list.
- */
-
- h2 = DUK_HEAPHDR_GET_NEXT(heap, h1);
- if (h2) {
- DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */
- heap->refzero_list = h2;
- } else {
- heap->refzero_list = NULL;
- heap->refzero_list_tail = NULL;
- }
-
- /*
- * Rescue or free.
- */
-
- if (rescued) {
- /* yes -> move back to heap allocated */
- DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1));
- DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1));
- DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1));
- DUK_HEAPHDR_CLEAR_FINALIZED(h1);
- h2 = heap->heap_allocated;
- DUK_HEAPHDR_SET_PREV(heap, h1, NULL);
- if (h2) {
- DUK_HEAPHDR_SET_PREV(heap, h2, h1);
- }
- DUK_HEAPHDR_SET_NEXT(heap, h1, h2);
- DUK_ASSERT_HEAPHDR_LINKS(heap, h1);
- DUK_ASSERT_HEAPHDR_LINKS(heap, h2);
- heap->heap_allocated = h1;
- } else {
- /* no -> decref members, then free */
- duk__refcount_finalize_hobject(thr, obj);
- duk_heap_free_heaphdr_raw(heap, h1);
- }
-
- count++;
- }
- DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap);
-
- DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count));
-
- /*
- * Once the whole refzero cascade has been freed, check for
- * a voluntary mark-and-sweep.
- */
-
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_VOLUNTARY_GC)
- /* 'count' is more or less comparable to normal trigger counter update
- * which happens in memory block (re)allocation.
- */
- heap->mark_and_sweep_trigger_counter -= count;
- if (heap->mark_and_sweep_trigger_counter <= 0) {
- duk_bool_t rc;
- duk_small_uint_t flags = 0; /* not emergency */
- DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep"));
- rc = duk_heap_mark_and_sweep(heap, flags);
- DUK_UNREF(rc);
- DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc));
- }
-#endif /* DUK_USE_MARK_AND_SWEEP && DUK_USE_VOLUNTARY_GC */
-}
-
-/*
- * Incref and decref functions.
- *
- * Decref may trigger immediate refzero handling, which may free and finalize
- * an arbitrary number of objects.
- *
- */
-
-DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
- duk_heap *heap;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(h != NULL);
-
- heap = thr->heap;
- DUK_DDD(DUK_DDDPRINT("refzero %p: %!O", (void *) h, (duk_heaphdr *) h));
-
- /*
- * Refzero handling is skipped entirely if (1) mark-and-sweep is
- * running or (2) execution is paused in the debugger. The objects
- * are left in the heap, and will be freed by mark-and-sweep or
- * eventual heap destruction.
- *
- * This is necessary during mark-and-sweep because refcounts are also
- * updated during the sweep phase (otherwise objects referenced by a
- * swept object would have incorrect refcounts) which then calls here.
- * This could be avoided by using separate decref macros in
- * mark-and-sweep; however, mark-and-sweep also calls finalizers which
- * would use the ordinary decref macros anyway and still call this
- * function.
- *
- * This check must be enabled also when mark-and-sweep support has been
- * disabled: the flag is also used in heap destruction when running
- * finalizers for remaining objects, and the flag prevents objects from
- * being moved around in heap linked lists.
- */
-
- /* XXX: ideally this would be just one flag (maybe a derived one) so
- * that a single bit test is sufficient to check the condition.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap))) {
-#else
- if (DUK_UNLIKELY(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap))) {
-#endif
- DUK_DDD(DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h));
- return;
- }
-
- switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
- case DUK_HTYPE_STRING:
- /*
- * Strings have no internal references but do have "weak"
- * references in the string cache. Also note that strings
- * are not on the heap_allocated list like other heap
- * elements.
- */
-
- duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
- duk_heap_string_remove(heap, (duk_hstring *) h);
- duk_heap_free_heaphdr_raw(heap, h);
- break;
-
- case DUK_HTYPE_OBJECT:
- /*
- * Objects have internal references. Must finalize through
- * the "refzero" work list.
- */
-
- duk_heap_remove_any_from_heap_allocated(heap, h);
- duk__queue_refzero(heap, h);
- duk__refzero_free_pending(thr);
- break;
-
- case DUK_HTYPE_BUFFER:
- /*
- * Buffers have no internal references. However, a dynamic
- * buffer has a separate allocation for the buffer. This is
- * freed by duk_heap_free_heaphdr_raw().
- */
-
- duk_heap_remove_any_from_heap_allocated(heap, h);
- duk_heap_free_heaphdr_raw(heap, h);
- break;
-
- default:
- DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h)));
- DUK_UNREACHABLE();
- }
-}
-
-#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- DUK_ASSERT_DISABLE(h->h_refcount >= 0);
- DUK_HEAPHDR_PREINC_REFCOUNT(h);
- }
-}
-#endif
-
-#if 0 /* unused */
-DUK_INTERNAL void duk_tval_incref_allownull(duk_tval *tv) {
- if (tv == NULL) {
- return;
- }
- if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- DUK_ASSERT_DISABLE(h->h_refcount >= 0);
- DUK_HEAPHDR_PREINC_REFCOUNT(h);
- }
-}
-#endif
-
-DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(tv != NULL);
-
- if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- duk_heaphdr_decref(thr, h);
- }
-}
-
-#if 0 /* unused */
-DUK_INTERNAL void duk_tval_decref_allownull(duk_hthread *thr, duk_tval *tv) {
- DUK_ASSERT(thr != NULL);
-
- if (tv == NULL) {
- return;
- }
- if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
- duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- duk_heaphdr_decref(thr, h);
- }
-}
-#endif
-
-#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
-DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) {
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
-
- DUK_HEAPHDR_PREINC_REFCOUNT(h);
-}
-#endif
-
-#if 0 /* unused */
-DUK_INTERNAL void duk_heaphdr_incref_allownull(duk_heaphdr *h) {
- if (h == NULL) {
- return;
- }
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
-
- DUK_HEAPHDR_PREINC_REFCOUNT(h);
-}
-#endif
-
-DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
-
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY(h)) {
- return;
- }
-#endif
- if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
- return;
- }
- duk_heaphdr_refzero(thr, h);
-}
-
-DUK_INTERNAL void duk_heaphdr_decref_allownull(duk_hthread *thr, duk_heaphdr *h) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
-
- if (h == NULL) {
- return;
- }
- DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
-
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY(h)) {
- return;
- }
-#endif
- DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
- if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
- return;
- }
- duk_heaphdr_refzero(thr, h);
-}
-
-#else
-
-/* no refcounting */
-
-#endif /* DUK_USE_REFERENCE_COUNTING */
-#line 1 "duk_heap_stringcache.c"
-/*
- * String cache.
- *
- * Provides a cache to optimize indexed string lookups. The cache keeps
- * track of (byte offset, char offset) states for a fixed number of strings.
- * Otherwise we'd need to scan from either end of the string, as we store
- * strings in (extended) UTF-8.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Delete references to given hstring from the heap string cache.
- *
- * String cache references are 'weak': they are not counted towards
- * reference counts, nor serve as roots for mark-and-sweep. When an
- * object is about to be freed, such references need to be removed.
- */
-
-DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
- duk_small_int_t i;
- for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = heap->strcache + i;
- if (c->h == h) {
- DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
- (void *) h, (void *) heap));
- c->h = NULL;
-
- /* XXX: the string shouldn't appear twice, but we now loop to the
- * end anyway; if fixed, add a looping assertion to ensure there
- * is no duplicate.
- */
- }
- }
-}
-
-/*
- * String scanning helpers
- *
- * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are
- * considered to contribute a character. This must match how string
- * character length is computed.
- */
-
-DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
- while (n > 0) {
- for (;;) {
- p++;
- if (p >= q) {
- return NULL;
- }
- if ((*p & 0xc0) != 0x80) {
- break;
- }
- }
- n--;
- }
- return p;
-}
-
-DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
- while (n > 0) {
- for (;;) {
- p--;
- if (p < q) {
- return NULL;
- }
- if ((*p & 0xc0) != 0x80) {
- break;
- }
- }
- n--;
- }
- return p;
-}
-
-/*
- * Convert char offset to byte offset
- *
- * Avoid using the string cache if possible: for ASCII strings byte and
- * char offsets are equal and for short strings direct scanning may be
- * better than using the string cache (which may evict a more important
- * entry).
- *
- * Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t).
- * Better typing might be to use duk_size_t.
- */
-
-DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
- duk_heap *heap;
- duk_strcache *sce;
- duk_uint_fast32_t byte_offset;
- duk_small_int_t i;
- duk_bool_t use_cache;
- duk_uint_fast32_t dist_start, dist_end, dist_sce;
- const duk_uint8_t *p_start;
- const duk_uint8_t *p_end;
- const duk_uint8_t *p_found;
-
- if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
- goto error;
- }
-
- /*
- * For ASCII strings, the answer is simple.
- */
-
- if (DUK_HSTRING_IS_ASCII(h)) {
- /* clen == blen -> pure ascii */
- return char_offset;
- }
-
- /*
- * For non-ASCII strings, we need to scan forwards or backwards
- * from some starting point. The starting point may be the start
- * or end of the string, or some cached midpoint in the string
- * cache.
- *
- * For "short" strings we simply scan without checking or updating
- * the cache. For longer strings we check and update the cache as
- * necessary, inserting a new cache entry if none exists.
- */
-
- DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
- (void *) h, (long) char_offset,
- (long) DUK_HSTRING_GET_CHARLEN(h),
- (long) DUK_HSTRING_GET_BYTELEN(h)));
-
- heap = thr->heap;
- sce = NULL;
- use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
-
- if (use_cache) {
-#ifdef DUK_USE_DDDPRINT
- DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
- for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = heap->strcache + i;
- DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
- (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
- }
-#endif
-
- for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = heap->strcache + i;
-
- if (c->h == h) {
- sce = c;
- break;
- }
- }
- }
-
- /*
- * Scan from shortest distance:
- * - start of string
- * - end of string
- * - cache entry (if exists)
- */
-
- DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
- dist_start = char_offset;
- dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
- dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */
-
- p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
- p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
- p_found = NULL;
-
- if (sce) {
- if (char_offset >= sce->cidx) {
- dist_sce = char_offset - sce->cidx;
- if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
- DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
- "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
- "scan forwards from sce",
- (long) use_cache, (void *) (sce ? sce->h : NULL),
- (sce ? (long) sce->cidx : (long) -1),
- (sce ? (long) sce->bidx : (long) -1),
- (long) dist_start, (long) dist_end, (long) dist_sce));
-
- p_found = duk__scan_forwards(p_start + sce->bidx,
- p_end,
- dist_sce);
- goto scan_done;
- }
- } else {
- dist_sce = sce->cidx - char_offset;
- if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
- DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
- "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
- "scan backwards from sce",
- (long) use_cache, (void *) (sce ? sce->h : NULL),
- (sce ? (long) sce->cidx : (long) -1),
- (sce ? (long) sce->bidx : (long) -1),
- (long) dist_start, (long) dist_end, (long) dist_sce));
-
- p_found = duk__scan_backwards(p_start + sce->bidx,
- p_start,
- dist_sce);
- goto scan_done;
- }
- }
- }
-
- /* no sce, or sce scan not best */
-
- if (dist_start <= dist_end) {
- DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
- "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
- "scan forwards from string start",
- (long) use_cache, (void *) (sce ? sce->h : NULL),
- (sce ? (long) sce->cidx : (long) -1),
- (sce ? (long) sce->bidx : (long) -1),
- (long) dist_start, (long) dist_end, (long) dist_sce));
-
- p_found = duk__scan_forwards(p_start,
- p_end,
- dist_start);
- } else {
- DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
- "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
- "scan backwards from string end",
- (long) use_cache, (void *) (sce ? sce->h : NULL),
- (sce ? (long) sce->cidx : (long) -1),
- (sce ? (long) sce->bidx : (long) -1),
- (long) dist_start, (long) dist_end, (long) dist_sce));
-
- p_found = duk__scan_backwards(p_end,
- p_start,
- dist_end);
- }
-
- scan_done:
-
- if (!p_found) {
- /* Scan error: this shouldn't normally happen; it could happen if
- * string is not valid UTF-8 data, and clen/blen are not consistent
- * with the scanning algorithm.
- */
- goto error;
- }
-
- DUK_ASSERT(p_found >= p_start);
- DUK_ASSERT(p_found <= p_end); /* may be equal */
- byte_offset = (duk_uint32_t) (p_found - p_start);
-
- DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
- (void *) h, (long) char_offset, (long) byte_offset));
-
- /*
- * Update cache entry (allocating if necessary), and move the
- * cache entry to the first place (in an "LRU" policy).
- */
-
- if (use_cache) {
- /* update entry, allocating if necessary */
- if (!sce) {
- sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1; /* take last entry */
- sce->h = h;
- }
- DUK_ASSERT(sce != NULL);
- sce->bidx = (duk_uint32_t) (p_found - p_start);
- sce->cidx = (duk_uint32_t) char_offset;
-
- /* LRU: move our entry to first */
- if (sce > &heap->strcache[0]) {
- /*
- * A C
- * B A
- * C <- sce ==> B
- * D D
- */
- duk_strcache tmp;
-
- tmp = *sce;
- DUK_MEMMOVE((void *) (&heap->strcache[1]),
- (const void *) (&heap->strcache[0]),
- (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
- heap->strcache[0] = tmp;
-
- /* 'sce' points to the wrong entry here, but is no longer used */
- }
-#ifdef DUK_USE_DDDPRINT
- DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
- for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
- duk_strcache *c = heap->strcache + i;
- DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
- (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
- }
-#endif
- }
-
- return byte_offset;
-
- error:
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- return 0;
-}
-#line 1 "duk_heap_stringtable.c"
-/*
- * Heap stringtable handling, string interning.
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_STRTAB_PROBE)
-#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size))
-#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash))
-#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap))
-#endif
-
-/*
- * Create a hstring and insert into the heap. The created object
- * is directly garbage collectable with reference count zero.
- *
- * The caller must place the interned string into the stringtable
- * immediately (without chance of a longjmp); otherwise the string
- * is lost.
- */
-
-DUK_LOCAL
-duk_hstring *duk__alloc_init_hstring(duk_heap *heap,
- const duk_uint8_t *str,
- duk_uint32_t blen,
- duk_uint32_t strhash,
- const duk_uint8_t *extdata) {
- duk_hstring *res = NULL;
- duk_uint8_t *data;
- duk_size_t alloc_size;
- duk_uarridx_t dummy;
- duk_uint32_t clen;
-
-#if defined(DUK_USE_STRLEN16)
- /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */
- if (blen > 0xffffUL) {
- DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern"));
- return NULL;
- }
-#endif
-
- if (extdata) {
- alloc_size = (duk_size_t) sizeof(duk_hstring_external);
- res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
- if (!res) {
- goto alloc_error;
- }
- DUK_MEMZERO(res, sizeof(duk_hstring_external));
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
-#endif
- DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA);
-
- ((duk_hstring_external *) res)->extdata = extdata;
- } else {
- /* NUL terminate for convenient C access */
- alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1);
- res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
- if (!res) {
- goto alloc_error;
- }
- DUK_MEMZERO(res, sizeof(duk_hstring));
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
-#endif
- DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
-
- data = (duk_uint8_t *) (res + 1);
- DUK_MEMCPY(data, str, blen);
- data[blen] = (duk_uint8_t) 0;
- }
-
- DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res));
- if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) {
- DUK_HSTRING_SET_ARRIDX(res);
- }
-
- /* All strings beginning with 0xff are treated as "internal",
- * even strings interned by the user. This allows user code to
- * create internal properties too, and makes behavior consistent
- * in case user code happens to use a string also used by Duktape
- * (such as string has already been interned and has the 'internal'
- * flag set).
- */
- DUK_ASSERT(!DUK_HSTRING_HAS_INTERNAL(res));
- if (blen > 0 && str[0] == (duk_uint8_t) 0xff) {
- DUK_HSTRING_SET_INTERNAL(res);
- }
-
- DUK_HSTRING_SET_HASH(res, strhash);
- DUK_HSTRING_SET_BYTELEN(res, blen);
-
- clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen);
- DUK_ASSERT(clen <= blen);
-#if defined(DUK_USE_HSTRING_CLEN)
- DUK_HSTRING_SET_CHARLEN(res, clen);
-#endif
-
- /* Using an explicit 'ASCII' flag has larger footprint (one call site
- * only) but is quite useful for the case when there's no explicit
- * 'clen' in duk_hstring.
- */
- DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
- if (clen == blen) {
- DUK_HSTRING_SET_ASCII(res);
- }
-
- DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld",
- (unsigned long) DUK_HSTRING_GET_HASH(res),
- (long) DUK_HSTRING_GET_BYTELEN(res),
- (long) DUK_HSTRING_GET_CHARLEN(res),
- (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0),
- (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0)));
-
- return res;
-
- alloc_error:
- DUK_FREE(heap, res);
- return NULL;
-}
-
-/*
- * String table algorithm: fixed size string table with array chaining
- *
- * The top level string table has a fixed size, with each slot holding
- * either NULL, string pointer, or pointer to a separately allocated
- * string pointer list.
- *
- * This is good for low memory environments using a pool allocator: the
- * top level allocation has a fixed size and the pointer lists have quite
- * small allocation size, which further matches the typical pool sizes
- * needed by objects, strings, property tables, etc.
- */
-
-#if defined(DUK_USE_STRTAB_CHAIN)
-
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_uint16_t *lst;
- duk_uint16_t *new_lst;
- duk_size_t i, n;
- duk_uint16_t null16 = heap->heapptr_null16;
- duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
-
- slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
-
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str16 == null16) {
- e->u.str16 = h16;
- } else {
- /* Now two entries in the same slot, alloc list */
- lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2);
- if (lst == NULL) {
- return 1; /* fail */
- }
- lst[0] = e->u.str16;
- lst[1] = h16;
- e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst);
- e->listlen = 2;
- }
- } else {
- DUK_ASSERT(e->u.strlist16 != null16);
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
- DUK_ASSERT(lst != NULL);
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] == null16) {
- lst[i] = h16;
- return 0;
- }
- }
-
- if (e->listlen + 1 == 0) {
- /* Overflow, relevant mainly when listlen is 16 bits. */
- return 1; /* fail */
- }
-
- new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1));
- if (new_lst == NULL) {
- return 1; /* fail */
- }
- new_lst[e->listlen++] = h16;
- e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst);
- }
- return 0;
-}
-#else /* DUK_USE_HEAPPTR16 */
-DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_hstring **lst;
- duk_hstring **new_lst;
- duk_size_t i, n;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
-
- slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
-
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str == NULL) {
- e->u.str = h;
- } else {
- /* Now two entries in the same slot, alloc list */
- lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2);
- if (lst == NULL) {
- return 1; /* fail */
- }
- lst[0] = e->u.str;
- lst[1] = h;
- e->u.strlist = lst;
- e->listlen = 2;
- }
- } else {
- DUK_ASSERT(e->u.strlist != NULL);
- lst = e->u.strlist;
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] == NULL) {
- lst[i] = h;
- return 0;
- }
- }
-
- if (e->listlen + 1 == 0) {
- /* Overflow, relevant mainly when listlen is 16 bits. */
- return 1; /* fail */
- }
-
- new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1));
- if (new_lst == NULL) {
- return 1; /* fail */
- }
- new_lst[e->listlen++] = h;
- e->u.strlist = new_lst;
- }
- return 0;
-}
-#endif /* DUK_USE_HEAPPTR16 */
-
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_uint16_t *lst;
- duk_size_t i, n;
- duk_uint16_t null16 = heap->heapptr_null16;
-
- DUK_ASSERT(heap != NULL);
-
- slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
-
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str16 != null16) {
- duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
- DUK_ASSERT(h != NULL);
- if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
- return h;
- }
- }
- } else {
- DUK_ASSERT(e->u.strlist16 != null16);
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
- DUK_ASSERT(lst != NULL);
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] != null16) {
- duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]);
- DUK_ASSERT(h != NULL);
- if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
- return h;
- }
- }
- }
- }
-
- return NULL;
-}
-#else /* DUK_USE_HEAPPTR16 */
-DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_hstring **lst;
- duk_size_t i, n;
-
- DUK_ASSERT(heap != NULL);
-
- slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
-
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str != NULL &&
- DUK_HSTRING_GET_BYTELEN(e->u.str) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) {
- return e->u.str;
- }
- } else {
- DUK_ASSERT(e->u.strlist != NULL);
- lst = e->u.strlist;
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] != NULL &&
- DUK_HSTRING_GET_BYTELEN(lst[i]) == blen &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) {
- return lst[i];
- }
- }
- }
-
- return NULL;
-}
-#endif /* DUK_USE_HEAPPTR16 */
-
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_uint16_t *lst;
- duk_size_t i, n;
- duk_uint16_t h16;
- duk_uint16_t null16 = heap->heapptr_null16;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
-
- slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
-
- DUK_ASSERT(h != NULL);
- h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- if (e->u.str16 == h16) {
- e->u.str16 = null16;
- return;
- }
- } else {
- DUK_ASSERT(e->u.strlist16 != null16);
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
- DUK_ASSERT(lst != NULL);
- for (i = 0, n = e->listlen; i < n; i++) {
- if (lst[i] == h16) {
- lst[i] = null16;
- return;
- }
- }
- }
-
- DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
- DUK_UNREACHABLE();
- return;
-}
-#else /* DUK_USE_HEAPPTR16 */
-DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
- duk_small_uint_t slotidx;
- duk_strtab_entry *e;
- duk_hstring **lst;
- duk_size_t i, n;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(h != NULL);
-
- slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
- DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
-
- e = heap->strtable + slotidx;
- if (e->listlen == 0) {
- DUK_ASSERT(h != NULL);
- if (e->u.str == h) {
- e->u.str = NULL;
- return;
- }
- } else {
- DUK_ASSERT(e->u.strlist != NULL);
- lst = e->u.strlist;
- for (i = 0, n = e->listlen; i < n; i++) {
- DUK_ASSERT(h != NULL);
- if (lst[i] == h) {
- lst[i] = NULL;
- return;
- }
- }
- }
-
- DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
- DUK_UNREACHABLE();
- return;
-}
-#endif /* DUK_USE_HEAPPTR16 */
-
-#if defined(DUK_USE_DEBUG)
-DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
- duk_strtab_entry *e;
- duk_small_uint_t i;
- duk_size_t j, n, used;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *lst;
- duk_uint16_t null16 = heap->heapptr_null16;
-#else
- duk_hstring **lst;
-#endif
-
- DUK_ASSERT(heap != NULL);
-
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
- e = heap->strtable + i;
-
- if (e->listlen == 0) {
-#if defined(DUK_USE_HEAPPTR16)
- DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0)));
-#else
- DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0)));
-#endif
- } else {
- used = 0;
-#if defined(DUK_USE_HEAPPTR16)
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
-#else
- lst = e->u.strlist;
-#endif
- DUK_ASSERT(lst != NULL);
- for (j = 0, n = e->listlen; j < n; j++) {
-#if defined(DUK_USE_HEAPPTR16)
- if (lst[j] != null16) {
-#else
- if (lst[j] != NULL) {
-#endif
- used++;
- }
- }
- DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen));
- }
- }
-}
-#endif /* DUK_USE_DEBUG */
-
-#endif /* DUK_USE_STRTAB_CHAIN */
-
-/*
- * String table algorithm: closed hashing with a probe sequence
- *
- * This is the default algorithm and works fine for environments with
- * minimal memory constraints.
- */
-
-#if defined(DUK_USE_STRTAB_PROBE)
-
-/* Count actually used (non-NULL, non-DELETED) entries. */
-DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) {
- duk_int_t res = 0;
- duk_uint_fast32_t i, n;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t null16 = heap->heapptr_null16;
- duk_uint16_t deleted16 = heap->heapptr_deleted16;
-#endif
-
- n = (duk_uint_fast32_t) heap->st_size;
- for (i = 0; i < n; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) {
-#else
- if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) {
-#endif
- res++;
- }
- }
- return res;
-}
-
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
-#else
-DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
-#endif
- duk_uint32_t i;
- duk_uint32_t step;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t null16 = heap->heapptr_null16;
- duk_uint16_t deleted16 = heap->heapptr_deleted16;
-#endif
-
- DUK_ASSERT(size > 0);
-
- i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size);
- step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h));
- for (;;) {
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t e16 = entries16[i];
-#else
- duk_hstring *e = entries[i];
-#endif
-
-#if defined(DUK_USE_HEAPPTR16)
- /* XXX: could check for e16 == 0 because NULL is guaranteed to
- * encode to zero.
- */
- if (e16 == null16) {
-#else
- if (e == NULL) {
-#endif
- DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i));
-#if defined(DUK_USE_HEAPPTR16)
- entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-#else
- entries[i] = h;
-#endif
- (*p_used)++;
- break;
-#if defined(DUK_USE_HEAPPTR16)
- } else if (e16 == deleted16) {
-#else
- } else if (e == DUK__DELETED_MARKER(heap)) {
-#endif
- /* st_used remains the same, DELETED is counted as used */
- DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i));
-#if defined(DUK_USE_HEAPPTR16)
- entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-#else
- entries[i] = h;
-#endif
- break;
- }
- DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i));
- i = (i + step) % size;
-
- /* looping should never happen */
- DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size));
- }
-}
-
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
-#else
-DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
-#endif
- duk_uint32_t i;
- duk_uint32_t step;
-
- DUK_ASSERT(size > 0);
-
- i = DUK__HASH_INITIAL(strhash, size);
- step = DUK__HASH_PROBE_STEP(strhash);
- for (;;) {
- duk_hstring *e;
-#if defined(DUK_USE_HEAPPTR16)
- e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]);
-#else
- e = entries[i];
-#endif
-
- if (!e) {
- return NULL;
- }
- if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) {
- if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) {
- DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)",
- (long) i, (long) step, (long) size));
- return e;
- }
- }
- DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)",
- (long) i, (long) step, (long) size));
- i = (i + step) % size;
-
- /* looping should never happen */
- DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size));
- }
- DUK_UNREACHABLE();
-}
-
-#if defined(DUK_USE_HEAPPTR16)
-DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) {
-#else
-DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) {
-#endif
- duk_uint32_t i;
- duk_uint32_t step;
- duk_uint32_t hash;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t null16 = heap->heapptr_null16;
- duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
-#endif
-
- DUK_ASSERT(size > 0);
-
- hash = DUK_HSTRING_GET_HASH(h);
- i = DUK__HASH_INITIAL(hash, size);
- step = DUK__HASH_PROBE_STEP(hash);
- for (;;) {
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t e16 = entries16[i];
-#else
- duk_hstring *e = entries[i];
-#endif
-
-#if defined(DUK_USE_HEAPPTR16)
- if (e16 == null16) {
-#else
- if (!e) {
-#endif
- DUK_UNREACHABLE();
- break;
- }
-#if defined(DUK_USE_HEAPPTR16)
- if (e16 == h16) {
-#else
- if (e == h) {
-#endif
- /* st_used remains the same, DELETED is counted as used */
- DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i));
-#if defined(DUK_USE_HEAPPTR16)
- entries16[i] = heap->heapptr_deleted16;
-#else
- entries[i] = DUK__DELETED_MARKER(heap);
-#endif
- break;
- }
-
- DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i));
- i = (i + step) % size;
-
- /* looping should never happen */
- DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size));
- }
-}
-
-DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) {
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_small_uint_t prev_mark_and_sweep_base_flags;
-#endif
-#ifdef DUK_USE_DEBUG
- duk_uint32_t old_used = heap->st_used;
-#endif
- duk_uint32_t old_size = heap->st_size;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *old_entries = heap->strtable16;
- duk_uint16_t *new_entries = NULL;
-#else
- duk_hstring **old_entries = heap->strtable;
- duk_hstring **new_entries = NULL;
-#endif
- duk_uint32_t new_used = 0;
- duk_uint32_t i;
-
-#ifdef DUK_USE_DEBUG
- DUK_UNREF(old_used); /* unused with some debug level combinations */
-#endif
-
-#ifdef DUK_USE_DDDPRINT
- DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
- (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
- (long) (((double) old_used) / ((double) old_size) * 100.0),
- (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap),
- (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0)));
-#endif
-
- DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */
- DUK_ASSERT(old_entries);
-#ifdef DUK_USE_MARK_AND_SWEEP
- DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
-#endif
-
- /*
- * The attempt to allocate may cause a GC. Such a GC must not attempt to resize
- * the stringtable (though it can be swept); finalizer execution and object
- * compaction must also be postponed to avoid the pressure to add strings to the
- * string table.
- */
-
-#ifdef DUK_USE_MARK_AND_SWEEP
- prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
- heap->mark_and_sweep_base_flags |= \
- DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive call here */
- DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings */
- DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */
-#endif
-
-#if defined(DUK_USE_HEAPPTR16)
- new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size);
-#else
- new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size);
-#endif
-
-#ifdef DUK_USE_MARK_AND_SWEEP
- heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
-#endif
-
- if (!new_entries) {
- goto resize_error;
- }
-
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- for (i = 0; i < new_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- new_entries[i] = heap->heapptr_null16;
-#else
- new_entries[i] = NULL;
-#endif
- }
-#else
-#if defined(DUK_USE_HEAPPTR16)
- /* Relies on NULL encoding to zero. */
- DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size);
-#else
- DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size);
-#endif
-#endif
-
- /* Because new_size > duk__count_used_probe(heap), guaranteed to work */
- for (i = 0; i < old_size; i++) {
- duk_hstring *e;
-
-#if defined(DUK_USE_HEAPPTR16)
- e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]);
-#else
- e = old_entries[i];
-#endif
- if (e == NULL || e == DUK__DELETED_MARKER(heap)) {
- continue;
- }
- /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */
- duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e);
- }
-
-#ifdef DUK_USE_DDPRINT
- DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
- (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
- (long) (((double) old_used) / ((double) old_size) * 100.0),
- (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used,
- (long) (((double) new_used) / ((double) new_size) * 100.0)));
-#endif
-
-#if defined(DUK_USE_HEAPPTR16)
- DUK_FREE(heap, heap->strtable16);
- heap->strtable16 = new_entries;
-#else
- DUK_FREE(heap, heap->strtable);
- heap->strtable = new_entries;
-#endif
- heap->st_size = new_size;
- heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */
-
- return 0; /* OK */
-
- resize_error:
- DUK_FREE(heap, new_entries);
- return 1; /* FAIL */
-}
-
-DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) {
- duk_uint32_t new_size;
- duk_bool_t ret;
-
- new_size = (duk_uint32_t) duk__count_used_probe(heap);
- if (new_size >= 0x80000000UL) {
- new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME;
- } else {
- new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size));
- new_size = duk_util_get_hash_prime(new_size);
- }
- DUK_ASSERT(new_size > 0);
-
- /* rehash even if old and new sizes are the same to get rid of
- * DELETED entries.
- */
-
- ret = duk__resize_strtab_raw_probe(heap, new_size);
-
- return ret;
-}
-
-DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) {
- duk_uint32_t new_free;
- duk_uint32_t tmp1;
- duk_uint32_t tmp2;
-
- DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */
- new_free = heap->st_size - new_used; /* unsigned intentionally */
-
- /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */
- /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */
-
- tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR;
- tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR;
-
- if (new_free <= tmp1 || new_used <= tmp2) {
- /* load factor too low or high, count actually used entries and resize */
- return duk__resize_strtab_probe(heap);
- } else {
- return 0; /* OK */
- }
-}
-
-#if defined(DUK_USE_DEBUG)
-DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
- duk_uint32_t i;
- duk_hstring *h;
-
- DUK_ASSERT(heap != NULL);
-#if defined(DUK_USE_HEAPPTR16)
- DUK_ASSERT(heap->strtable16 != NULL);
-#else
- DUK_ASSERT(heap->strtable != NULL);
-#endif
- DUK_UNREF(h);
-
- for (i = 0; i < heap->st_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]);
-#else
- h = heap->strtable[i];
-#endif
-
- DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h));
- }
-}
-#endif /* DUK_USE_DEBUG */
-
-#endif /* DUK_USE_STRTAB_PROBE */
-
-/*
- * Raw intern and lookup
- */
-
-DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
- duk_hstring *res;
- const duk_uint8_t *extdata;
-
-#if defined(DUK_USE_STRTAB_PROBE)
- if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) {
- return NULL;
- }
-#endif
-
- /* For manual testing only. */
-#if 0
- {
- duk_size_t i;
- DUK_PRINTF("INTERN: \"");
- for (i = 0; i < blen; i++) {
- duk_uint8_t x = str[i];
- if (x >= 0x20 && x <= 0x7e && x != '"' && x != '\\') {
- DUK_PRINTF("%c", (int) x); /* char: use int cast */
- } else {
- DUK_PRINTF("\\x%02lx", (long) x);
- }
- }
- DUK_PRINTF("\"\n");
- }
-#endif
-
-#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
- extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen);
-#else
- extdata = (const duk_uint8_t *) NULL;
-#endif
- res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata);
- if (!res) {
- return NULL;
- }
-
-#if defined(DUK_USE_STRTAB_CHAIN)
- if (duk__insert_hstring_chain(heap, res)) {
- /* failed */
- DUK_FREE(heap, res);
- return NULL;
- }
-#elif defined(DUK_USE_STRTAB_PROBE)
- /* guaranteed to succeed */
- duk__insert_hstring_probe(heap,
-#if defined(DUK_USE_HEAPPTR16)
- heap->strtable16,
-#else
- heap->strtable,
-#endif
- heap->st_size,
- &heap->st_used,
- res);
-#else
-#error internal error, invalid strtab options
-#endif
-
- /* Note: hstring is in heap but has refcount zero and is not strongly reachable.
- * Caller should increase refcount and make the hstring reachable before any
- * operations which require allocation (and possible gc).
- */
-
- return res;
-}
-
-DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) {
- duk_hstring *res;
-
- DUK_ASSERT(out_strhash);
-
- *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);
-
-#if defined(DUK_USE_ROM_STRINGS)
- {
- duk_small_uint_t i;
- /* XXX: This is VERY inefficient now, and should be e.g. a
- * binary search or perfect hash, to be fixed.
- */
- for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) {
- duk_hstring *romstr;
- romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]);
- if (blen == DUK_HSTRING_GET_BYTELEN(romstr) &&
- DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) {
- DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
- romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr)));
- DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr));
- *out_strhash = DUK_HSTRING_GET_HASH(romstr);
- return romstr;
- }
- }
- }
-#endif /* DUK_USE_ROM_STRINGS */
-
-#if defined(DUK_USE_STRTAB_CHAIN)
- res = duk__find_matching_string_chain(heap, str, blen, *out_strhash);
-#elif defined(DUK_USE_STRTAB_PROBE)
- res = duk__find_matching_string_probe(heap,
-#if defined(DUK_USE_HEAPPTR16)
- heap->strtable16,
-#else
- heap->strtable,
-#endif
- heap->st_size,
- str,
- blen,
- *out_strhash);
-#else
-#error internal error, invalid strtab options
-#endif
-
- return res;
-}
-
-/*
- * Exposed calls
- */
-
-#if 0 /*unused*/
-DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
- duk_uint32_t strhash; /* dummy */
- return duk__do_lookup(heap, str, blen, &strhash);
-}
-#endif
-
-DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
- duk_hstring *res;
- duk_uint32_t strhash;
-
- /* caller is responsible for ensuring this */
- DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN);
-
- res = duk__do_lookup(heap, str, blen, &strhash);
- if (res) {
- return res;
- }
-
- res = duk__do_intern(heap, str, blen, strhash);
- return res; /* may be NULL */
-}
-
-DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
- duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen);
- if (!res) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
- return res;
-}
-
-#if 0 /*unused*/
-DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) {
- char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
- DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
- buf[sizeof(buf) - 1] = (char) 0;
- DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
- return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
-}
-#endif
-
-DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) {
- char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
- DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
- buf[sizeof(buf) - 1] = (char) 0;
- DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
- return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
-}
-
-DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
- duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val);
- if (!res) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
- return res;
-}
-
-/* find and remove string from stringtable; caller must free the string itself */
-#if defined(DUK_USE_REFERENCE_COUNTING)
-DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) {
- DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h));
-
-#if defined(DUK_USE_STRTAB_CHAIN)
- duk__remove_matching_hstring_chain(heap, h);
-#elif defined(DUK_USE_STRTAB_PROBE)
- duk__remove_matching_hstring_probe(heap,
-#if defined(DUK_USE_HEAPPTR16)
- heap->strtable16,
-#else
- heap->strtable,
-#endif
- heap->st_size,
- h);
-#else
-#error internal error, invalid strtab options
-#endif
-}
-#endif
-
-#if defined(DUK_USE_MARK_AND_SWEEP) && defined(DUK_USE_MS_STRINGTABLE_RESIZE)
-DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) {
- /* Force a resize so that DELETED entries are eliminated.
- * Another option would be duk__recheck_strtab_size_probe();
- * but since that happens on every intern anyway, this whole
- * check can now be disabled.
- */
-#if defined(DUK_USE_STRTAB_CHAIN)
- DUK_UNREF(heap);
-#elif defined(DUK_USE_STRTAB_PROBE)
- duk__resize_strtab_probe(heap);
-#endif
-}
-#endif
-
-#if defined(DUK_USE_STRTAB_CHAIN)
-DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
- /* Free strings in the stringtable and any allocations needed
- * by the stringtable itself.
- */
- duk_uint_fast32_t i, j;
- duk_strtab_entry *e;
-#if defined(DUK_USE_HEAPPTR16)
- duk_uint16_t *lst;
- duk_uint16_t null16 = heap->heapptr_null16;
-#else
- duk_hstring **lst;
-#endif
- duk_hstring *h;
-
- for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
- e = heap->strtable + i;
- if (e->listlen > 0) {
-#if defined(DUK_USE_HEAPPTR16)
- lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
-#else
- lst = e->u.strlist;
-#endif
- DUK_ASSERT(lst != NULL);
-
- for (j = 0; j < e->listlen; j++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
- lst[j] = null16;
-#else
- h = lst[j];
- lst[j] = NULL;
-#endif
- /* strings may have inner refs (extdata) in some cases */
- if (h != NULL) {
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
- }
- }
-#if defined(DUK_USE_HEAPPTR16)
- e->u.strlist16 = null16;
-#else
- e->u.strlist = NULL;
-#endif
- DUK_FREE(heap, lst);
- } else {
-#if defined(DUK_USE_HEAPPTR16)
- h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
- e->u.str16 = null16;
-#else
- h = e->u.str;
- e->u.str = NULL;
-#endif
- if (h != NULL) {
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
- }
- }
- e->listlen = 0;
- }
-}
-#endif /* DUK_USE_STRTAB_CHAIN */
-
-#if defined(DUK_USE_STRTAB_PROBE)
-DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
- duk_uint_fast32_t i;
- duk_hstring *h;
-
-#if defined(DUK_USE_HEAPPTR16)
- if (heap->strtable16) {
-#else
- if (heap->strtable) {
-#endif
- for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
-#if defined(DUK_USE_HEAPPTR16)
- h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
-#else
- h = heap->strtable[i];
-#endif
- if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
- continue;
- }
- DUK_ASSERT(h != NULL);
-
- /* strings may have inner refs (extdata) in some cases */
- duk_free_hstring_inner(heap, h);
- DUK_FREE(heap, h);
-#if 0 /* not strictly necessary */
- heap->strtable[i] = NULL;
-#endif
- }
-#if defined(DUK_USE_HEAPPTR16)
- DUK_FREE(heap, heap->strtable16);
-#else
- DUK_FREE(heap, heap->strtable);
-#endif
-#if 0 /* not strictly necessary */
- heap->strtable = NULL;
-#endif
- }
-}
-#endif /* DUK_USE_STRTAB_PROBE */
-
-/* Undefine local defines */
-#undef DUK__HASH_INITIAL
-#undef DUK__HASH_PROBE_STEP
-#undef DUK__DELETED_MARKER
-#line 1 "duk_hobject_alloc.c"
-/*
- * Hobject allocation.
- *
- * Provides primitive allocation functions for all object types (plain object,
- * compiled function, native function, thread). The object return is not yet
- * in "heap allocated" list and has a refcount of zero, so caller must careful.
- */
-
-/* include removed: duk_internal.h */
-
-DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) {
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
-#endif
-
- /* XXX: macro? sets both heaphdr and object flags */
- obj->hdr.h_flags = hobject_flags;
- DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */
-
-#if defined(DUK_USE_HEAPPTR16)
- /* Zero encoded pointer is required to match NULL */
- DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
-#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
- DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
-#endif
-#endif
- DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr);
- DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
-
- /*
- * obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
- * with this properly. This is intentional: empty objects consume a minimum
- * amount of memory. Further, an initial allocation might fail and cause
- * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
- */
-}
-
-/*
- * Allocate an duk_hobject.
- *
- * The allocated object has no allocation for properties; the caller may
- * want to force a resize if a desired size is known.
- *
- * The allocated object has zero reference count and is not reachable.
- * The caller MUST make the object reachable and increase its reference
- * count before invoking any operation that might require memory allocation.
- */
-
-DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
- duk_hobject *res;
-
- DUK_ASSERT(heap != NULL);
-
- /* different memory layout, alloc size, and init */
- DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPILEDFUNCTION) == 0);
- DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATIVEFUNCTION) == 0);
- DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_THREAD) == 0);
-
- res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject));
- if (!res) {
- return NULL;
- }
- DUK_MEMZERO(res, sizeof(duk_hobject));
-
- duk__init_object_parts(heap, res, hobject_flags);
-
- return res;
-}
-
-DUK_INTERNAL duk_hcompiledfunction *duk_hcompiledfunction_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
- duk_hcompiledfunction *res;
-
- res = (duk_hcompiledfunction *) DUK_ALLOC(heap, sizeof(duk_hcompiledfunction));
- if (!res) {
- return NULL;
- }
- DUK_MEMZERO(res, sizeof(duk_hcompiledfunction));
-
- duk__init_object_parts(heap, &res->obj, hobject_flags);
-
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
-#ifdef DUK_USE_HEAPPTR16
- /* NULL pointer is required to encode to zero, so memset is enough. */
-#else
- res->data = NULL;
- res->funcs = NULL;
- res->bytecode = NULL;
-#endif
-#endif
-
- return res;
-}
-
-DUK_INTERNAL duk_hnativefunction *duk_hnativefunction_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
- duk_hnativefunction *res;
-
- res = (duk_hnativefunction *) DUK_ALLOC(heap, sizeof(duk_hnativefunction));
- if (!res) {
- return NULL;
- }
- DUK_MEMZERO(res, sizeof(duk_hnativefunction));
-
- duk__init_object_parts(heap, &res->obj, hobject_flags);
-
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- res->func = NULL;
-#endif
-
- return res;
-}
-
-DUK_INTERNAL duk_hbufferobject *duk_hbufferobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
- duk_hbufferobject *res;
-
- res = (duk_hbufferobject *) DUK_ALLOC(heap, sizeof(duk_hbufferobject));
- if (!res) {
- return NULL;
- }
- DUK_MEMZERO(res, sizeof(duk_hbufferobject));
-
- duk__init_object_parts(heap, &res->obj, hobject_flags);
-
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- res->buf = NULL;
-#endif
-
- DUK_ASSERT_HBUFFEROBJECT_VALID(res);
- return res;
-}
-
-/*
- * Allocate a new thread.
- *
- * Leaves the built-ins array uninitialized. The caller must either
- * initialize a new global context or share existing built-ins from
- * another thread.
- */
-
-DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
- duk_hthread *res;
-
- res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
- if (!res) {
- return NULL;
- }
- DUK_MEMZERO(res, sizeof(duk_hthread));
-
- duk__init_object_parts(heap, &res->obj, hobject_flags);
-
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- res->ptr_curr_pc = NULL;
- res->heap = NULL;
- res->valstack = NULL;
- res->valstack_end = NULL;
- res->valstack_bottom = NULL;
- res->valstack_top = NULL;
- res->callstack = NULL;
- res->catchstack = NULL;
- res->resumer = NULL;
- res->compile_ctx = NULL,
-#ifdef DUK_USE_HEAPPTR16
- res->strs16 = NULL;
-#else
- res->strs = NULL;
-#endif
- {
- int i;
- for (i = 0; i < DUK_NUM_BUILTINS; i++) {
- res->builtins[i] = NULL;
- }
- }
-#endif
- /* when nothing is running, API calls are in non-strict mode */
- DUK_ASSERT(res->strict == 0);
-
- res->heap = heap;
- res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
- res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
- res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;
-
- return res;
-}
-
-#if 0 /* unused now */
-DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) {
- duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags);
- if (!res) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
- return res;
-}
-#endif
-#line 1 "duk_hobject_enum.c"
-/*
- * Hobject enumeration support.
- *
- * Creates an internal enumeration state object to be used e.g. with for-in
- * enumeration. The state object contains a snapshot of target object keys
- * and internal control state for enumeration. Enumerator flags allow caller
- * to e.g. request internal/non-enumerable properties, and to enumerate only
- * "own" properties.
- *
- * Also creates the result value for e.g. Object.keys() based on the same
- * internal structure.
- *
- * This snapshot-based enumeration approach is used to simplify enumeration:
- * non-snapshot-based approaches are difficult to reconcile with mutating
- * the enumeration target, running multiple long-lived enumerators at the
- * same time, garbage collection details, etc. The downside is that the
- * enumerator object is memory inefficient especially for iterating arrays.
- */
-
-/* include removed: duk_internal.h */
-
-/* XXX: identify enumeration target with an object index (not top of stack) */
-
-/* must match exactly the number of internal properties inserted to enumerator */
-#define DUK__ENUM_START_INDEX 2
-
-DUK_LOCAL const duk_uint16_t duk__bufferobject_virtual_props[] = {
- DUK_STRIDX_LENGTH,
- DUK_STRIDX_BYTE_LENGTH,
- DUK_STRIDX_BYTE_OFFSET,
- DUK_STRIDX_BYTES_PER_ELEMENT
-};
-
-/*
- * Helper to sort array index keys. The keys are in the enumeration object
- * entry part, starting from DUK__ENUM_START_INDEX, and the entry part is dense.
- *
- * We use insertion sort because it is simple (leading to compact code,)
- * works nicely in-place, and minimizes operations if data is already sorted
- * or nearly sorted (which is a very common case here). It also minimizes
- * the use of element comparisons in general. This is nice because element
- * comparisons here involve re-parsing the string keys into numbers each
- * time, which is naturally very expensive.
- *
- * Note that the entry part values are all "true", e.g.
- *
- * "1" -> true, "3" -> true, "2" -> true
- *
- * so it suffices to only work in the key part without exchanging any keys,
- * simplifying the sort.
- *
- * http://en.wikipedia.org/wiki/Insertion_sort
- *
- * (Compiles to about 160 bytes now as a stand-alone function.)
- */
-
-DUK_LOCAL void duk__sort_array_indices(duk_hthread *thr, duk_hobject *h_obj) {
- duk_hstring **keys;
- duk_hstring **p_curr, **p_insert, **p_end;
- duk_hstring *h_curr;
- duk_uarridx_t val_highest, val_curr, val_insert;
-
- DUK_ASSERT(h_obj != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(h_obj) >= 2); /* control props */
- DUK_UNREF(thr);
-
- if (DUK_HOBJECT_GET_ENEXT(h_obj) <= 1 + DUK__ENUM_START_INDEX) {
- return;
- }
-
- keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
- p_end = keys + DUK_HOBJECT_GET_ENEXT(h_obj);
- keys += DUK__ENUM_START_INDEX;
-
- DUK_DDD(DUK_DDDPRINT("keys=%p, p_end=%p (after skipping enum props)",
- (void *) keys, (void *) p_end));
-
-#ifdef DUK_USE_DDDPRINT
- {
- duk_uint_fast32_t i;
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h_obj); i++) {
- DUK_DDD(DUK_DDDPRINT("initial: %ld %p -> %!O",
- (long) i,
- (void *) DUK_HOBJECT_E_GET_KEY_PTR(thr->heap, h_obj, i),
- (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(thr->heap, h_obj, i)));
- }
- }
-#endif
-
- val_highest = DUK_HSTRING_GET_ARRIDX_SLOW(keys[0]);
- for (p_curr = keys + 1; p_curr < p_end; p_curr++) {
- DUK_ASSERT(*p_curr != NULL);
- val_curr = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
-
- if (val_curr >= val_highest) {
- DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
- "already in correct order, next",
- (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
- val_highest = val_curr;
- continue;
- }
-
- DUK_DDD(DUK_DDDPRINT("p_curr=%p, p_end=%p, val_highest=%ld, val_curr=%ld -> "
- "needs to be inserted",
- (void *) p_curr, (void *) p_end, (long) val_highest, (long) val_curr));
-
- /* Needs to be inserted; scan backwards, since we optimize
- * for the case where elements are nearly in order.
- */
-
- p_insert = p_curr - 1;
- for (;;) {
- val_insert = DUK_HSTRING_GET_ARRIDX_SLOW(*p_insert);
- if (val_insert < val_curr) {
- DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> insert after this",
- (void *) p_insert, (long) val_insert, (long) val_curr));
- p_insert++;
- break;
- }
- if (p_insert == keys) {
- DUK_DDD(DUK_DDDPRINT("p_insert=%p -> out of keys, insert to beginning", (void *) p_insert));
- break;
- }
- DUK_DDD(DUK_DDDPRINT("p_insert=%p, val_insert=%ld, val_curr=%ld -> search backwards",
- (void *) p_insert, (long) val_insert, (long) val_curr));
- p_insert--;
- }
-
- DUK_DDD(DUK_DDDPRINT("final p_insert=%p", (void *) p_insert));
-
- /* .-- p_insert .-- p_curr
- * v v
- * | ... | insert | ... | curr
- */
-
- h_curr = *p_curr;
- DUK_DDD(DUK_DDDPRINT("memmove: dest=%p, src=%p, size=%ld, h_curr=%p",
- (void *) (p_insert + 1), (void *) p_insert,
- (long) (p_curr - p_insert), (void *) h_curr));
-
- DUK_MEMMOVE((void *) (p_insert + 1),
- (const void *) p_insert,
- (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
- *p_insert = h_curr;
- /* keep val_highest */
- }
-
-#ifdef DUK_USE_DDDPRINT
- {
- duk_uint_fast32_t i;
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h_obj); i++) {
- DUK_DDD(DUK_DDDPRINT("final: %ld %p -> %!O",
- (long) i,
- (void *) DUK_HOBJECT_E_GET_KEY_PTR(thr->heap, h_obj, i),
- (duk_heaphdr *) DUK_HOBJECT_E_GET_KEY(thr->heap, h_obj, i)));
- }
- }
-#endif
-}
-
-/*
- * Create an internal enumerator object E, which has its keys ordered
- * to match desired enumeration ordering. Also initialize internal control
- * properties for enumeration.
- *
- * Note: if an array was used to hold enumeration keys instead, an array
- * scan would be needed to eliminate duplicates found in the prototype chain.
- */
-
-DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *enum_target;
- duk_hobject *curr;
- duk_hobject *res;
-#if defined(DUK_USE_ES6_PROXY)
- duk_hobject *h_proxy_target;
- duk_hobject *h_proxy_handler;
- duk_hobject *h_trap_result;
-#endif
- duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */
-
- DUK_ASSERT(ctx != NULL);
-
- DUK_DDD(DUK_DDDPRINT("create enumerator, stack top: %ld", (long) duk_get_top(ctx)));
-
- enum_target = duk_require_hobject(ctx, -1);
- DUK_ASSERT(enum_target != NULL);
-
- duk_push_object_internal(ctx);
- res = duk_require_hobject(ctx, -1);
-
- DUK_DDD(DUK_DDDPRINT("created internal object"));
-
- /* [enum_target res] */
-
- /* Target must be stored so that we can recheck whether or not
- * keys still exist when we enumerate. This is not done if the
- * enumeration result comes from a proxy trap as there is no
- * real object to check against.
- */
- duk_push_hobject(ctx, enum_target);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_TARGET);
-
- /* Initialize index so that we skip internal control keys. */
- duk_push_int(ctx, DUK__ENUM_START_INDEX);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
-
- /*
- * Proxy object handling
- */
-
-#if defined(DUK_USE_ES6_PROXY)
- if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
- goto skip_proxy;
- }
- if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
- enum_target,
- &h_proxy_target,
- &h_proxy_handler))) {
- goto skip_proxy;
- }
-
- DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
- duk_push_hobject(ctx, h_proxy_handler);
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_ENUMERATE)) {
- /* No need to replace the 'enum_target' value in stack, only the
- * enum_target reference. This also ensures that the original
- * enum target is reachable, which keeps the proxy and the proxy
- * target reachable. We do need to replace the internal _Target.
- */
- DUK_DDD(DUK_DDDPRINT("no enumerate trap, enumerate proxy target instead"));
- DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
- enum_target = h_proxy_target;
-
- duk_push_hobject(ctx, enum_target); /* -> [ ... enum_target res handler undefined target ] */
- duk_put_prop_stridx(ctx, -4, DUK_STRIDX_INT_TARGET);
-
- duk_pop_2(ctx); /* -> [ ... enum_target res ] */
- goto skip_proxy;
- }
-
- /* [ ... enum_target res handler trap ] */
- duk_insert(ctx, -2);
- duk_push_hobject(ctx, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
- duk_call_method(ctx, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
- h_trap_result = duk_require_hobject(ctx, -1);
- DUK_UNREF(h_trap_result);
-
- /* Copy trap result keys into the enumerator object. */
- len = (duk_uint_fast32_t) duk_get_length(ctx, -1);
- for (i = 0; i < len; i++) {
- /* XXX: not sure what the correct semantic details are here,
- * e.g. handling of missing values (gaps), handling of non-array
- * trap results, etc.
- *
- * For keys, we simply skip non-string keys which seems to be
- * consistent with how e.g. Object.keys() will process proxy trap
- * results (ES6, Section 19.1.2.14).
- */
- if (duk_get_prop_index(ctx, -1, i) && duk_is_string(ctx, -1)) {
- /* [ ... enum_target res trap_result val ] */
- duk_push_true(ctx);
- /* [ ... enum_target res trap_result val true ] */
- duk_put_prop(ctx, -4);
- } else {
- duk_pop(ctx);
- }
- }
- /* [ ... enum_target res trap_result ] */
- duk_pop(ctx);
- duk_remove(ctx, -2);
-
- /* [ ... res ] */
-
- /* The internal _Target property is kept pointing to the original
- * enumeration target (the proxy object), so that the enumerator
- * 'next' operation can read property values if so requested. The
- * fact that the _Target is a proxy disables key existence check
- * during enumeration.
- */
- DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O", (duk_heaphdr *) res));
- goto compact_and_return;
-
- skip_proxy:
-#endif /* DUK_USE_ES6_PROXY */
-
- curr = enum_target;
- while (curr) {
- /*
- * Virtual properties.
- *
- * String and buffer indices are virtual and always enumerable,
- * 'length' is virtual and non-enumerable. Array and arguments
- * object props have special behavior but are concrete.
- */
-
- if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) ||
- DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
- /* String and buffer enumeration behavior is identical now,
- * so use shared handler.
- */
- if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
- duk_hstring *h_val;
- h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
- DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
- len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val);
- } else {
- duk_hbufferobject *h_bufobj;
- DUK_ASSERT(DUK_HOBJECT_IS_BUFFEROBJECT(curr));
- h_bufobj = (duk_hbufferobject *) curr;
- if (h_bufobj == NULL) {
- /* Neutered buffer, zero length seems
- * like good behavior here.
- */
- len = 0;
- } else {
- /* There's intentionally no check for
- * current underlying buffer length.
- */
- len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift);
- }
- }
-
- for (i = 0; i < len; i++) {
- duk_hstring *k;
-
- k = duk_heap_string_intern_u32_checked(thr, i);
- DUK_ASSERT(k);
- duk_push_hstring(ctx, k);
- duk_push_true(ctx);
-
- /* [enum_target res key true] */
- duk_put_prop(ctx, -3);
-
- /* [enum_target res] */
- }
-
- /* 'length' and other virtual properties are not
- * enumerable, but are included if non-enumerable
- * properties are requested.
- */
-
- if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
- duk_uint_fast32_t n;
-
- if (DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
- n = sizeof(duk__bufferobject_virtual_props) / sizeof(duk_uint16_t);
- } else {
- DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr));
- DUK_ASSERT(duk__bufferobject_virtual_props[0] == DUK_STRIDX_LENGTH);
- n = 1; /* only 'length' */
- }
-
- for (i = 0; i < n; i++) {
- duk_push_hstring_stridx(ctx, duk__bufferobject_virtual_props[i]);
- duk_push_true(ctx);
- duk_put_prop(ctx, -3);
- }
-
- }
- } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(curr)) {
- if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
- duk_push_true(ctx);
- duk_put_prop(ctx, -3);
- }
- }
-
- /*
- * Array part
- *
- * Note: ordering between array and entry part must match 'abandon array'
- * behavior in duk_hobject_props.c: key order after an array is abandoned
- * must be the same.
- */
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) {
- duk_hstring *k;
- duk_tval *tv;
-
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i);
- if (DUK_TVAL_IS_UNUSED(tv)) {
- continue;
- }
- k = duk_heap_string_intern_u32_checked(thr, i);
- DUK_ASSERT(k);
-
- duk_push_hstring(ctx, k);
- duk_push_true(ctx);
-
- /* [enum_target res key true] */
- duk_put_prop(ctx, -3);
-
- /* [enum_target res] */
- }
-
- /*
- * Entries part
- */
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) {
- duk_hstring *k;
-
- k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i);
- if (!k) {
- continue;
- }
- if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i) &&
- !(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
- continue;
- }
- if (DUK_HSTRING_HAS_INTERNAL(k) &&
- !(enum_flags & DUK_ENUM_INCLUDE_INTERNAL)) {
- continue;
- }
- if ((enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) &&
- (DUK_HSTRING_GET_ARRIDX_SLOW(k) == DUK_HSTRING_NO_ARRAY_INDEX)) {
- continue;
- }
-
- DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
- !DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
-
- duk_push_hstring(ctx, k);
- duk_push_true(ctx);
-
- /* [enum_target res key true] */
- duk_put_prop(ctx, -3);
-
- /* [enum_target res] */
- }
-
- if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
- break;
- }
-
- curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
- }
-
- /* [enum_target res] */
-
- duk_remove(ctx, -2);
-
- /* [res] */
-
- if ((enum_flags & (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) ==
- (DUK_ENUM_ARRAY_INDICES_ONLY | DUK_ENUM_SORT_ARRAY_INDICES)) {
- /*
- * Some E5/E5.1 algorithms require that array indices are iterated
- * in a strictly ascending order. This is the case for e.g.
- * Array.prototype.forEach() and JSON.stringify() PropertyList
- * handling.
- *
- * To ensure this property for arrays with an array part (and
- * arbitrary objects too, since e.g. forEach() can be applied
- * to an array), the caller can request that we sort the keys
- * here.
- */
-
- /* XXX: avoid this at least when enum_target is an Array, it has an
- * array part, and no ancestor properties were included? Not worth
- * it for JSON, but maybe worth it for forEach().
- */
-
- /* XXX: may need a 'length' filter for forEach()
- */
- DUK_DDD(DUK_DDDPRINT("sort array indices by caller request"));
- duk__sort_array_indices(thr, res);
- }
-
-#if defined(DUK_USE_ES6_PROXY)
- compact_and_return:
-#endif
- /* compact; no need to seal because object is internal */
- duk_hobject_compact_props(thr, res);
-
- DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
-}
-
-/*
- * Returns non-zero if a key and/or value was enumerated, and:
- *
- * [enum] -> [key] (get_value == 0)
- * [enum] -> [key value] (get_value == 1)
- *
- * Returns zero without pushing anything on the stack otherwise.
- */
-DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *e;
- duk_hobject *enum_target;
- duk_hstring *res = NULL;
- duk_uint_fast32_t idx;
- duk_bool_t check_existence;
-
- DUK_ASSERT(ctx != NULL);
-
- /* [... enum] */
-
- e = duk_require_hobject(ctx, -1);
-
- /* XXX use get tval ptr, more efficient */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_NEXT);
- idx = (duk_uint_fast32_t) duk_require_uint(ctx, -1);
- duk_pop(ctx);
- DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
-
- /* Enumeration keys are checked against the enumeration target (to see
- * that they still exist). In the proxy enumeration case _Target will
- * be the proxy, and checking key existence against the proxy is not
- * required (or sensible, as the keys may be fully virtual).
- */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET);
- enum_target = duk_require_hobject(ctx, -1);
- DUK_ASSERT(enum_target != NULL);
-#if defined(DUK_USE_ES6_PROXY)
- check_existence = (!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(enum_target));
-#else
- check_existence = 1;
-#endif
- duk_pop(ctx); /* still reachable */
-
- DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
- (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* no array part */
- for (;;) {
- duk_hstring *k;
-
- if (idx >= DUK_HOBJECT_GET_ENEXT(e)) {
- DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements"));
- break;
- }
-
- /* we know these because enum objects are internally created */
- k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx);
- DUK_ASSERT(k != NULL);
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx));
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v));
-
- idx++;
-
- /* recheck that the property still exists */
- if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) {
- DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip"));
- continue;
- }
-
- DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O", (duk_heaphdr *) k));
- res = k;
- break;
- }
-
- DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
-
- duk_push_u32(ctx, (duk_uint32_t) idx);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_INT_NEXT);
-
- /* [... enum] */
-
- if (res) {
- duk_push_hstring(ctx, res);
- if (get_value) {
- duk_push_hobject(ctx, enum_target);
- duk_dup(ctx, -2); /* -> [... enum key enum_target key] */
- duk_get_prop(ctx, -2); /* -> [... enum key enum_target val] */
- duk_remove(ctx, -2); /* -> [... enum key val] */
- duk_remove(ctx, -3); /* -> [... key val] */
- } else {
- duk_remove(ctx, -2); /* -> [... key] */
- }
- return 1;
- } else {
- duk_pop(ctx); /* -> [...] */
- return 0;
- }
-}
-
-/*
- * Get enumerated keys in an Ecmascript array. Matches Object.keys() behavior
- * described in E5 Section 15.2.3.14.
- */
-
-DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *e;
- duk_uint_fast32_t i;
- duk_uint_fast32_t idx;
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(duk_get_hobject(ctx, -1) != NULL);
- DUK_UNREF(thr);
-
- /* Create a temporary enumerator to get the (non-duplicated) key list;
- * the enumerator state is initialized without being needed, but that
- * has little impact.
- */
-
- duk_hobject_enumerator_create(ctx, enum_flags);
- duk_push_array(ctx);
-
- /* [enum_target enum res] */
-
- e = duk_require_hobject(ctx, -2);
- DUK_ASSERT(e != NULL);
-
- idx = 0;
- for (i = DUK__ENUM_START_INDEX; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(e); i++) {
- duk_hstring *k;
-
- k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, i);
- DUK_ASSERT(k); /* enumerator must have no keys deleted */
-
- /* [enum_target enum res] */
- duk_push_hstring(ctx, k);
- duk_put_prop_index(ctx, -2, idx);
- idx++;
- }
-
- /* [enum_target enum res] */
- duk_remove(ctx, -2);
-
- /* [enum_target res] */
-
- return 1; /* return 1 to allow callers to tail call */
-}
-#line 1 "duk_hobject_finalizer.c"
-/*
- * Run an duk_hobject finalizer. Used for both reference counting
- * and mark-and-sweep algorithms. Must never throw an error.
- *
- * There is no return value. Any return value or error thrown by
- * the finalizer is ignored (although errors are debug logged).
- *
- * Notes:
- *
- * - The thread used for calling the finalizer is the same as the
- * 'thr' argument. This may need to change later.
- *
- * - The finalizer thread 'top' assertions are there because it is
- * critical that strict stack policy is observed (i.e. no cruft
- * left on the finalizer stack).
- */
-
-/* include removed: duk_internal.h */
-
-DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx) {
- duk_hthread *thr;
-
- DUK_ASSERT(ctx != NULL);
- thr = (duk_hthread *) ctx;
-
- DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
-
- /* [... obj] */
-
- /* XXX: Finalizer lookup should traverse the prototype chain (to allow
- * inherited finalizers) but should not invoke accessors or proxy object
- * behavior. At the moment this lookup will invoke proxy behavior, so
- * caller must ensure that this function is not called if the target is
- * a Proxy.
- */
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
- if (!duk_is_callable(ctx, -1)) {
- DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable"));
- return 0;
- }
- duk_dup(ctx, -2);
- duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
- DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer"));
- duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
- DUK_DDD(DUK_DDDPRINT("finalizer finished successfully"));
- return 0;
-
- /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
- * so we don't need to pop stuff here. There is no return value;
- * caller determines rescued status based on object refcount.
- */
-}
-
-DUK_INTERNAL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
- duk_ret_t rc;
-#ifdef DUK_USE_ASSERTIONS
- duk_idx_t entry_top;
-#endif
-
- DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT_VALSTACK_SPACE(thr, 1);
-
-#ifdef DUK_USE_ASSERTIONS
- entry_top = duk_get_top(ctx);
-#endif
- /*
- * Get and call the finalizer. All of this must be wrapped
- * in a protected call, because even getting the finalizer
- * may trigger an error (getter may throw one, for instance).
- */
-
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
- if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
- DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
- return;
- }
- DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
- /* This shouldn't happen; call sites should avoid looking up
- * _Finalizer "through" a Proxy, but ignore if we come here
- * with a Proxy to avoid finalizer re-entry.
- */
- DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call"));
- return;
- }
-
- /* XXX: use a NULL error handler for the finalizer call? */
-
- DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper"));
- duk_push_hobject(ctx, obj); /* this also increases refcount by one */
- rc = duk_safe_call(ctx, duk__finalize_helper, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
- DUK_ASSERT_TOP(ctx, entry_top + 2); /* duk_safe_call discipline */
-
- if (rc != DUK_EXEC_SUCCESS) {
- /* Note: we ask for one return value from duk_safe_call to get this
- * error debugging here.
- */
- DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
- (void *) obj, (duk_tval *) duk_get_tval(ctx, -1)));
- }
- duk_pop_2(ctx); /* -> [...] */
-
- DUK_ASSERT_TOP(ctx, entry_top);
-}
-#line 1 "duk_hobject_misc.c"
-/*
- * Misc support functions
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) {
- duk_uint_t sanity;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(h != NULL);
- /* allow 'p' to be NULL; then the result is always false */
-
- sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
- do {
- if (h == p) {
- return 1;
- }
-
- if (sanity-- == 0) {
- if (ignore_loop) {
- break;
- } else {
- DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
- }
- }
- h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
- } while (h);
-
- return 0;
-}
-
-DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk_hobject *tmp;
-
- DUK_ASSERT(h);
- tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
- DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
-#else
- DUK_ASSERT(h);
- DUK_UNREF(thr);
- DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
-#endif
-}
-#line 1 "duk_hobject_pc2line.c"
-/*
- * Helpers for creating and querying pc2line debug data, which
- * converts a bytecode program counter to a source line number.
- *
- * The run-time pc2line data is bit-packed, and documented in:
- *
- * doc/function-objects.rst
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_PC2LINE)
-
-/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
-DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
- duk_context *ctx = (duk_context *) thr;
- duk_hbuffer_dynamic *h_buf;
- duk_bitencoder_ctx be_ctx_alloc;
- duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
- duk_uint32_t *hdr;
- duk_size_t new_size;
- duk_uint_fast32_t num_header_entries;
- duk_uint_fast32_t curr_offset;
- duk_int_fast32_t curr_line, next_line, diff_line;
- duk_uint_fast32_t curr_pc;
- duk_uint_fast32_t hdr_index;
-
- DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
-
- /* XXX: add proper spare handling to dynamic buffer, to minimize
- * reallocs; currently there is no spare at all.
- */
-
- num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
- curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
-
- duk_push_dynamic_buffer(ctx, (duk_size_t) curr_offset);
- h_buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_buf != NULL);
- DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
-
- hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
- DUK_ASSERT(hdr != NULL);
- hdr[0] = (duk_uint32_t) length; /* valid pc range is [0, length[ */
-
- curr_pc = 0U;
- while (curr_pc < length) {
- new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH);
- duk_hbuffer_resize(thr, h_buf, new_size);
-
- hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
- DUK_ASSERT(hdr != NULL);
- DUK_ASSERT(curr_pc < length);
- hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2;
- curr_line = (duk_int_fast32_t) instrs[curr_pc].line;
- hdr[hdr_index + 0] = (duk_uint32_t) curr_line;
- hdr[hdr_index + 1] = (duk_uint32_t) curr_offset;
-
-#if 0
- DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld",
- (long) (curr_pc / DUK_PC2LINE_SKIP),
- (long) curr_pc,
- (long) hdr[hdr_index + 0],
- (long) hdr[hdr_index + 1]));
-#endif
-
- DUK_MEMZERO(be_ctx, sizeof(*be_ctx));
- be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
- be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
-
- for (;;) {
- curr_pc++;
- if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) || /* end of diff run */
- (curr_pc >= length) ) { /* end of bytecode */
- break;
- }
- DUK_ASSERT(curr_pc < length);
- next_line = (duk_int32_t) instrs[curr_pc].line;
- diff_line = next_line - curr_line;
-
-#if 0
- DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld",
- (long) curr_line, (long) next_line, (long) diff_line));
-#endif
-
- if (diff_line == 0) {
- /* 0 */
- duk_be_encode(be_ctx, 0, 1);
- } else if (diff_line >= 1 && diff_line <= 4) {
- /* 1 0 <2 bits> */
- duk_be_encode(be_ctx, (0x02 << 2) + (diff_line - 1), 4);
- } else if (diff_line >= -0x80 && diff_line <= 0x7f) {
- /* 1 1 0 <8 bits> */
- DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
- duk_be_encode(be_ctx, (0x06 << 8) + (diff_line + 0x80), 11);
- } else {
- /* 1 1 1 <32 bits>
- * Encode in two parts to avoid bitencode 24-bit limitation
- */
- duk_be_encode(be_ctx, (0x07 << 16) + ((next_line >> 16) & 0xffffU), 19);
- duk_be_encode(be_ctx, next_line & 0xffffU, 16);
- }
-
- curr_line = next_line;
- }
-
- duk_be_finish(be_ctx);
- DUK_ASSERT(!be_ctx->truncated);
-
- /* be_ctx->offset == length of encoded bitstream */
- curr_offset += (duk_uint_fast32_t) be_ctx->offset;
- }
-
- /* compact */
- new_size = (duk_size_t) curr_offset;
- duk_hbuffer_resize(thr, h_buf, new_size);
-
- (void) duk_to_fixed_buffer(ctx, -1, NULL);
-
- DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
- (long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
- (duk_tval *) duk_get_tval(ctx, -1)));
-}
-
-/* PC is unsigned. If caller does PC arithmetic and gets a negative result,
- * it will map to a large PC which is out of bounds and causes a zero to be
- * returned.
- */
-DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) {
- duk_bitdecoder_ctx bd_ctx_alloc;
- duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc;
- duk_uint32_t *hdr;
- duk_uint_fast32_t start_offset;
- duk_uint_fast32_t pc_limit;
- duk_uint_fast32_t hdr_index;
- duk_uint_fast32_t pc_base;
- duk_uint_fast32_t n;
- duk_uint_fast32_t curr_line;
-
- DUK_ASSERT(buf != NULL);
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf));
- DUK_UNREF(thr);
-
- /*
- * Use the index in the header to find the right starting point
- */
-
- hdr_index = pc / DUK_PC2LINE_SKIP;
- pc_base = hdr_index * DUK_PC2LINE_SKIP;
- n = pc - pc_base;
-
- if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
- DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header"));
- goto error;
- }
-
- hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf);
- pc_limit = hdr[0];
- if (pc >= pc_limit) {
- /* Note: pc is unsigned and cannot be negative */
- DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)",
- (long) pc, (long) pc_limit));
- goto error;
- }
-
- curr_line = hdr[1 + hdr_index * 2];
- start_offset = hdr[1 + hdr_index * 2 + 1];
- if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
- DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)",
- (long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf)));
- goto error;
- }
-
- /*
- * Iterate the bitstream (line diffs) until PC is reached
- */
-
- DUK_MEMZERO(bd_ctx, sizeof(*bd_ctx));
- bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
- bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
-
-#if 0
- DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld",
- (long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset));
-#endif
-
- while (n > 0) {
-#if 0
- DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld", (long) n, (long) curr_line));
-#endif
-
- if (duk_bd_decode_flag(bd_ctx)) {
- if (duk_bd_decode_flag(bd_ctx)) {
- if (duk_bd_decode_flag(bd_ctx)) {
- /* 1 1 1 <32 bits> */
- duk_uint_fast32_t t;
- t = duk_bd_decode(bd_ctx, 16); /* workaround: max nbits = 24 now */
- t = (t << 16) + duk_bd_decode(bd_ctx, 16);
- curr_line = t;
- } else {
- /* 1 1 0 <8 bits> */
- duk_uint_fast32_t t;
- t = duk_bd_decode(bd_ctx, 8);
- curr_line = curr_line + t - 0x80;
- }
- } else {
- /* 1 0 <2 bits> */
- duk_uint_fast32_t t;
- t = duk_bd_decode(bd_ctx, 2);
- curr_line = curr_line + t + 1;
- }
- } else {
- /* 0: no change */
- }
-
- n--;
- }
-
- DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line));
- return curr_line;
-
- error:
- DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc));
- return 0;
-}
-
-DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc) {
- duk_hbuffer_fixed *pc2line;
- duk_uint_fast32_t line;
-
- /* XXX: now that pc2line is used by the debugger quite heavily in
- * checked execution, this should be optimized to avoid value stack
- * and perhaps also implement some form of pc2line caching (see
- * future work in debugger.rst).
- */
-
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_PC2LINE);
- pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
- if (pc2line != NULL) {
- DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
- line = duk__hobject_pc2line_query_raw((duk_hthread *) ctx, pc2line, (duk_uint_fast32_t) pc);
- } else {
- line = 0;
- }
- duk_pop(ctx);
-
- return line;
-}
-
-#endif /* DUK_USE_PC2LINE */
-#line 1 "duk_hobject_props.c"
-/*
- * Hobject property set/get functionality.
- *
- * This is very central functionality for size, performance, and compliance.
- * It is also rather intricate; see hobject-algorithms.rst for discussion on
- * the algorithms and memory-management.rst for discussion on refcounts and
- * side effect issues.
- *
- * Notes:
- *
- * - It might be tempting to assert "refcount nonzero" for objects
- * being operated on, but that's not always correct: objects with
- * a zero refcount may be operated on by the refcount implementation
- * (finalization) for instance. Hence, no refcount assertions are made.
- *
- * - Many operations (memory allocation, identifier operations, etc)
- * may cause arbitrary side effects (e.g. through GC and finalization).
- * These side effects may invalidate duk_tval pointers which point to
- * areas subject to reallocation (like value stack). Heap objects
- * themselves have stable pointers. Holding heap object pointers or
- * duk_tval copies is not problematic with respect to side effects;
- * care must be taken when holding and using argument duk_tval pointers.
- *
- * - If a finalizer is executed, it may operate on the the same object
- * we're currently dealing with. For instance, the finalizer might
- * delete a certain property which has already been looked up and
- * confirmed to exist. Ideally finalizers would be disabled if GC
- * happens during property access. At the moment property table realloc
- * disables finalizers, and all DECREFs may cause arbitrary changes so
- * handle DECREF carefully.
- *
- * - The order of operations for a DECREF matters. When DECREF is executed,
- * the entire object graph must be consistent; note that a refzero may
- * lead to a mark-and-sweep through a refcount finalizer.
- */
-
-/*
- * XXX: array indices are mostly typed as duk_uint32_t here; duk_uarridx_t
- * might be more appropriate.
- */
-
-/*
- * XXX: duk_uint_fast32_t should probably be used in many places here.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Local defines
- */
-
-#define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX
-
-/* hash probe sequence */
-#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size))
-#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash))
-
-/* marker values for hash part */
-#define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED
-#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED
-
-/* valstack space that suffices for all local calls, including recursion
- * of other than Duktape calls (getters etc)
- */
-#define DUK__VALSTACK_SPACE 10
-
-/* valstack space allocated especially for proxy lookup which does a
- * recursive property lookup
- */
-#define DUK__VALSTACK_PROXY_LOOKUP 20
-
-/*
- * Local prototypes
- */
-
-DUK_LOCAL_DECL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
-DUK_LOCAL_DECL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag);
-DUK_LOCAL_DECL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
-
-DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr, duk_hobject *obj, duk_uint32_t old_len, duk_uint32_t new_len, duk_bool_t force_flag, duk_uint32_t *out_result_len);
-DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj);
-
-DUK_LOCAL_DECL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags);
-DUK_LOCAL_DECL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags);
-DUK_LOCAL duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc);
-
-/*
- * Misc helpers
- */
-
-/* Convert a duk_tval number (caller checks) to a 32-bit index. Returns
- * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array
- * index.
- */
-/* XXX: for fastints, could use a variant which assumes a double duk_tval
- * (and doesn't need to check for fastint again).
- */
-DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) {
- duk_double_t dbl;
- duk_uint32_t idx;
-
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
-
- /* -0 is accepted here as index 0 because ToString(-0) == "0" which is
- * in canonical form and thus an array index.
- */
- dbl = DUK_TVAL_GET_NUMBER(tv);
- idx = (duk_uint32_t) dbl;
- if ((duk_double_t) idx == dbl) {
- /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF,
- * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX.
- */
- return idx;
- }
- return DUK__NO_ARRAY_INDEX;
-}
-
-#if defined(DUK_USE_FASTINT)
-/* Convert a duk_tval fastint (caller checks) to a 32-bit index. */
-DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
- duk_int64_t t;
-
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
-
- t = DUK_TVAL_GET_FASTINT(tv);
- if ((t & ~0xffffffffULL) != 0) {
- /* Catches >0x100000000 and negative values. */
- return DUK__NO_ARRAY_INDEX;
- }
-
- /* If the value happens to be 0xFFFFFFFF, it's not a valid array index
- * but will then match DUK__NO_ARRAY_INDEX.
- */
- return (duk_uint32_t) t;
-}
-#endif /* DUK_USE_FASTINT */
-
-/* Push an arbitrary duk_tval to the stack, coerce it to string, and return
- * both a duk_hstring pointer and an array index (or DUK__NO_ARRAY_INDEX).
- */
-DUK_LOCAL duk_uint32_t duk__push_tval_to_hstring_arr_idx(duk_context *ctx, duk_tval *tv, duk_hstring **out_h) {
- duk_uint32_t arr_idx;
- duk_hstring *h;
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(out_h != NULL);
-
- duk_push_tval(ctx, tv);
- duk_to_string(ctx, -1);
- h = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h != NULL);
- *out_h = h;
-
- arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h);
- return arr_idx;
-}
-
-/* String is an own (virtual) property of a lightfunc. */
-DUK_LOCAL duk_bool_t duk__key_is_lightfunc_ownprop(duk_hthread *thr, duk_hstring *key) {
- DUK_UNREF(thr);
- return (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_NAME(thr));
-}
-
-/*
- * Helpers for managing property storage size
- */
-
-/* Get default hash part size for a certain entry part size. */
-#if defined(DUK_USE_HOBJECT_HASH_PART)
-DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) {
- DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
-
- if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
- duk_uint32_t res;
-
- /* result: hash_prime(floor(1.2 * e_size)) */
- res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR);
-
- /* if fails, e_size will be zero = not an issue, except performance-wise */
- DUK_ASSERT(res == 0 || res > e_size);
- return res;
- } else {
- return 0;
- }
-}
-#endif /* USE_PROP_HASH_PART */
-
-/* Get minimum entry part growth for a certain size. */
-DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) {
- duk_uint32_t res;
-
- DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
-
- res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR;
- DUK_ASSERT(res >= 1); /* important for callers */
- return res;
-}
-
-/* Get minimum array part growth for a certain size. */
-DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) {
- duk_uint32_t res;
-
- DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES);
-
- res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR;
- DUK_ASSERT(res >= 1); /* important for callers */
- return res;
-}
-
-/* Count actually used entry part entries (non-NULL keys). */
-DUK_LOCAL duk_uint32_t duk__count_used_e_keys(duk_hthread *thr, duk_hobject *obj) {
- duk_uint_fast32_t i;
- duk_uint_fast32_t n = 0;
- duk_hstring **e;
-
- DUK_ASSERT(obj != NULL);
- DUK_UNREF(thr);
-
- e = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, obj);
- for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
- if (*e++) {
- n++;
- }
- }
- return (duk_uint32_t) n;
-}
-
-/* Count actually used array part entries and array minimum size.
- * NOTE: 'out_min_size' can be computed much faster by starting from the
- * end and breaking out early when finding first used entry, but this is
- * not needed now.
- */
-DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) {
- duk_uint_fast32_t i;
- duk_uint_fast32_t used = 0;
- duk_uint_fast32_t highest_idx = (duk_uint_fast32_t) -1; /* see below */
- duk_tval *a;
-
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(out_used != NULL);
- DUK_ASSERT(out_min_size != NULL);
- DUK_UNREF(thr);
-
- a = DUK_HOBJECT_A_GET_BASE(thr->heap, obj);
- for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
- duk_tval *tv = a++;
- if (!DUK_TVAL_IS_UNUSED(tv)) {
- used++;
- highest_idx = i;
- }
- }
-
- /* Initial value for highest_idx is -1 coerced to unsigned. This
- * is a bit odd, but (highest_idx + 1) will then wrap to 0 below
- * for out_min_size as intended.
- */
-
- *out_used = used;
- *out_min_size = highest_idx + 1; /* 0 if no used entries */
-}
-
-/* Check array density and indicate whether or not the array part should be abandoned. */
-DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) {
- /*
- * Array abandon check; abandon if:
- *
- * new_used / new_size < limit
- * new_used < limit * new_size || limit is 3 bits fixed point
- * new_used < limit' / 8 * new_size || *8
- * 8*new_used < limit' * new_size || :8
- * new_used < limit' * (new_size / 8)
- *
- * Here, new_used = a_used, new_size = a_size.
- *
- * Note: some callers use approximate values for a_used and/or a_size
- * (e.g. dropping a '+1' term). This doesn't affect the usefulness
- * of the check, but may confuse debugging.
- */
-
- return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3));
-}
-
-/* Fast check for extending array: check whether or not a slow density check is required. */
-DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) {
- /*
- * In a fast check we assume old_size equals old_used (i.e., existing
- * array is fully dense).
- *
- * Slow check if:
- *
- * (new_size - old_size) / old_size > limit
- * new_size - old_size > limit * old_size
- * new_size > (1 + limit) * old_size || limit' is 3 bits fixed point
- * new_size > (1 + (limit' / 8)) * old_size || * 8
- * 8 * new_size > (8 + limit') * old_size || : 8
- * new_size > (8 + limit') * (old_size / 8)
- * new_size > limit'' * (old_size / 8) || limit'' = 9 -> max 25% increase
- * arr_idx + 1 > limit'' * (old_size / 8)
- *
- * This check doesn't work well for small values, so old_size is rounded
- * up for the check (and the '+ 1' of arr_idx can be ignored in practice):
- *
- * arr_idx > limit'' * ((old_size + 7) / 8)
- */
-
- return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
-}
-
-/*
- * Proxy helpers
- */
-
-#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
- duk_tval *tv_target;
- duk_tval *tv_handler;
- duk_hobject *h_target;
- duk_hobject *h_handler;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(out_target != NULL);
- DUK_ASSERT(out_handler != NULL);
-
- /* Caller doesn't need to check exotic proxy behavior (but does so for
- * some fast paths).
- */
- if (DUK_LIKELY(!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
- return 0;
- }
-
- tv_handler = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_HANDLER(thr));
- if (!tv_handler) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_handler));
- h_handler = DUK_TVAL_GET_OBJECT(tv_handler);
- DUK_ASSERT(h_handler != NULL);
- *out_handler = h_handler;
- tv_handler = NULL; /* avoid issues with relocation */
-
- tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_TARGET(thr));
- if (!tv_target) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
- h_target = DUK_TVAL_GET_OBJECT(tv_target);
- DUK_ASSERT(h_target != NULL);
- *out_target = h_target;
- tv_target = NULL; /* avoid issues with relocation */
-
- return 1;
-}
-#endif /* DUK_USE_ES6_PROXY */
-
-/* Get Proxy target object. If the argument is not a Proxy, return it as is.
- * If a Proxy is revoked, an error is thrown.
- */
-#if defined(DUK_USE_ES6_PROXY)
-DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj) {
- duk_hobject *h_target;
- duk_hobject *h_handler;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
-
- /* Resolve Proxy targets until Proxy chain ends. No explicit check for
- * a Proxy loop: user code cannot create such a loop without tweaking
- * internal properties directly.
- */
-
- while (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
- if (duk_hobject_proxy_check(thr, obj, &h_target, &h_handler)) {
- DUK_ASSERT(h_target != NULL);
- obj = h_target;
- } else {
- break;
- }
- }
-
- DUK_ASSERT(obj != NULL);
- return obj;
-}
-#endif /* DUK_USE_ES6_PROXY */
-
-#if defined(DUK_USE_ES6_PROXY)
-DUK_LOCAL duk_bool_t duk__proxy_check_prop(duk_hthread *thr, duk_hobject *obj, duk_small_uint_t stridx_trap, duk_tval *tv_key, duk_hobject **out_target) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *h_handler;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(tv_key != NULL);
- DUK_ASSERT(out_target != NULL);
-
- if (!duk_hobject_proxy_check(thr, obj, out_target, &h_handler)) {
- return 0;
- }
- DUK_ASSERT(*out_target != NULL);
- DUK_ASSERT(h_handler != NULL);
-
- /* XXX: At the moment Duktape accesses internal keys like _Finalizer using a
- * normal property set/get which would allow a proxy handler to interfere with
- * such behavior and to get access to internal key strings. This is not a problem
- * as such because internal key strings can be created in other ways too (e.g.
- * through buffers). The best fix is to change Duktape internal lookups to
- * skip proxy behavior. Until that, internal property accesses bypass the
- * proxy and are applied to the target (as if the handler did not exist).
- * This has some side effects, see test-bi-proxy-internal-keys.js.
- */
-
- if (DUK_TVAL_IS_STRING(tv_key)) {
- duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key);
- DUK_ASSERT(h_key != NULL);
- if (DUK_HSTRING_HAS_INTERNAL(h_key)) {
- DUK_DDD(DUK_DDDPRINT("internal key, skip proxy handler and apply to target"));
- return 0;
- }
- }
-
- /* The handler is looked up with a normal property lookup; it may be an
- * accessor or the handler object itself may be a proxy object. If the
- * handler is a proxy, we need to extend the valstack as we make a
- * recursive proxy check without a function call in between (in fact
- * there is no limit to the potential recursion here).
- *
- * (For sanity, proxy creation rejects another proxy object as either
- * the handler or the target at the moment so recursive proxy cases
- * are not realized now.)
- */
-
- /* XXX: C recursion limit if proxies are allowed as handler/target values */
-
- duk_require_stack(ctx, DUK__VALSTACK_PROXY_LOOKUP);
- duk_push_hobject(ctx, h_handler);
- if (duk_get_prop_stridx(ctx, -1, stridx_trap)) {
- /* -> [ ... handler trap ] */
- duk_insert(ctx, -2); /* -> [ ... trap handler ] */
-
- /* stack prepped for func call: [ ... trap handler ] */
- return 1;
- } else {
- duk_pop_2(ctx);
- return 0;
- }
-}
-#endif /* DUK_USE_ES6_PROXY */
-
-/*
- * Reallocate property allocation, moving properties to the new allocation.
- *
- * Includes key compaction, rehashing, and can also optionally abandoning
- * the array part, 'migrating' array entries into the beginning of the
- * new entry part. Arguments are not validated here, so e.g. new_h_size
- * MUST be a valid prime.
- *
- * There is no support for in-place reallocation or just compacting keys
- * without resizing the property allocation. This is intentional to keep
- * code size minimal.
- *
- * The implementation is relatively straightforward, except for the array
- * abandonment process. Array abandonment requires that new string keys
- * are interned, which may trigger GC. All keys interned so far must be
- * reachable for GC at all times; valstack is used for that now.
- *
- * Also, a GC triggered during this reallocation process must not interfere
- * with the object being resized. This is currently controlled by using
- * heap->mark_and_sweep_base_flags to indicate that no finalizers will be
- * executed (as they can affect ANY object) and no objects are compacted
- * (it would suffice to protect this particular object only, though).
- *
- * Note: a non-checked variant would be nice but is a bit tricky to
- * implement for the array abandonment process. It's easy for
- * everything else.
- *
- * Note: because we need to potentially resize the valstack (as part
- * of abandoning the array part), any tval pointers to the valstack
- * will become invalid after this call.
- */
-
-DUK_LOCAL
-void duk__realloc_props(duk_hthread *thr,
- duk_hobject *obj,
- duk_uint32_t new_e_size,
- duk_uint32_t new_a_size,
- duk_uint32_t new_h_size,
- duk_bool_t abandon_array) {
- duk_context *ctx = (duk_context *) thr;
-#ifdef DUK_USE_MARK_AND_SWEEP
- duk_small_uint_t prev_mark_and_sweep_base_flags;
-#endif
- duk_uint32_t new_alloc_size;
- duk_uint32_t new_e_size_adjusted;
- duk_uint8_t *new_p;
- duk_hstring **new_e_k;
- duk_propvalue *new_e_pv;
- duk_uint8_t *new_e_f;
- duk_tval *new_a;
- duk_uint32_t *new_h;
- duk_uint32_t new_e_next;
- duk_uint_fast32_t i;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0));
- DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size); /* required to guarantee success of rehashing,
- * intentionally use unadjusted new_e_size
- */
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /*
- * Pre resize assertions.
- */
-
-#ifdef DUK_USE_ASSERTIONS
- /* XXX: pre-checks (such as no duplicate keys) */
-#endif
-
- /*
- * For property layout 1, tweak e_size to ensure that the whole entry
- * part (key + val + flags) is a suitable multiple for alignment
- * (platform specific).
- *
- * Property layout 2 does not require this tweaking and is preferred
- * on low RAM platforms requiring alignment.
- */
-
-#if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3)
- DUK_DDD(DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %ld", (long) new_e_size));
- new_e_size_adjusted = new_e_size;
-#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1)
- DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size));
- new_e_size_adjusted = new_e_size;
-#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
- new_e_size_adjusted = (new_e_size + DUK_HOBJECT_ALIGN_TARGET - 1) & (~(DUK_HOBJECT_ALIGN_TARGET - 1));
- DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld",
- (long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted));
- DUK_ASSERT(new_e_size_adjusted >= new_e_size);
-#else
-#error invalid hobject layout defines
-#endif
-
- /*
- * Debug logging after adjustment.
- */
-
- DUK_DDD(DUK_DDDPRINT("attempt to resize hobject %p props (%ld -> %ld bytes), from {p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld} to "
- "{e_size=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
- (void *) obj,
- (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
- DUK_HOBJECT_GET_ASIZE(obj),
- DUK_HOBJECT_GET_HSIZE(obj)),
- (long) DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size),
- (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
- (long) DUK_HOBJECT_GET_ESIZE(obj),
- (long) DUK_HOBJECT_GET_ENEXT(obj),
- (long) DUK_HOBJECT_GET_ASIZE(obj),
- (long) DUK_HOBJECT_GET_HSIZE(obj),
- (long) new_e_size_adjusted,
- (long) new_a_size,
- (long) new_h_size,
- (long) abandon_array,
- (long) new_e_size));
-
- /*
- * Property count check. This is the only point where we ensure that
- * we don't get more (allocated) property space that we can handle.
- * There aren't hard limits as such, but some algorithms fail (e.g.
- * finding next higher prime, selecting hash part size) if we get too
- * close to the 4G property limit.
- *
- * Since this works based on allocation size (not actually used size),
- * the limit is a bit approximate but good enough in practice.
- */
-
- if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
-
- /*
- * Compute new alloc size and alloc new area.
- *
- * The new area is allocated as a dynamic buffer and placed into the
- * valstack for reachability. The actual buffer is then detached at
- * the end.
- *
- * Note: heap_mark_and_sweep_base_flags are altered here to ensure
- * no-one touches this object while we're resizing and rehashing it.
- * The flags must be reset on every exit path after it. Finalizers
- * and compaction is prevented currently for all objects while it
- * would be enough to restrict it only for the current object.
- */
-
-#ifdef DUK_USE_MARK_AND_SWEEP
- prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
- thr->heap->mark_and_sweep_base_flags |=
- DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
- DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */
-#endif
-
- new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size);
- DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size));
- if (new_alloc_size == 0) {
- /* for zero size, don't push anything on valstack */
- DUK_ASSERT(new_e_size_adjusted == 0);
- DUK_ASSERT(new_a_size == 0);
- DUK_ASSERT(new_h_size == 0);
- new_p = NULL;
- } else {
- /* This may trigger mark-and-sweep with arbitrary side effects,
- * including an attempted resize of the object we're resizing,
- * executing a finalizer which may add or remove properties of
- * the object we're resizing etc.
- */
-
- /* Note: buffer is dynamic so that we can 'steal' the actual
- * allocation later.
- */
-
- new_p = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, new_alloc_size); /* errors out if out of memory */
- DUK_ASSERT(new_p != NULL); /* since new_alloc_size > 0 */
- }
-
- /* Set up pointers to the new property area: this is hidden behind a macro
- * because it is memory layout specific.
- */
- DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h,
- new_e_size_adjusted, new_a_size, new_h_size);
- DUK_UNREF(new_h); /* happens when hash part dropped */
- new_e_next = 0;
-
- /* if new_p == NULL, all of these pointers are NULL */
- DUK_ASSERT((new_p != NULL) ||
- (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL &&
- new_a == NULL && new_h == NULL));
-
- DUK_DDD(DUK_DDDPRINT("new alloc size %ld, new_e_k=%p, new_e_pv=%p, new_e_f=%p, new_a=%p, new_h=%p",
- (long) new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f,
- (void *) new_a, (void *) new_h));
-
- /*
- * Migrate array to start of entries if requested.
- *
- * Note: from an enumeration perspective the order of entry keys matters.
- * Array keys should appear wherever they appeared before the array abandon
- * operation.
- */
-
- if (abandon_array) {
- /*
- * Note: assuming new_a_size == 0, and that entry part contains
- * no conflicting keys, refcounts do not need to be adjusted for
- * the values, as they remain exactly the same.
- *
- * The keys, however, need to be interned, incref'd, and be
- * reachable for GC. Any intern attempt may trigger a GC and
- * claim any non-reachable strings, so every key must be reachable
- * at all times.
- *
- * A longjmp must not occur here, as the new_p allocation would
- * be freed without these keys being decref'd, hence the messy
- * decref handling if intern fails.
- */
- DUK_ASSERT(new_a_size == 0);
-
- for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
- duk_tval *tv1;
- duk_tval *tv2;
- duk_hstring *key;
-
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
-
- tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
- if (DUK_TVAL_IS_UNUSED(tv1)) {
- continue;
- }
-
- DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
- new_e_pv != NULL && new_e_f != NULL);
-
- /*
- * Intern key via the valstack to ensure reachability behaves
- * properly. We must avoid longjmp's here so use non-checked
- * primitives.
- *
- * Note: duk_check_stack() potentially reallocs the valstack,
- * invalidating any duk_tval pointers to valstack. Callers
- * must be careful.
- */
-
- /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */
- if (!duk_check_stack(ctx, 1)) {
- goto abandon_error;
- }
- DUK_ASSERT_VALSTACK_SPACE(thr, 1);
- key = duk_heap_string_intern_u32(thr->heap, i);
- if (!key) {
- goto abandon_error;
- }
- duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */
-
- /* key is now reachable in the valstack */
-
- DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */
- new_e_k[new_e_next] = key;
- tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */
- DUK_TVAL_SET_TVAL(tv2, tv1);
- new_e_f[new_e_next] = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE |
- DUK_PROPDESC_FLAG_CONFIGURABLE;
- new_e_next++;
-
- /* Note: new_e_next matches pushed temp key count, and nothing can
- * fail above between the push and this point.
- */
- }
-
- DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next));
- duk_pop_n(ctx, new_e_next);
- }
-
- /*
- * Copy keys and values in the entry part (compacting them at the same time).
- */
-
- for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
- duk_hstring *key;
-
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
-
- key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
- if (!key) {
- continue;
- }
-
- DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
- new_e_pv != NULL && new_e_f != NULL);
-
- new_e_k[new_e_next] = key;
- new_e_pv[new_e_next] = DUK_HOBJECT_E_GET_VALUE(thr->heap, obj, i);
- new_e_f[new_e_next] = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
- new_e_next++;
- }
- /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */
-
- /*
- * Copy array elements to new array part.
- */
-
- if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) {
- /* copy existing entries as is */
- DUK_ASSERT(new_p != NULL && new_a != NULL);
- if (DUK_HOBJECT_GET_ASIZE(obj) > 0) {
- /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
- * the 'new_a' pointer will be invalid which is not allowed even
- * when copy size is zero.
- */
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0);
- DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj));
- }
-
- /* fill new entries with -unused- (required, gc reachable) */
- for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
- duk_tval *tv = &new_a[i];
- DUK_TVAL_SET_UNUSED(tv);
- }
- } else {
-#ifdef DUK_USE_ASSERTIONS
- /* caller must have decref'd values above new_a_size (if that is necessary) */
- if (!abandon_array) {
- for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
- duk_tval *tv;
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
-
- /* current assertion is quite strong: decref's and set to unused */
- DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
- }
- }
-#endif
- if (new_a_size > 0) {
- /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
- * the 'new_a' pointer will be invalid which is not allowed even
- * when copy size is zero.
- */
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
- DUK_ASSERT(new_a_size > 0);
- DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size);
- }
- }
-
- /*
- * Rebuild the hash part always from scratch (guaranteed to finish).
- *
- * Any resize of hash part requires rehashing. In addition, by rehashing
- * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical
- * to ensuring the hash part never fills up.
- */
-
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- if (DUK_UNLIKELY(new_h_size > 0)) {
- DUK_ASSERT(new_h != NULL);
-
- /* fill new_h with u32 0xff = UNUSED */
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
- DUK_ASSERT(new_h_size > 0);
- DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
-
- DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */
- for (i = 0; i < new_e_next; i++) {
- duk_hstring *key = new_e_k[i];
- duk_uint32_t j, step;
-
- DUK_ASSERT(key != NULL);
- j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size);
- step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
-
- for (;;) {
- DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */
- if (new_h[j] == DUK__HASH_UNUSED) {
- DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i));
- new_h[j] = i;
- break;
- }
- DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step));
- j = (j + step) % new_h_size;
-
- /* guaranteed to finish */
- DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size));
- }
- }
- } else {
- DUK_DDD(DUK_DDDPRINT("no hash part, no rehash"));
- }
-#endif /* DUK_USE_HOBJECT_HASH_PART */
-
- /*
- * Nice debug log.
- */
-
- DUK_DD(DUK_DDPRINT("resized hobject %p props (%ld -> %ld bytes), from {p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld} to "
- "{p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
- (void *) obj,
- (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
- DUK_HOBJECT_GET_ASIZE(obj),
- DUK_HOBJECT_GET_HSIZE(obj)),
- (long) new_alloc_size,
- (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
- (long) DUK_HOBJECT_GET_ESIZE(obj),
- (long) DUK_HOBJECT_GET_ENEXT(obj),
- (long) DUK_HOBJECT_GET_ASIZE(obj),
- (long) DUK_HOBJECT_GET_HSIZE(obj),
- (void *) new_p,
- (long) new_e_size_adjusted,
- (long) new_e_next,
- (long) new_a_size,
- (long) new_h_size,
- (long) abandon_array,
- (long) new_e_size));
-
- /*
- * All done, switch properties ('p') allocation to new one.
- */
-
- DUK_FREE(thr->heap, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
- DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p);
- DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted);
- DUK_HOBJECT_SET_ENEXT(obj, new_e_next);
- DUK_HOBJECT_SET_ASIZE(obj, new_a_size);
- DUK_HOBJECT_SET_HSIZE(obj, new_h_size);
-
- if (new_p) {
- /*
- * Detach actual buffer from dynamic buffer in valstack, and
- * pop it from the stack.
- *
- * XXX: the buffer object is certainly not reachable at this point,
- * so it would be nice to free it forcibly even with only
- * mark-and-sweep enabled. Not a big issue though.
- */
- (void) duk_steal_buffer(ctx, -1, NULL);
- duk_pop(ctx);
- } else {
- DUK_ASSERT(new_alloc_size == 0);
- /* no need to pop, nothing was pushed */
- }
-
- /* clear array part flag only after switching */
- if (abandon_array) {
- DUK_HOBJECT_CLEAR_ARRAY_PART(obj);
- }
-
- DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj));
-
-#ifdef DUK_USE_MARK_AND_SWEEP
- thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
-#endif
-
- /*
- * Post resize assertions.
- */
-
-#ifdef DUK_USE_ASSERTIONS
- /* XXX: post-checks (such as no duplicate keys) */
-#endif
- return;
-
- /*
- * Abandon array failed, need to decref keys already inserted
- * into the beginning of new_e_k before unwinding valstack.
- */
-
- abandon_error:
- DUK_D(DUK_DPRINT("hobject resize failed during abandon array, decref keys"));
- i = new_e_next;
- while (i > 0) {
- i--;
- DUK_ASSERT(new_e_k != NULL);
- DUK_ASSERT(new_e_k[i] != NULL);
- DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */
- }
-
-#ifdef DUK_USE_MARK_AND_SWEEP
- thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
-#endif
-
- DUK_ERROR_ALLOC_DEFMSG(thr);
-}
-
-/*
- * Helpers to resize properties allocation on specific needs.
- */
-
-/* Grow entry part allocation for one additional entry. */
-DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
- duk_uint32_t old_e_used; /* actually used, non-NULL entries */
- duk_uint32_t new_e_size;
- duk_uint32_t new_a_size;
- duk_uint32_t new_h_size;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
-
- /* Duktape 0.11.0 and prior tried to optimize the resize by not
- * counting the number of actually used keys prior to the resize.
- * This worked mostly well but also caused weird leak-like behavior
- * as in: test-bug-object-prop-alloc-unbounded.js. So, now we count
- * the keys explicitly to compute the new entry part size.
- */
-
- old_e_used = duk__count_used_e_keys(thr, obj);
- new_e_size = old_e_used + duk__get_min_grow_e(old_e_used);
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- new_h_size = duk__get_default_h_size(new_e_size);
-#else
- new_h_size = 0;
-#endif
- new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
- DUK_ASSERT(new_e_size >= old_e_used + 1); /* duk__get_min_grow_e() is always >= 1 */
-
- duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
-}
-
-/* Grow array part for a new highest array index. */
-DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) {
- duk_uint32_t new_e_size;
- duk_uint32_t new_a_size;
- duk_uint32_t new_h_size;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(highest_arr_idx >= DUK_HOBJECT_GET_ASIZE(obj));
-
- /* minimum new length is highest_arr_idx + 1 */
-
- new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
- new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
- new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx);
- DUK_ASSERT(new_a_size >= highest_arr_idx + 1); /* duk__get_min_grow_a() is always >= 1 */
-
- duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
-}
-
-/* Abandon array part, moving array entries into entries part.
- * This requires a props resize, which is a heavy operation.
- * We also compact the entries part while we're at it, although
- * this is not strictly required.
- */
-DUK_LOCAL void duk__abandon_array_checked(duk_hthread *thr, duk_hobject *obj) {
- duk_uint32_t new_e_size;
- duk_uint32_t new_a_size;
- duk_uint32_t new_h_size;
- duk_uint32_t e_used; /* actually used, non-NULL keys */
- duk_uint32_t a_used;
- duk_uint32_t a_size;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
-
- e_used = duk__count_used_e_keys(thr, obj);
- duk__compute_a_stats(thr, obj, &a_used, &a_size);
-
- /*
- * Must guarantee all actually used array entries will fit into
- * new entry part. Add one growth step to ensure we don't run out
- * of space right away.
- */
-
- new_e_size = e_used + a_used;
- new_e_size = new_e_size + duk__get_min_grow_e(new_e_size);
- new_a_size = 0;
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- new_h_size = duk__get_default_h_size(new_e_size);
-#else
- new_h_size = 0;
-#endif
-
- DUK_DD(DUK_DDPRINT("abandon array part for hobject %p, "
- "array stats before: e_used=%ld, a_used=%ld, a_size=%ld; "
- "resize to e_size=%ld, a_size=%ld, h_size=%ld",
- (void *) obj, (long) e_used, (long) a_used, (long) a_size,
- (long) new_e_size, (long) new_a_size, (long) new_h_size));
-
- duk__realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
-}
-
-/*
- * Compact an object. Minimizes allocation size for objects which are
- * not likely to be extended. This is useful for internal and non-
- * extensible objects, but can also be called for non-extensible objects.
- * May abandon the array part if it is computed to be too sparse.
- *
- * This call is relatively expensive, as it needs to scan both the
- * entries and the array part.
- *
- * The call may fail due to allocation error.
- */
-
-DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) {
- duk_uint32_t e_size; /* currently used -> new size */
- duk_uint32_t a_size; /* currently required */
- duk_uint32_t a_used; /* actually used */
- duk_uint32_t h_size;
- duk_bool_t abandon_array;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
-
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
- DUK_DD(DUK_DDPRINT("ignore attempt to compact a rom object"));
- return;
- }
-#endif
-
- e_size = duk__count_used_e_keys(thr, obj);
- duk__compute_a_stats(thr, obj, &a_used, &a_size);
-
- DUK_DD(DUK_DDPRINT("compacting hobject, used e keys %ld, used a keys %ld, min a size %ld, "
- "resized array density would be: %ld/%ld = %lf",
- (long) e_size, (long) a_used, (long) a_size,
- (long) a_used, (long) a_size,
- (double) a_used / (double) a_size));
-
- if (duk__abandon_array_density_check(a_used, a_size)) {
- DUK_DD(DUK_DDPRINT("decided to abandon array during compaction, a_used=%ld, a_size=%ld",
- (long) a_used, (long) a_size));
- abandon_array = 1;
- e_size += a_used;
- a_size = 0;
- } else {
- DUK_DD(DUK_DDPRINT("decided to keep array during compaction"));
- abandon_array = 0;
- }
-
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
- h_size = duk__get_default_h_size(e_size);
- } else {
- h_size = 0;
- }
-#else
- h_size = 0;
-#endif
-
- DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld",
- (long) e_size, (long) a_size, (long) h_size, (long) abandon_array));
-
- duk__realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
-}
-
-/*
- * Find an existing key from entry part either by linear scan or by
- * using the hash index (if it exists).
- *
- * Sets entry index (and possibly the hash index) to output variables,
- * which allows the caller to update the entry and hash entries in-place.
- * If entry is not found, both values are set to -1. If entry is found
- * but there is no hash part, h_idx is set to -1.
- */
-
-DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) {
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(e_idx != NULL);
- DUK_ASSERT(h_idx != NULL);
- DUK_UNREF(heap);
-
- if (DUK_LIKELY(DUK_HOBJECT_GET_HSIZE(obj) == 0))
- {
- /* Linear scan: more likely because most objects are small.
- * This is an important fast path.
- *
- * XXX: this might be worth inlining for property lookups.
- */
- duk_uint_fast32_t i;
- duk_uint_fast32_t n;
- duk_hstring **h_keys_base;
- DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using linear scan for lookup"));
-
- h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(heap, obj);
- n = DUK_HOBJECT_GET_ENEXT(obj);
- for (i = 0; i < n; i++) {
- if (h_keys_base[i] == key) {
- *e_idx = i;
- *h_idx = -1;
- return;
- }
- }
- }
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- else
- {
- /* hash lookup */
- duk_uint32_t n;
- duk_uint32_t i, step;
- duk_uint32_t *h_base;
-
- DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup"));
-
- h_base = DUK_HOBJECT_H_GET_BASE(heap, obj);
- n = DUK_HOBJECT_GET_HSIZE(obj);
- i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
- step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
-
- for (;;) {
- duk_uint32_t t;
-
- DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
- DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
- t = h_base[i];
- DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED ||
- (t < DUK_HOBJECT_GET_ESIZE(obj))); /* t >= 0 always true, unsigned */
-
- if (t == DUK__HASH_UNUSED) {
- break;
- } else if (t == DUK__HASH_DELETED) {
- DUK_DDD(DUK_DDDPRINT("lookup miss (deleted) i=%ld, t=%ld",
- (long) i, (long) t));
- } else {
- DUK_ASSERT(t < DUK_HOBJECT_GET_ESIZE(obj));
- if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) {
- DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p",
- (long) i, (long) t, (void *) key));
- *e_idx = t;
- *h_idx = i;
- return;
- }
- DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld",
- (long) i, (long) t));
- }
- i = (i + step) % n;
-
- /* guaranteed to finish, as hash is never full */
- DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n));
- }
- }
-#endif /* DUK_USE_HOBJECT_HASH_PART */
-
- /* not found */
- *e_idx = -1;
- *h_idx = -1;
-}
-
-/* For internal use: get non-accessor entry value */
-DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key) {
- duk_int_t e_idx;
- duk_int_t h_idx;
-
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_UNREF(heap);
-
- duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
- if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
- return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
- } else {
- return NULL;
- }
-}
-
-/* For internal use: get non-accessor entry value and attributes */
-DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs) {
- duk_int_t e_idx;
- duk_int_t h_idx;
-
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(out_attrs != NULL);
- DUK_UNREF(heap);
-
- duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
- if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
- *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
- return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
- } else {
- *out_attrs = 0;
- return NULL;
- }
-}
-
-/* For internal use: get array part value */
-DUK_INTERNAL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i) {
- duk_tval *tv;
-
- DUK_ASSERT(obj != NULL);
- DUK_UNREF(heap);
-
- if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
- return NULL;
- }
- if (i >= DUK_HOBJECT_GET_ASIZE(obj)) {
- return NULL;
- }
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, obj, i);
- return tv;
-}
-
-/*
- * Allocate and initialize a new entry, resizing the properties allocation
- * if necessary. Returns entry index (e_idx) or throws an error if alloc fails.
- *
- * Sets the key of the entry (increasing the key's refcount), and updates
- * the hash part if it exists. Caller must set value and flags, and update
- * the entry value refcount. A decref for the previous value is not necessary.
- */
-
-DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
- duk_uint32_t idx;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj));
-
-#ifdef DUK_USE_ASSERTIONS
- /* key must not already exist in entry part */
- {
- duk_uint_fast32_t i;
- for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
- DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != key);
- }
- }
-#endif
-
- if (DUK_HOBJECT_GET_ENEXT(obj) >= DUK_HOBJECT_GET_ESIZE(obj)) {
- /* only need to guarantee 1 more slot, but allocation growth is in chunks */
- DUK_DDD(DUK_DDDPRINT("entry part full, allocate space for one more entry"));
- duk__grow_props_for_new_entry_item(thr, obj);
- }
- DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) < DUK_HOBJECT_GET_ESIZE(obj));
- idx = DUK_HOBJECT_POSTINC_ENEXT(obj);
-
- /* previous value is assumed to be garbage, so don't touch it */
- DUK_HOBJECT_E_SET_KEY(thr->heap, obj, idx, key);
- DUK_HSTRING_INCREF(thr, key);
-
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) {
- duk_uint32_t n;
- duk_uint32_t i, step;
- duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
-
- n = DUK_HOBJECT_GET_HSIZE(obj);
- i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
- step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
-
- for (;;) {
- duk_uint32_t t = h_base[i];
- if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
- DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() inserted key into hash part, %ld -> %ld",
- (long) i, (long) idx));
- DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
- DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
- DUK_ASSERT_DISABLE(idx >= 0);
- DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
- h_base[i] = idx;
- break;
- }
- DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i));
- i = (i + step) % n;
-
- /* guaranteed to find an empty slot */
- DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj)));
- }
- }
-#endif /* DUK_USE_HOBJECT_HASH_PART */
-
- /* Note: we could return the hash index here too, but it's not
- * needed right now.
- */
-
- DUK_ASSERT_DISABLE(idx >= 0);
- DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
- DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj));
- return idx;
-}
-
-/*
- * Object internal value
- *
- * Returned value is guaranteed to be reachable / incref'd, caller does not need
- * to incref OR decref. No proxies or accessors are invoked, no prototype walk.
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv_out) {
- duk_int_t e_idx;
- duk_int_t h_idx;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(tv_out != NULL);
-
- /* always in entry part, no need to look up parents etc */
- duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx);
- if (e_idx >= 0) {
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx));
- DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx));
- return 1;
- }
- DUK_TVAL_SET_UNDEFINED(tv_out);
- return 0;
-}
-
-DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) {
- duk_tval tv;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(obj != NULL);
-
- /* This is not strictly necessary, but avoids compiler warnings; e.g.
- * gcc won't reliably detect that no uninitialized data is read below.
- */
- DUK_MEMZERO((void *) &tv, sizeof(duk_tval));
-
- if (duk_hobject_get_internal_value(heap, obj, &tv)) {
- duk_hstring *h;
- DUK_ASSERT(DUK_TVAL_IS_STRING(&tv));
- h = DUK_TVAL_GET_STRING(&tv);
- return h;
- }
-
- return NULL;
-}
-
-/*
- * Arguments handling helpers (argument map mainly).
- *
- * An arguments object has exotic behavior for some numeric indices.
- * Accesses may translate to identifier operations which may have
- * arbitrary side effects (potentially invalidating any duk_tval
- * pointers).
- */
-
-/* Lookup 'key' from arguments internal 'map', perform a variable lookup
- * if mapped, and leave the result on top of stack (and return non-zero).
- * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]].
- */
-DUK_LOCAL
-duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
- duk_hobject *obj,
- duk_hstring *key,
- duk_propdesc *temp_desc,
- duk_hobject **out_map,
- duk_hobject **out_varenv) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *map;
- duk_hobject *varenv;
- duk_bool_t rc;
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- DUK_DDD(DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p "
- "(obj -> %!O, key -> %!O)",
- (void *) thr, (void *) obj, (void *) key, (void *) temp_desc,
- (duk_heaphdr *) obj, (duk_heaphdr *) key));
-
- if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- DUK_DDD(DUK_DDDPRINT("-> no 'map'"));
- return 0;
- }
-
- map = duk_require_hobject(ctx, -1);
- DUK_ASSERT(map != NULL);
- duk_pop(ctx); /* map is reachable through obj */
-
- if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map"));
- return 0;
- }
-
- /* [... varname] */
- DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- DUK_ASSERT(duk_is_string(ctx, -1)); /* guaranteed when building arguments */
-
- /* get varenv for varname (callee's declarative lexical environment) */
- rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */
- varenv = duk_require_hobject(ctx, -1);
- DUK_ASSERT(varenv != NULL);
- duk_pop(ctx); /* varenv remains reachable through 'obj' */
-
- DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv));
-
- /* success: leave varname in stack */
- *out_map = map;
- *out_varenv = varenv;
- return 1; /* [... varname] */
-}
-
-/* Lookup 'key' from arguments internal 'map', and leave replacement value
- * on stack top if mapped (and return non-zero).
- * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
- */
-DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *map;
- duk_hobject *varenv;
- duk_hstring *varname;
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
- DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic get behavior"));
- return 0;
- }
-
- /* [... varname] */
-
- varname = duk_require_hstring(ctx, -1);
- DUK_ASSERT(varname != NULL);
- duk_pop(ctx); /* varname is still reachable */
-
- DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
- "key=%!O, varname=%!O",
- (duk_heaphdr *) key,
- (duk_heaphdr *) varname));
-
- (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/);
-
- /* [... value this_binding] */
-
- duk_pop(ctx);
-
- /* leave result on stack top */
- return 1;
-}
-
-/* Lookup 'key' from arguments internal 'map', perform a variable write if mapped.
- * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]).
- * Assumes stack top contains 'put' value (which is NOT popped).
- */
-DUK_LOCAL void duk__check_arguments_map_for_put(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *map;
- duk_hobject *varenv;
- duk_hstring *varname;
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
- DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic put behavior"));
- return;
- }
-
- /* [... put_value varname] */
-
- varname = duk_require_hstring(ctx, -1);
- DUK_ASSERT(varname != NULL);
- duk_pop(ctx); /* varname is still reachable */
-
- DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
- "key=%!O, varname=%!O, value=%!T",
- (duk_heaphdr *) key,
- (duk_heaphdr *) varname,
- (duk_tval *) duk_require_tval(ctx, -1)));
-
- /* [... put_value] */
-
- /*
- * Note: although arguments object variable mappings are only established
- * for non-strict functions (and a call to a non-strict function created
- * the arguments object in question), an inner strict function may be doing
- * the actual property write. Hence the throw_flag applied here comes from
- * the property write call.
- */
-
- duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, -1), throw_flag);
-
- /* [... put_value] */
-}
-
-/* Lookup 'key' from arguments internal 'map', delete mapping if found.
- * Used in E5 Section 10.6 algorithm for [[Delete]]. Note that the
- * variable/argument itself (where the map points) is not deleted.
- */
-DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *map;
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior"));
- return;
- }
-
- map = duk_require_hobject(ctx, -1);
- DUK_ASSERT(map != NULL);
- duk_pop(ctx); /* map is reachable through obj */
-
- DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result",
- (duk_heaphdr *) key));
-
- /* Note: no recursion issue, we can trust 'map' to behave */
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(map));
- DUK_DDD(DUK_DDDPRINT("map before deletion: %!O", (duk_heaphdr *) map));
- (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
- DUK_DDD(DUK_DDDPRINT("map after deletion: %!O", (duk_heaphdr *) map));
-}
-
-/*
- * Ecmascript compliant [[GetOwnProperty]](P), for internal use only.
- *
- * If property is found:
- * - Fills descriptor fields to 'out_desc'
- * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
- * property onto the stack ('undefined' for accessor properties).
- * - Returns non-zero
- *
- * If property is not found:
- * - 'out_desc' is left in untouched state (possibly garbage)
- * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
- * set)
- * - Returns zero
- *
- * Notes:
- *
- * - Getting a property descriptor may cause an allocation (and hence
- * GC) to take place, hence reachability and refcount of all related
- * values matter. Reallocation of value stack, properties, etc may
- * invalidate many duk_tval pointers (concretely, those which reside
- * in memory areas subject to reallocation). However, heap object
- * pointers are never affected (heap objects have stable pointers).
- *
- * - The value of a plain property is always reachable and has a non-zero
- * reference count.
- *
- * - The value of a virtual property is not necessarily reachable from
- * elsewhere and may have a refcount of zero. Hence we push it onto
- * the valstack for the caller, which ensures it remains reachable
- * while it is needed.
- *
- * - There are no virtual accessor properties. Hence, all getters and
- * setters are always related to concretely stored properties, which
- * ensures that the get/set functions in the resulting descriptor are
- * reachable and have non-zero refcounts. Should there be virtual
- * accessor properties later, this would need to change.
- */
-
-DUK_LOCAL duk_bool_t duk__get_own_propdesc_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_uint32_t arr_idx, duk_propdesc *out_desc, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv;
-
- DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
- "arr_idx=%ld (obj -> %!O, key -> %!O)",
- (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
- (long) flags, (long) arr_idx,
- (duk_heaphdr *) obj, (duk_heaphdr *) key));
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(out_desc != NULL);
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /* XXX: optimize this filling behavior later */
- out_desc->flags = 0;
- out_desc->get = NULL;
- out_desc->set = NULL;
- out_desc->e_idx = -1;
- out_desc->h_idx = -1;
- out_desc->a_idx = -1;
-
- /*
- * Array part
- */
-
- if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
- if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
- if (!DUK_TVAL_IS_UNUSED(tv)) {
- DUK_DDD(DUK_DDDPRINT("-> found in array part"));
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_tval(ctx, tv);
- }
- /* implicit attributes */
- out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_CONFIGURABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE;
- out_desc->a_idx = arr_idx;
- goto prop_found;
- }
- }
- /* assume array part is comprehensive (contains all array indexed elements
- * or none of them); hence no need to check the entries part here.
- */
- DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property (has array part, "
- "should be there if present)"));
- goto prop_not_found_concrete;
- }
-
- /*
- * Entries part
- */
-
- duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx);
- if (out_desc->e_idx >= 0) {
- duk_int_t e_idx = out_desc->e_idx;
- out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx);
- if (out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part"));
- out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx);
- out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx);
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- /* a dummy undefined value is pushed to make valstack
- * behavior uniform for caller
- */
- duk_push_undefined(ctx);
- }
- } else {
- DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part"));
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_tval(ctx, tv);
- }
- }
- goto prop_found;
- }
-
- /*
- * Not found as a concrete property, check whether a String object
- * virtual property matches.
- */
-
- prop_not_found_concrete:
-
- if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
- DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld",
- (duk_heaphdr *) key, (long) arr_idx));
-
- if (arr_idx != DUK__NO_ARRAY_INDEX) {
- duk_hstring *h_val;
-
- DUK_DDD(DUK_DDDPRINT("array index exists"));
-
- h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
- DUK_ASSERT(h_val);
- if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
- DUK_DDD(DUK_DDDPRINT("-> found, array index inside string"));
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_hstring(ctx, h_val);
- duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
- }
- out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */
- DUK_PROPDESC_FLAG_VIRTUAL;
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
- } else {
- /* index is above internal string length -> property is fully normal */
- DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property"));
- }
- } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- duk_hstring *h_val;
-
- DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
-
- h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
- DUK_ASSERT(h_val != NULL);
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
- }
- } else if (DUK_HOBJECT_IS_BUFFEROBJECT(obj)) {
- duk_hbufferobject *h_bufobj;
- duk_uint_t byte_off;
- duk_small_uint_t elem_size;
-
- h_bufobj = (duk_hbufferobject *) obj;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
- DUK_DDD(DUK_DDDPRINT("bufferobject property get for key: %!O, arr_idx: %ld",
- (duk_heaphdr *) key, (long) arr_idx));
-
- if (arr_idx != DUK__NO_ARRAY_INDEX) {
- DUK_DDD(DUK_DDDPRINT("array index exists"));
-
- /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
- * length downshift won't.
- */
- if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
- byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_uint8_t *data;
-
- if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
- data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufferobject_push_validated_read(ctx, h_bufobj, data, elem_size);
- } else {
- DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (read zero)"));
- duk_push_uint(ctx, 0);
- }
- }
- out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE |
- DUK_PROPDESC_FLAG_VIRTUAL;
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
- } else {
- /* index is above internal buffer length -> property is fully normal */
- DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property"));
- }
- } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
-
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- /* Length in elements: take into account shift, but
- * intentionally don't check the underlying buffer here.
- */
- duk_push_uint(ctx, h_bufobj->length >> h_bufobj->shift);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
- } else if (key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr)) {
- /* If neutered must return 0; length is zeroed during
- * neutering.
- */
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, h_bufobj->length);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
- return 1; /* cannot be arguments exotic */
- } else if (key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr)) {
- /* If neutered must return 0; offset is zeroed during
- * neutering.
- */
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, h_bufobj->offset);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
- return 1; /* cannot be arguments exotic */
- } else if (key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_push_uint(ctx, 1 << h_bufobj->shift);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
- return 1; /* cannot be arguments exotic */
- }
- } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(obj)) {
- DUK_DDD(DUK_DDDPRINT("duktape/c object exotic property get for key: %!O, arr_idx: %ld",
- (duk_heaphdr *) key, (long) arr_idx));
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
-
- if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
- duk_int16_t func_nargs = ((duk_hnativefunction *) obj)->nargs;
- duk_push_int(ctx, func_nargs == DUK_HNATIVEFUNCTION_NARGS_VARARGS ? 0 : func_nargs);
- }
- out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* not enumerable */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
- return 1; /* cannot be arguments exotic */
- }
- }
-
- /* Array properties have exotic behavior but they are concrete,
- * so no special handling here.
- *
- * Arguments exotic behavior (E5 Section 10.6, [[GetOwnProperty]]
- * is only relevant as a post-check implemented below; hence no
- * check here.
- */
-
- /*
- * Not found as concrete or virtual
- */
-
- DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)"));
- return 0;
-
- /*
- * Found
- *
- * Arguments object has exotic post-processing, see E5 Section 10.6,
- * description of [[GetOwnProperty]] variant for arguments.
- */
-
- prop_found:
- DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior"));
-
- /* Notes:
- * - only numbered indices are relevant, so arr_idx fast reject is good
- * (this is valid unless there are more than 4**32-1 arguments).
- * - since variable lookup has no side effects, this can be skipped if
- * DUK_GETDESC_FLAG_PUSH_VALUE is not set.
- */
-
- if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
- arr_idx != DUK__NO_ARRAY_INDEX &&
- (flags & DUK_GETDESC_FLAG_PUSH_VALUE)) {
- duk_propdesc temp_desc;
-
- /* Magically bound variable cannot be an accessor. However,
- * there may be an accessor property (or a plain property) in
- * place with magic behavior removed. This happens e.g. when
- * a magic property is redefined with defineProperty().
- * Cannot assert for "not accessor" here.
- */
-
- /* replaces top of stack with new value if necessary */
- DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0);
-
- if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
- DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- /* [... old_result result] -> [... result] */
- duk_remove(ctx, -2);
- }
- }
-
- return 1;
-}
-
-DUK_INTERNAL duk_bool_t duk_hobject_get_own_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(out_desc != NULL);
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- return duk__get_own_propdesc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, flags);
-}
-
-/*
- * Ecmascript compliant [[GetProperty]](P), for internal use only.
- *
- * If property is found:
- * - Fills descriptor fields to 'out_desc'
- * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
- * property onto the stack ('undefined' for accessor properties).
- * - Returns non-zero
- *
- * If property is not found:
- * - 'out_desc' is left in untouched state (possibly garbage)
- * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
- * set)
- * - Returns zero
- *
- * May cause arbitrary side effects and invalidate (most) duk_tval
- * pointers.
- */
-
-DUK_LOCAL duk_bool_t duk__get_propdesc(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *out_desc, duk_small_uint_t flags) {
- duk_hobject *curr;
- duk_uint32_t arr_idx;
- duk_uint_t sanity;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(out_desc != NULL);
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
-
- DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
- "arr_idx=%ld (obj -> %!O, key -> %!O)",
- (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
- (long) flags, (long) arr_idx,
- (duk_heaphdr *) obj, (duk_heaphdr *) key));
-
- curr = obj;
- DUK_ASSERT(curr != NULL);
- sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
- do {
- if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) {
- /* stack contains value (if requested), 'out_desc' is set */
- return 1;
- }
-
- /* not found in 'curr', next in prototype chain; impose max depth */
- if (sanity-- == 0) {
- if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) {
- /* treat like property not found */
- break;
- } else {
- DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
- }
- }
- curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
- } while (curr);
-
- /* out_desc is left untouched (possibly garbage), caller must use return
- * value to determine whether out_desc can be looked up
- */
-
- return 0;
-}
-
-/*
- * Shallow fast path checks for accessing array elements with numeric
- * indices. The goal is to try to avoid coercing an array index to an
- * (interned) string for the most common lookups, in particular, for
- * standard Array objects.
- *
- * Interning is avoided but only for a very narrow set of cases:
- * - Object has array part, index is within array allocation, and
- * value is not unused (= key exists)
- * - Object has no interfering exotic behavior (e.g. arguments or
- * string object exotic behaviors interfere, array exotic
- * behavior does not).
- *
- * Current shortcoming: if key does not exist (even if it is within
- * the array allocation range) a slow path lookup with interning is
- * always required. This can probably be fixed so that there is a
- * quick fast path for non-existent elements as well, at least for
- * standard Array objects.
- */
-
-DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
- duk_tval *tv;
- duk_uint32_t idx;
-
- DUK_UNREF(thr);
-
- if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
- !DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
- !DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) &&
- !DUK_HOBJECT_IS_BUFFEROBJECT(obj) &&
- !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
- /* Must have array part and no conflicting exotic behaviors.
- * Doesn't need to have array special behavior, e.g. Arguments
- * object has array part.
- */
- return NULL;
- }
-
- /* Arrays never have other exotic behaviors. */
-
- DUK_DDD(DUK_DDDPRINT("fast path attempt (no exotic string/arguments/buffer "
- "behavior, object has array part)"));
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_key)) {
- idx = duk__tval_fastint_to_arr_idx(tv_key);
- } else
-#endif
- if (DUK_TVAL_IS_DOUBLE(tv_key)) {
- idx = duk__tval_number_to_arr_idx(tv_key);
- } else {
- DUK_DDD(DUK_DDDPRINT("key is not a number"));
- return NULL;
- }
-
- /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
- * is 0xffffffffUL. We don't need to check for that explicitly
- * because 0xffffffffUL will never be inside object 'a_size'.
- */
-
- if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
- DUK_DDD(DUK_DDDPRINT("key is not an array index or outside array part"));
- return NULL;
- }
- DUK_ASSERT(idx != 0xffffffffUL);
- DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
-
- /* XXX: for array instances we could take a shortcut here and assume
- * Array.prototype doesn't contain an array index property.
- */
-
- DUK_DDD(DUK_DDDPRINT("key is a valid array index and inside array part"));
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
- if (!DUK_TVAL_IS_UNUSED(tv)) {
- DUK_DDD(DUK_DDDPRINT("-> fast path successful"));
- return tv;
- }
-
- DUK_DDD(DUK_DDDPRINT("fast path attempt failed, fall back to slow path"));
- return NULL;
-}
-
-DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val, duk_propdesc *temp_desc) {
- duk_tval *tv;
- duk_uint32_t idx;
- duk_uint32_t old_len, new_len;
-
- if (!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) &&
- DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
- DUK_HOBJECT_HAS_EXTENSIBLE(obj))) {
- return 0;
- }
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures */
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_key)) {
- idx = duk__tval_fastint_to_arr_idx(tv_key);
- } else
-#endif
- if (DUK_TVAL_IS_DOUBLE(tv_key)) {
- idx = duk__tval_number_to_arr_idx(tv_key);
- } else {
- DUK_DDD(DUK_DDDPRINT("key is not a number"));
- return 0;
- }
-
- /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
- * is 0xffffffffUL. We don't need to check for that explicitly
- * because 0xffffffffUL will never be inside object 'a_size'.
- */
-
- if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { /* for resizing of array part, use slow path */
- return 0;
- }
- DUK_ASSERT(idx != 0xffffffffUL);
- DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
-
- old_len = duk__get_old_array_length(thr, obj, temp_desc);
-
- if (idx >= old_len) {
- DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
- "(arr_idx=%ld, old_len=%ld)",
- (long) idx, (long) old_len));
- if (!(temp_desc->flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
- return 0; /* not reachable */
- }
- new_len = idx + 1;
-
- /* No resize has occurred so temp_desc->e_idx is still OK */
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, temp_desc->e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- DUK_TVAL_SET_FASTINT_U32(tv, new_len); /* no need for decref/incref because value is a number */
- } else {
- ;
- }
-
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
-
- DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld", (long) idx));
- return 1;
-}
-
-/*
- * Fast path for bufferobject getprop/putprop
- */
-
-DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
- duk_context *ctx;
- duk_uint32_t idx;
- duk_hbufferobject *h_bufobj;
- duk_uint_t byte_off;
- duk_small_uint_t elem_size;
- duk_uint8_t *data;
-
- ctx = (duk_context *) thr;
-
- if (!DUK_HOBJECT_IS_BUFFEROBJECT(obj)) {
- return 0;
- }
- h_bufobj = (duk_hbufferobject *) obj;
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_key)) {
- idx = duk__tval_fastint_to_arr_idx(tv_key);
- } else
-#endif
- if (DUK_TVAL_IS_DOUBLE(tv_key)) {
- idx = duk__tval_number_to_arr_idx(tv_key);
- } else {
- return 0;
- }
-
- /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
- * is 0xffffffffUL. We don't need to check for that explicitly
- * because 0xffffffffUL will never be inside bufferobject length.
- */
-
- /* Careful with wrapping (left shifting idx would be unsafe). */
- if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
- return 0;
- }
- DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
-
- byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
-
- if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
- data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufferobject_push_validated_read(ctx, h_bufobj, data, elem_size);
- } else {
- DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (read zero)"));
- duk_push_uint(ctx, 0);
- }
-
- return 1;
-}
-
-DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
- duk_context *ctx;
- duk_uint32_t idx;
- duk_hbufferobject *h_bufobj;
- duk_uint_t byte_off;
- duk_small_uint_t elem_size;
- duk_uint8_t *data;
-
- ctx = (duk_context *) thr;
-
- if (!(DUK_HOBJECT_IS_BUFFEROBJECT(obj) &&
- DUK_TVAL_IS_NUMBER(tv_val))) {
- return 0;
- }
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufferobjects now */
-
- h_bufobj = (duk_hbufferobject *) obj;
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_key)) {
- idx = duk__tval_fastint_to_arr_idx(tv_key);
- } else
-#endif
- if (DUK_TVAL_IS_DOUBLE(tv_key)) {
- idx = duk__tval_number_to_arr_idx(tv_key);
- } else {
- return 0;
- }
-
- /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
- * is 0xffffffffUL. We don't need to check for that explicitly
- * because 0xffffffffUL will never be inside bufferobject length.
- */
-
- /* Careful with wrapping (left shifting idx would be unsafe). */
- if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
- return 0;
- }
- DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
-
- byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
-
- /* Value is required to be a number in the fast path so there
- * are no side effects in write coercion.
- */
- duk_push_tval(ctx, tv_val);
- DUK_ASSERT(duk_is_number(ctx, -1));
-
- if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
- data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufferobject_validated_write(ctx, h_bufobj, data, elem_size);
- } else {
- DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (write skipped)"));
- }
-
- duk_pop(ctx);
- return 1;
-}
-
-/*
- * GETPROP: Ecmascript property read.
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
- duk_context *ctx = (duk_context *) thr;
- duk_tval tv_obj_copy;
- duk_tval tv_key_copy;
- duk_hobject *curr = NULL;
- duk_hstring *key = NULL;
- duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
- duk_propdesc desc;
- duk_uint_t sanity;
-
- DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
- (void *) thr, (void *) tv_obj, (void *) tv_key,
- (duk_tval *) tv_obj, (duk_tval *) tv_key));
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(tv_obj != NULL);
- DUK_ASSERT(tv_key != NULL);
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /*
- * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
- * them being invalidated by a valstack resize.
- *
- * XXX: this is now an overkill for many fast paths. Rework this
- * to be faster (although switching to a valstack discipline might
- * be a better solution overall).
- */
-
- DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
- DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
- tv_obj = &tv_obj_copy;
- tv_key = &tv_key_copy;
-
- /*
- * Coercion and fast path processing
- */
-
- switch (DUK_TVAL_GET_TAG(tv_obj)) {
- case DUK_TAG_UNDEFINED:
- case DUK_TAG_NULL: {
- /* Note: unconditional throw */
- DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
-#if defined(DUK_USE_PARANOID_ERRORS)
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
-#else
- DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
- duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
-#endif
- return 0;
- }
-
- case DUK_TAG_BOOLEAN: {
- DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
- curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
- break;
- }
-
- case DUK_TAG_STRING: {
- duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
- duk_int_t pop_count;
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_key)) {
- arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
- DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
- pop_count = 0;
- } else
-#endif
- if (DUK_TVAL_IS_NUMBER(tv_key)) {
- arr_idx = duk__tval_number_to_arr_idx(tv_key);
- DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx));
- pop_count = 0;
- } else {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
- DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
- "coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
- pop_count = 1;
- }
-
- if (arr_idx != DUK__NO_ARRAY_INDEX &&
- arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
- duk_pop_n(ctx, pop_count);
- duk_push_hstring(ctx, h);
- duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
- "after coercion -> return char)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- }
-
- if (pop_count == 0) {
- /* This is a pretty awkward control flow, but we need to recheck the
- * key coercion here.
- */
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
- DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
- "coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
- }
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
- "return string length)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- }
- DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
- curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
- goto lookup; /* avoid double coercion */
- }
-
- case DUK_TAG_OBJECT: {
- duk_tval *tmp;
-
- curr = DUK_TVAL_GET_OBJECT(tv_obj);
- DUK_ASSERT(curr != NULL);
-
- tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key);
- if (tmp) {
- duk_push_tval(ctx, tmp);
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
- "fast path)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- }
-
- if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) {
- /* Read value pushed on stack. */
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufferobject "
- "fast path)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- }
-
-#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(curr))) {
- duk_hobject *h_target;
-
- if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) {
- /* -> [ ... trap handler ] */
- DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
- duk_call_method(ctx, 3 /*nargs*/);
-
- /* Target object must be checked for a conflicting
- * non-configurable property.
- */
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
-
- if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- duk_tval *tv_hook = duk_require_tval(ctx, -3); /* value from hook */
- duk_tval *tv_targ = duk_require_tval(ctx, -1); /* value from target */
- duk_bool_t datadesc_reject;
- duk_bool_t accdesc_reject;
-
- DUK_DDD(DUK_DDDPRINT("proxy 'get': target has matching property %!O, check for "
- "conflicting property; tv_hook=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
- "desc.get=%p, desc.set=%p",
- (duk_heaphdr *) key, (duk_tval *) tv_hook, (duk_tval *) tv_targ,
- (unsigned long) desc.flags,
- (void *) desc.get, (void *) desc.set));
-
- datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
- !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
- !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
- !duk_js_samevalue(tv_hook, tv_targ);
- accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
- !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
- (desc.get == NULL) &&
- !DUK_TVAL_IS_UNDEFINED(tv_hook);
- if (datadesc_reject || accdesc_reject) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
- }
-
- duk_pop_2(ctx);
- } else {
- duk_pop(ctx);
- }
- return 1; /* return value */
- }
-
- curr = h_target; /* resume lookup from target */
- DUK_TVAL_SET_OBJECT(tv_obj, curr);
- }
-#endif /* DUK_USE_ES6_PROXY */
-
- if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
-
- if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, "
- "key matches magically bound property -> skip standard "
- "Get with replacement value)",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* no need for 'caller' post-check, because 'key' must be an array index */
-
- duk_remove(ctx, -2); /* [key result] -> [result] */
- return 1;
- }
-
- goto lookup; /* avoid double coercion */
- }
- break;
- }
-
- /* Buffer has virtual properties similar to string, but indexed values
- * are numbers, not 1-byte buffers/strings which would perform badly.
- */
- case DUK_TAG_BUFFER: {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
- duk_int_t pop_count;
-
- /*
- * Because buffer values are often looped over, a number fast path
- * is important.
- */
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_key)) {
- arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
- DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
- pop_count = 0;
- }
- else
-#endif
- if (DUK_TVAL_IS_NUMBER(tv_key)) {
- arr_idx = duk__tval_number_to_arr_idx(tv_key);
- DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
- pop_count = 0;
- } else {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
- DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
- "coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
- pop_count = 1;
- }
-
- if (arr_idx != DUK__NO_ARRAY_INDEX &&
- arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
- duk_pop_n(ctx, pop_count);
- duk_push_uint(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
- "after coercion -> return byte as number)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- }
-
- if (pop_count == 0) {
- /* This is a pretty awkward control flow, but we need to recheck the
- * key coercion here.
- */
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
- DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
- "coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
- }
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' or 'byteLength' "
- "after coercion -> return buffer length)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- } else if (key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, 0); /* [] -> [res] */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'byteOffset' after coercion -> "
- "return 0 for consistency with Buffer objects)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- } else if (key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
- duk_pop(ctx); /* [key] -> [] */
- duk_push_uint(ctx, 1); /* [] -> [res] */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'BYTES_PER_ELEMENT' after coercion -> "
- "return 1 for consistency with Buffer objects)",
- (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
- }
-
- DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype"));
- curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
- goto lookup; /* avoid double coercion */
- }
-
- case DUK_TAG_POINTER: {
- DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
- curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
- break;
- }
-
- case DUK_TAG_LIGHTFUNC: {
- duk_int_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_obj);
-
- /* Must coerce key: if key is an object, it may coerce to e.g. 'length'. */
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- duk_int_t lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
- duk_pop(ctx);
- duk_push_int(ctx, lf_len);
- return 1;
- } else if (key == DUK_HTHREAD_STRING_NAME(thr)) {
- duk_pop(ctx);
- duk_push_lightfunc_name(ctx, tv_obj);
- return 1;
- }
-
- DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
- curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
- goto lookup; /* avoid double coercion */
- }
-
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default: {
- /* number */
- DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_obj));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
- curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
- break;
- }
- }
-
- /* key coercion (unless already coerced above) */
- DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
-
- /*
- * Property lookup
- */
-
- lookup:
- /* [key] (coerced) */
- DUK_ASSERT(curr != NULL);
- DUK_ASSERT(key != NULL);
-
- sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
- do {
- if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- goto next_in_chain;
- }
-
- if (desc.get != NULL) {
- /* accessor with defined getter */
- DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
-
- duk_pop(ctx); /* [key undefined] -> [key] */
- duk_push_hobject(ctx, desc.get);
- duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
-#ifdef DUK_USE_NONSTD_GETTER_KEY_ARGUMENT
- duk_dup(ctx, -3);
- duk_call_method(ctx, 1); /* [key getter this key] -> [key retval] */
-#else
- duk_call_method(ctx, 0); /* [key getter this] -> [key retval] */
-#endif
- } else {
- /* [key value] or [key undefined] */
-
- /* data property or accessor without getter */
- DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
- (desc.get == NULL));
-
- /* if accessor without getter, return value is undefined */
- DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
- duk_is_undefined(ctx, -1));
-
- /* Note: for an accessor without getter, falling through to
- * check for "caller" exotic behavior is unnecessary as
- * "undefined" will never activate the behavior. But it does
- * no harm, so we'll do it anyway.
- */
- }
-
- goto found; /* [key result] */
-
- next_in_chain:
- /* XXX: option to pretend property doesn't exist if sanity limit is
- * hit might be useful.
- */
- if (sanity-- == 0) {
- DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
- }
- curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
- } while (curr);
-
- /*
- * Not found
- */
-
- duk_to_undefined(ctx, -1); /* [key] -> [undefined] (default value) */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(ctx, -1)));
- return 0;
-
- /*
- * Found; post-processing (Function and arguments objects)
- */
-
- found:
- /* [key result] */
-
-#if !defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- /* Special behavior for 'caller' property of (non-bound) function objects
- * and non-strict Arguments objects: if 'caller' -value- (!) is a strict
- * mode function, throw a TypeError (E5 Sections 15.3.5.4, 10.6).
- * Quite interestingly, a non-strict function with no formal arguments
- * will get an arguments object -without- special 'caller' behavior!
- *
- * The E5.1 spec is a bit ambiguous if this special behavior applies when
- * a bound function is the base value (not the 'caller' value): Section
- * 15.3.4.5 (describing bind()) states that [[Get]] for bound functions
- * matches that of Section 15.3.5.4 ([[Get]] for Function instances).
- * However, Section 13.3.5.4 has "NOTE: Function objects created using
- * Function.prototype.bind use the default [[Get]] internal method."
- * The current implementation assumes this means that bound functions
- * should not have the special [[Get]] behavior.
- *
- * The E5.1 spec is also a bit unclear if the TypeError throwing is
- * applied if the 'caller' value is a strict bound function. The
- * current implementation will throw even for both strict non-bound
- * and strict bound functions.
- *
- * See test-dev-strict-func-as-caller-prop-value.js for quite extensive
- * tests.
- *
- * This exotic behavior is disabled when the non-standard 'caller' property
- * is enabled, as it conflicts with the free use of 'caller'.
- */
- if (key == DUK_HTHREAD_STRING_CALLER(thr) &&
- DUK_TVAL_IS_OBJECT(tv_obj)) {
- duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj);
- DUK_ASSERT(orig != NULL);
-
- if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) ||
- DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
- duk_hobject *h;
-
- /* XXX: The TypeError is currently not applied to bound
- * functions because the 'strict' flag is not copied by
- * bind(). This may or may not be correct, the specification
- * only refers to the value being a "strict mode Function
- * object" which is ambiguous.
- */
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(orig));
-
- h = duk_get_hobject(ctx, -1); /* NULL if not an object */
- if (h &&
- DUK_HOBJECT_IS_FUNCTION(h) &&
- DUK_HOBJECT_HAS_STRICT(h)) {
- /* XXX: sufficient to check 'strict', assert for 'is function' */
- DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ);
- }
- }
- }
-#endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
-
- duk_remove(ctx, -2); /* [key result] -> [result] */
-
- DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(ctx, -1)));
- return 1;
-}
-
-/*
- * HASPROP: Ecmascript property existence check ("in" operator).
- *
- * Interestingly, the 'in' operator does not do any coercion of
- * the target object.
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
- duk_context *ctx = (duk_context *) thr;
- duk_tval tv_key_copy;
- duk_hobject *obj;
- duk_hstring *key;
- duk_uint32_t arr_idx;
- duk_bool_t rc;
- duk_propdesc desc;
-
- DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
- (void *) thr, (void *) tv_obj, (void *) tv_key,
- (duk_tval *) tv_obj, (duk_tval *) tv_key));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(tv_obj != NULL);
- DUK_ASSERT(tv_key != NULL);
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
- tv_key = &tv_key_copy;
-
- /*
- * The 'in' operator requires an object as its right hand side,
- * throwing a TypeError unconditionally if this is not the case.
- *
- * However, lightfuncs need to behave like fully fledged objects
- * here to be maximally transparent, so we need to handle them
- * here.
- */
-
- /* XXX: Refactor key coercion so that it's only called once. It can't
- * be trivially lifted here because the object must be type checked
- * first.
- */
-
- if (DUK_TVAL_IS_OBJECT(tv_obj)) {
- obj = DUK_TVAL_GET_OBJECT(tv_obj);
- DUK_ASSERT(obj != NULL);
-
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- /* FOUND */
- rc = 1;
- goto pop_and_return;
- }
-
- /* If not found, resume existence check from Function.prototype.
- * We can just substitute the value in this case; nothing will
- * need the original base value (as would be the case with e.g.
- * setters/getters.
- */
- obj = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
- } else {
- /* Note: unconditional throw */
- DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
- }
-
- /* XXX: fast path for arrays? */
-
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_UNREF(arr_idx);
-
-#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
- duk_hobject *h_target;
- duk_bool_t tmp_bool;
-
- /* XXX: the key in 'key in obj' is string coerced before we're called
- * (which is the required behavior in E5/E5.1/E6) so the key is a string
- * here already.
- */
-
- if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) {
- /* [ ... key trap handler ] */
- DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_call_method(ctx, 2 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
- if (!tmp_bool) {
- /* Target object must be checked for a conflicting
- * non-configurable property.
- */
-
- if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
- DUK_DDD(DUK_DDDPRINT("proxy 'has': target has matching property %!O, check for "
- "conflicting property; desc.flags=0x%08lx, "
- "desc.get=%p, desc.set=%p",
- (duk_heaphdr *) key, (unsigned long) desc.flags,
- (void *) desc.get, (void *) desc.set));
- /* XXX: Extensibility check for target uses IsExtensible(). If we
- * implemented the isExtensible trap and didn't reject proxies as
- * proxy targets, it should be respected here.
- */
- if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */
- DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
- }
- }
- }
-
- duk_pop_2(ctx); /* [ key trap_result ] -> [] */
- return tmp_bool;
- }
-
- obj = h_target; /* resume check from proxy target */
- }
-#endif /* DUK_USE_ES6_PROXY */
-
- /* XXX: inline into a prototype walking loop? */
-
- rc = duk__get_propdesc(thr, obj, key, &desc, 0 /*flags*/); /* don't push value */
- /* fall through */
-
- pop_and_return:
- duk_pop(ctx); /* [ key ] -> [] */
- return rc;
-}
-
-/*
- * HASPROP variant used internally.
- *
- * This primitive must never throw an error, callers rely on this.
- * In particular, don't throw an error for prototype loops; instead,
- * pretend like the property doesn't exist if a prototype sanity limit
- * is reached.
- *
- * Does not implement proxy behavior: if applied to a proxy object,
- * returns key existence on the proxy object itself.
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
- duk_propdesc dummy;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- return duk__get_propdesc(thr, obj, key, &dummy, DUK_GETDESC_FLAG_IGNORE_PROTOLOOP); /* don't push value */
-}
-
-/*
- * Helper: handle Array object 'length' write which automatically
- * deletes properties, see E5 Section 15.4.5.1, step 3. This is
- * quite tricky to get right.
- *
- * Used by duk_hobject_putprop().
- */
-
-DUK_LOCAL duk_uint32_t duk__get_old_array_length(duk_hthread *thr, duk_hobject *obj, duk_propdesc *temp_desc) {
- duk_bool_t rc;
- duk_tval *tv;
- duk_uint32_t res;
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /* This function is only called for objects with array exotic behavior.
- * The [[DefineOwnProperty]] algorithm for arrays requires that
- * 'length' can never have a value outside the unsigned 32-bit range,
- * attempt to write such a value is a RangeError. Here we can thus
- * assert for this. When Duktape internals go around the official
- * property write interface (doesn't happen often) this assumption is
- * easy to accidentally break, so such code must be written carefully.
- * See test-bi-array-push-maxlen.js.
- */
-
- rc = duk__get_own_propdesc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, temp_desc, 0 /*flags*/); /* don't push value */
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0); /* arrays MUST have a 'length' property */
- DUK_ASSERT(temp_desc->e_idx >= 0);
-
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, temp_desc->e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* array 'length' is always a number, as we coerce it */
- DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) >= 0.0);
- DUK_ASSERT(DUK_TVAL_GET_NUMBER(tv) <= (double) 0xffffffffUL);
- DUK_ASSERT((duk_double_t) (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv) == DUK_TVAL_GET_NUMBER(tv));
-#if defined(DUK_USE_FASTINT)
- /* Downgrade checks are not made everywhere, so 'length' is not always
- * a fastint (it is a number though). This can be removed once length
- * is always guaranteed to be a fastint.
- */
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv) || DUK_TVAL_IS_DOUBLE(tv));
- if (DUK_TVAL_IS_FASTINT(tv)) {
- res = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv);
- } else {
- res = (duk_uint32_t) DUK_TVAL_GET_DOUBLE(tv);
- }
-#else
- res = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
-#endif /* DUK_USE_FASTINT */
-
- return res;
-}
-
-DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_uint32_t res;
- duk_double_t d;
-
- /* Input value should be on stack top and will be coerced and
- * popped. Refuse to update an Array's 'length' to a value
- * outside the 32-bit range. Negative zero is accepted as zero.
- */
-
- /* XXX: fastint */
-
- d = duk_to_number(ctx, -1);
- res = (duk_uint32_t) d;
- if ((duk_double_t) res != d) {
- DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
- }
- duk_pop(ctx);
- return res;
-}
-
-/* Delete elements required by a smaller length, taking into account
- * potentially non-configurable elements. Returns non-zero if all
- * elements could be deleted, and zero if all or some elements could
- * not be deleted. Also writes final "target length" to 'out_result_len'.
- * This is the length value that should go into the 'length' property
- * (must be set by the caller). Never throws an error.
- */
-DUK_LOCAL
-duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
- duk_hobject *obj,
- duk_uint32_t old_len,
- duk_uint32_t new_len,
- duk_bool_t force_flag,
- duk_uint32_t *out_result_len) {
- duk_uint32_t target_len;
- duk_uint_fast32_t i;
- duk_uint32_t arr_idx;
- duk_hstring *key;
- duk_tval *tv;
- duk_bool_t rc;
-
- DUK_DDD(DUK_DDDPRINT("new array length smaller than old (%ld -> %ld), "
- "probably need to remove elements",
- (long) old_len, (long) new_len));
-
- /*
- * New length is smaller than old length, need to delete properties above
- * the new length.
- *
- * If array part exists, this is straightforward: array entries cannot
- * be non-configurable so this is guaranteed to work.
- *
- * If array part does not exist, array-indexed values are scattered
- * in the entry part, and some may not be configurable (preventing length
- * from becoming lower than their index + 1). To handle the algorithm
- * in E5 Section 15.4.5.1, step l correctly, we scan the entire property
- * set twice.
- */
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(new_len < old_len);
- DUK_ASSERT(out_result_len != NULL);
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
- /*
- * All defined array-indexed properties are in the array part
- * (we assume the array part is comprehensive), and all array
- * entries are writable, configurable, and enumerable. Thus,
- * nothing can prevent array entries from being deleted.
- */
-
- DUK_DDD(DUK_DDDPRINT("have array part, easy case"));
-
- if (old_len < DUK_HOBJECT_GET_ASIZE(obj)) {
- /* XXX: assertion that entries >= old_len are already unused */
- i = old_len;
- } else {
- i = DUK_HOBJECT_GET_ASIZE(obj);
- }
- DUK_ASSERT(i <= DUK_HOBJECT_GET_ASIZE(obj));
-
- while (i > new_len) {
- i--;
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
- DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
- }
-
- *out_result_len = new_len;
- return 1;
- } else {
- /*
- * Entries part is a bit more complex
- */
-
- /* Stage 1: find highest preventing non-configurable entry (if any).
- * When forcing, ignore non-configurability.
- */
-
- DUK_DDD(DUK_DDDPRINT("no array part, slow case"));
-
- DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 1: find target_len "
- "(highest preventing non-configurable entry (if any))"));
-
- target_len = new_len;
- if (force_flag) {
- DUK_DDD(DUK_DDDPRINT("array length write, no array part; force flag -> skip stage 1"));
- goto skip_stage1;
- }
- for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
- key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
- if (!key) {
- DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
- continue;
- }
- if (!DUK_HSTRING_HAS_ARRIDX(key)) {
- DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
- continue;
- }
-
- DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
- arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
- DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
- DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
-
- if (arr_idx < new_len) {
- DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below new_len",
- (long) i, (long) arr_idx));
- continue;
- }
- if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)) {
- DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is a relevant array index %ld, but configurable",
- (long) i, (long) arr_idx));
- continue;
- }
-
- /* relevant array index is non-configurable, blocks write */
- if (arr_idx >= target_len) {
- DUK_DDD(DUK_DDDPRINT("entry at index %ld has arr_idx %ld, is not configurable, "
- "update target_len %ld -> %ld",
- (long) i, (long) arr_idx, (long) target_len,
- (long) (arr_idx + 1)));
- target_len = arr_idx + 1;
- }
- }
- skip_stage1:
-
- /* stage 2: delete configurable entries above target length */
-
- DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld, target_len=%ld",
- (long) old_len, (long) new_len, (long) target_len));
-
- DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 2: remove "
- "entries >= target_len"));
-
- for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
- key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
- if (!key) {
- DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
- continue;
- }
- if (!DUK_HSTRING_HAS_ARRIDX(key)) {
- DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
- continue;
- }
-
- DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
- arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
- DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
- DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
-
- if (arr_idx < target_len) {
- DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below target_len",
- (long) i, (long) arr_idx));
- continue;
- }
- DUK_ASSERT(force_flag || DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)); /* stage 1 guarantees */
-
- DUK_DDD(DUK_DDDPRINT("delete entry index %ld: key is array index %ld",
- (long) i, (long) arr_idx));
-
- /*
- * Slow delete, but we don't care as we're already in a very slow path.
- * The delete always succeeds: key has no exotic behavior, property
- * is configurable, and no resize occurs.
- */
- rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- }
-
- /* stage 3: update length (done by caller), decide return code */
-
- DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)"));
-
- *out_result_len = target_len;
-
- if (target_len == new_len) {
- DUK_DDD(DUK_DDDPRINT("target_len matches new_len, return success"));
- return 1;
- }
- DUK_DDD(DUK_DDDPRINT("target_len does not match new_len (some entry prevented "
- "full length adjustment), return error"));
- return 0;
- }
-
- DUK_UNREACHABLE();
-}
-
-/* XXX: is valstack top best place for argument? */
-DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
- duk_propdesc desc;
- duk_uint32_t old_len;
- duk_uint32_t new_len;
- duk_uint32_t result_len;
- duk_tval *tv;
- duk_bool_t rc;
-
- DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, "
- "new val: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(obj != NULL);
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- DUK_ASSERT(duk_is_valid_index(ctx, -1));
-
- /*
- * Get old and new length
- */
-
- old_len = duk__get_old_array_length(thr, obj, &desc);
- duk_dup(ctx, -1); /* [in_val in_val] */
- new_len = duk__to_new_array_length_checked(thr); /* -> [in_val] */
- DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
-
- /*
- * Writability check
- */
-
- if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- DUK_DDD(DUK_DDDPRINT("length is not writable, fail"));
- return 0;
- }
-
- /*
- * New length not lower than old length => no changes needed
- * (not even array allocation).
- */
-
- if (new_len >= old_len) {
- DUK_DDD(DUK_DDDPRINT("new length is higher than old length, just update length, no deletions"));
-
- DUK_ASSERT(desc.e_idx >= 0);
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx));
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- /* no decref needed for a number */
- DUK_TVAL_SET_FASTINT_U32(tv, new_len);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- return 1;
- }
-
- DUK_DDD(DUK_DDDPRINT("new length is lower than old length, probably must delete entries"));
-
- /*
- * New length lower than old length => delete elements, then
- * update length.
- *
- * Note: even though a bunch of elements have been deleted, the 'desc' is
- * still valid as properties haven't been resized (and entries compacted).
- */
-
- rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len);
- DUK_ASSERT(result_len >= new_len && result_len <= old_len);
-
- DUK_ASSERT(desc.e_idx >= 0);
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx));
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- /* no decref needed for a number */
- DUK_TVAL_SET_FASTINT_U32(tv, result_len);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
-
- /* XXX: shrink array allocation or entries compaction here? */
-
- return rc;
-}
-
-/*
- * PUTPROP: Ecmascript property write.
- *
- * Unlike Ecmascript primitive which returns nothing, returns 1 to indicate
- * success and 0 to indicate failure (assuming throw is not set).
- *
- * This is an extremely tricky function. Some examples:
- *
- * * Currently a decref may trigger a GC, which may compact an object's
- * property allocation. Consequently, any entry indices (e_idx) will
- * be potentially invalidated by a decref.
- *
- * * Exotic behaviors (strings, arrays, arguments object) require,
- * among other things:
- *
- * - Preprocessing before and postprocessing after an actual property
- * write. For example, array index write requires pre-checking the
- * array 'length' property for access control, and may require an
- * array 'length' update after the actual write has succeeded (but
- * not if it fails).
- *
- * - Deletion of multiple entries, as a result of array 'length' write.
- *
- * * Input values are taken as pointers which may point to the valstack.
- * If valstack is resized because of the put (this may happen at least
- * when the array part is abandoned), the pointers can be invalidated.
- * (We currently make a copy of all of the input values to avoid issues.)
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
- duk_tval tv_obj_copy;
- duk_tval tv_key_copy;
- duk_tval tv_val_copy;
- duk_hobject *orig = NULL; /* NULL if tv_obj is primitive */
- duk_hobject *curr;
- duk_hstring *key = NULL;
- duk_propdesc desc;
- duk_tval *tv;
- duk_uint32_t arr_idx;
- duk_bool_t rc;
- duk_int_t e_idx;
- duk_uint_t sanity;
- duk_uint32_t new_array_length = 0; /* 0 = no update */
-
- DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld "
- "(obj -> %!T, key -> %!T, val -> %!T)",
- (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val,
- (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(tv_obj != NULL);
- DUK_ASSERT(tv_key != NULL);
- DUK_ASSERT(tv_val != NULL);
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /*
- * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
- * them being invalidated by a valstack resize.
- *
- * XXX: this is an overkill for some paths, so optimize this later
- * (or maybe switch to a stack arguments model entirely).
- */
-
- DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
- DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
- DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val);
- tv_obj = &tv_obj_copy;
- tv_key = &tv_key_copy;
- tv_val = &tv_val_copy;
-
- /*
- * Coercion and fast path processing.
- */
-
- switch (DUK_TVAL_GET_TAG(tv_obj)) {
- case DUK_TAG_UNDEFINED:
- case DUK_TAG_NULL: {
- /* Note: unconditional throw */
- DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)",
- (duk_tval *) tv_obj));
-#if defined(DUK_USE_PARANOID_ERRORS)
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
-#else
- DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
- duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
-#endif
- return 0;
- }
-
- case DUK_TAG_BOOLEAN: {
- DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
- curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
- break;
- }
-
- case DUK_TAG_STRING: {
- duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
-
- /*
- * Note: currently no fast path for array index writes.
- * They won't be possible anyway as strings are immutable.
- */
-
- DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- goto fail_not_writable;
- }
-
- if (arr_idx != DUK__NO_ARRAY_INDEX &&
- arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
- goto fail_not_writable;
- }
-
- DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
- curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
- goto lookup; /* avoid double coercion */
- }
-
- case DUK_TAG_OBJECT: {
- orig = DUK_TVAL_GET_OBJECT(tv_obj);
- DUK_ASSERT(orig != NULL);
-
-#if defined(DUK_USE_ROM_OBJECTS)
- /* With this check in place fast paths won't need read-only
- * object checks. This is technically incorrect if there are
- * setters that cause no writes to ROM objects, but current
- * built-ins don't have such setters.
- */
- if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
- DUK_DD(DUK_DDPRINT("attempt to putprop on read-only target object"));
- goto fail_not_writable_no_pop; /* Must avoid duk_pop() in exit path */
- }
-#endif
-
- /* The fast path for array property put is not fully compliant:
- * If one places conflicting number-indexed properties into
- * Array.prototype (for example, a non-writable Array.prototype[7])
- * the fast path will incorrectly ignore them.
- *
- * This fast path could be made compliant by falling through
- * to the slow path if the previous value was UNUSED. This would
- * also remove the need to check for extensibility. Right now a
- * non-extensible array is slower than an extensible one as far
- * as writes are concerned.
- *
- * The fast path behavior is documented in more detail here:
- * tests/ecmascript/test-misc-array-fast-write.js
- */
-
- if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val, &desc) != 0) {
- DUK_DDD(DUK_DDDPRINT("array fast path success"));
- return 1;
- }
-
- if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) {
- DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufferobject fast path"));
- return 1;
- }
-
-#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(orig))) {
- duk_hobject *h_target;
- duk_bool_t tmp_bool;
-
- if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) {
- /* -> [ ... trap handler ] */
- DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_push_tval(ctx, tv_val); /* V */
- duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
- duk_call_method(ctx, 4 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
- duk_pop(ctx);
- if (!tmp_bool) {
- goto fail_proxy_rejected;
- }
-
- /* Target object must be checked for a conflicting
- * non-configurable property.
- */
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
-
- if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- duk_tval *tv_targ = duk_require_tval(ctx, -1);
- duk_bool_t datadesc_reject;
- duk_bool_t accdesc_reject;
-
- DUK_DDD(DUK_DDDPRINT("proxy 'set': target has matching property %!O, check for "
- "conflicting property; tv_val=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
- "desc.get=%p, desc.set=%p",
- (duk_heaphdr *) key, (duk_tval *) tv_val, (duk_tval *) tv_targ,
- (unsigned long) desc.flags,
- (void *) desc.get, (void *) desc.set));
-
- datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
- !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
- !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
- !duk_js_samevalue(tv_val, tv_targ);
- accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
- !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
- (desc.set == NULL);
- if (datadesc_reject || accdesc_reject) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
- }
-
- duk_pop_2(ctx);
- } else {
- duk_pop(ctx);
- }
- return 1; /* success */
- }
-
- orig = h_target; /* resume write to target */
- DUK_TVAL_SET_OBJECT(tv_obj, orig);
- }
-#endif /* DUK_USE_ES6_PROXY */
-
- curr = orig;
- break;
- }
-
- case DUK_TAG_BUFFER: {
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
- duk_int_t pop_count = 0;
-
- /*
- * Because buffer values may be looped over and read/written
- * from, an array index fast path is important.
- */
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_key)) {
- arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
- DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
- pop_count = 0;
- } else
-#endif
- if (DUK_TVAL_IS_NUMBER(tv_key)) {
- arr_idx = duk__tval_number_to_arr_idx(tv_key);
- DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
- pop_count = 0;
- } else {
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
- DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
- "coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
- pop_count = 1;
- }
-
- if (arr_idx != DUK__NO_ARRAY_INDEX &&
- arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
- duk_uint8_t *data;
- DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
- data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
-
- /* XXX: duk_to_int() ensures we'll get 8 lowest bits as
- * as input is within duk_int_t range (capped outside it).
- */
-#if defined(DUK_USE_FASTINT)
- /* Buffer writes are often integers. */
- if (DUK_TVAL_IS_FASTINT(tv_val)) {
- data[arr_idx] = (duk_uint8_t) DUK_TVAL_GET_FASTINT_U32(tv_val);
- }
- else
-#endif
- {
- duk_push_tval(ctx, tv_val);
- data[arr_idx] = (duk_uint8_t) duk_to_uint32(ctx, -1);
- pop_count++;
- }
-
- duk_pop_n(ctx, pop_count);
- DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)"));
- return 1;
- }
-
- if (pop_count == 0) {
- /* This is a pretty awkward control flow, but we need to recheck the
- * key coercion here.
- */
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
- DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
- "coercion key is %!T, arr_idx %ld",
- (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
- }
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_BYTE_LENGTH(thr) ||
- key == DUK_HTHREAD_STRING_BYTE_OFFSET(thr) ||
- key == DUK_HTHREAD_STRING_BYTES_PER_ELEMENT(thr)) {
- goto fail_not_writable;
- }
-
- DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from buffer prototype"));
- curr = thr->builtins[DUK_BIDX_BUFFER_PROTOTYPE];
- goto lookup; /* avoid double coercion */
- }
-
- case DUK_TAG_POINTER: {
- DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
- curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
- break;
- }
-
- case DUK_TAG_LIGHTFUNC: {
- /* All lightfunc own properties are non-writable and the lightfunc
- * is considered non-extensible. However, the write may be captured
- * by an inherited setter which means we can't stop the lookup here.
- */
-
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
-
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- goto fail_not_writable;
- }
-
- DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
- curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
- goto lookup; /* avoid double coercion */
- }
-
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default: {
- /* number */
- DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
- curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
- break;
- }
- }
-
- DUK_ASSERT(key == NULL);
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
-
- lookup:
-
- /*
- * Check whether the property already exists in the prototype chain.
- * Note that the actual write goes into the original base object
- * (except if an accessor property captures the write).
- */
-
- /* [key] */
-
- DUK_ASSERT(curr != NULL);
- sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
- do {
- if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
- goto next_in_chain;
- }
-
- if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- /*
- * Found existing accessor property (own or inherited).
- * Call setter with 'this' set to orig, and value as the only argument.
- * Setter calls are OK even for ROM objects.
- *
- * Note: no exotic arguments object behavior, because [[Put]] never
- * calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b).
- */
-
- duk_hobject *setter;
-
- DUK_DD(DUK_DDPRINT("put to an own or inherited accessor, calling setter"));
-
- setter = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, curr, desc.e_idx);
- if (!setter) {
- goto fail_no_setter;
- }
- duk_push_hobject(ctx, setter);
- duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
- duk_push_tval(ctx, tv_val); /* [key setter this val] */
-#ifdef DUK_USE_NONSTD_SETTER_KEY_ARGUMENT
- duk_dup(ctx, -4);
- duk_call_method(ctx, 2); /* [key setter this val key] -> [key retval] */
-#else
- duk_call_method(ctx, 1); /* [key setter this val] -> [key retval] */
-#endif
- duk_pop(ctx); /* ignore retval -> [key] */
- goto success_no_arguments_exotic;
- }
-
- if (orig == NULL) {
- /*
- * Found existing own or inherited plain property, but original
- * base is a primitive value.
- */
- DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
- goto fail_base_primitive;
- }
-
- if (curr != orig) {
- /*
- * Found existing inherited plain property.
- * Do an access control check, and if OK, write
- * new property to 'orig'.
- */
- if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
- DUK_DD(DUK_DDPRINT("found existing inherited plain property, but original object is not extensible"));
- goto fail_not_extensible;
- }
- if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- DUK_DD(DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable"));
- goto fail_not_writable;
- }
- DUK_DD(DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable"));
- goto create_new;
- } else {
- /*
- * Found existing own (non-inherited) plain property.
- * Do an access control check and update in place.
- */
-
- if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- DUK_DD(DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable"));
- goto fail_not_writable;
- }
- if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
- DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable"));
- if (DUK_HOBJECT_IS_BUFFEROBJECT(curr)) {
- duk_hbufferobject *h_bufobj;
- duk_uint_t byte_off;
- duk_small_uint_t elem_size;
-
- h_bufobj = (duk_hbufferobject *) curr;
- DUK_ASSERT_HBUFFEROBJECT_VALID(h_bufobj);
-
- DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object"));
-
- /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
- * length downshift won't.
- */
- if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
- duk_uint8_t *data;
- DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
-
- DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */
- byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
- elem_size = 1 << h_bufobj->shift;
-
- /* Coerce to number before validating pointers etc so that the
- * number coercions in duk_hbufferobject_validated_write() are
- * guaranteed to be side effect free and not invalidate the
- * pointer checks we do here.
- */
- duk_push_tval(ctx, tv_val);
- duk_to_number(ctx, -1);
-
- if (h_bufobj->buf != NULL && DUK_HBUFFEROBJECT_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
- data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
- duk_hbufferobject_validated_write(ctx, h_bufobj, data, elem_size);
- } else {
- DUK_D(DUK_DPRINT("bufferobject access out of underlying buffer, ignoring (write skipped)"));
- }
- duk_pop(ctx);
- goto success_no_arguments_exotic;
- }
- }
-
- goto fail_internal; /* should not happen */
- }
- DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable"));
- goto update_old;
- }
- DUK_UNREACHABLE();
-
- next_in_chain:
- /* XXX: option to pretend property doesn't exist if sanity limit is
- * hit might be useful.
- */
- if (sanity-- == 0) {
- DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
- }
- curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
- } while (curr);
-
- /*
- * Property not found in prototype chain.
- */
-
- DUK_DDD(DUK_DDDPRINT("property not found in prototype chain"));
-
- if (orig == NULL) {
- DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
- goto fail_base_primitive;
- }
-
- if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
- DUK_DD(DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible"));
- goto fail_not_extensible;
- }
-
- goto create_new;
-
- update_old:
-
- /*
- * Update an existing property of the base object.
- */
-
- /* [key] */
-
- DUK_DDD(DUK_DDDPRINT("update an existing property of the original object"));
-
- DUK_ASSERT(orig != NULL);
-#if defined(DUK_USE_ROM_OBJECTS)
- /* This should not happen because DUK_TAG_OBJECT case checks
- * for this already, but check just in case.
- */
- if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
- goto fail_not_writable;
- }
-#endif
-
- /* Although there are writable virtual properties (e.g. plain buffer
- * and buffer object number indices), they are handled before we come
- * here.
- */
- DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
- DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
-
- if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
- key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- /*
- * Write to 'length' of an array is a very complex case
- * handled in a helper which updates both the array elements
- * and writes the new 'length'. The write may result in an
- * unconditional RangeError or a partial write (indicated
- * by a return code).
- *
- * Note: the helper has an unnecessary writability check
- * for 'length', we already know it is writable.
- */
-
- DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper"));
-
- /* XXX: the helper currently assumes stack top contains new
- * 'length' value and the whole calling convention is not very
- * compatible with what we need.
- */
-
- duk_push_tval(ctx, tv_val); /* [key val] */
- rc = duk__handle_put_array_length(thr, orig);
- duk_pop(ctx); /* [key val] -> [key] */
- if (!rc) {
- goto fail_array_length_partial;
- }
-
- /* key is 'length', cannot match argument exotic behavior */
- goto success_no_arguments_exotic;
- }
-
- if (desc.e_idx >= 0) {
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
- DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv));
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
- /* don't touch property attributes or hash part */
- DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT",
- (long) desc.e_idx, (duk_tval *) tv));
- } else {
- /* Note: array entries are always writable, so the writability check
- * above is pointless for them. The check could be avoided with some
- * refactoring but is probably not worth it.
- */
-
- DUK_ASSERT(desc.a_idx >= 0);
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx);
- DUK_DDD(DUK_DDDPRINT("previous array value: %!iT", (duk_tval *) tv));
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
- DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT",
- (long) desc.a_idx, (duk_tval *) tv));
- }
-
- /* Regardless of whether property is found in entry or array part,
- * it may have arguments exotic behavior (array indices may reside
- * in entry part for abandoned / non-existent array parts).
- */
- goto success_with_arguments_exotic;
-
- create_new:
-
- /*
- * Create a new property in the original object.
- *
- * Exotic properties need to be reconsidered here from a write
- * perspective (not just property attributes perspective).
- * However, the property does not exist in the object already,
- * so this limits the kind of exotic properties that apply.
- */
-
- /* [key] */
-
- DUK_DDD(DUK_DDDPRINT("create new property to original object"));
-
- DUK_ASSERT(orig != NULL);
-
-#if defined(DUK_USE_ROM_OBJECTS)
- /* This should not happen because DUK_TAG_OBJECT case checks
- * for this already, but check just in case.
- */
- if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
- goto fail_not_writable;
- }
-#endif
-
- /* Not possible because array object 'length' is present
- * from its creation and cannot be deleted, and is thus
- * caught as an existing property above.
- */
- DUK_ASSERT(!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
- key == DUK_HTHREAD_STRING_LENGTH(thr)));
-
- if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
- arr_idx != DUK__NO_ARRAY_INDEX) {
- /* automatic length update */
- duk_uint32_t old_len;
-
- old_len = duk__get_old_array_length(thr, orig, &desc);
-
- if (arr_idx >= old_len) {
- DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
- "(arr_idx=%ld, old_len=%ld)",
- (long) arr_idx, (long) old_len));
-
- if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable"));
- goto fail_not_writable;
- }
-
- /* Note: actual update happens once write has been completed
- * without error below. The write should always succeed
- * from a specification viewpoint, but we may e.g. run out
- * of memory. It's safer in this order.
- */
-
- DUK_ASSERT(arr_idx != 0xffffffffUL);
- new_array_length = arr_idx + 1; /* flag for later write */
- } else {
- DUK_DDD(DUK_DDDPRINT("write new array entry does not require length update "
- "(arr_idx=%ld, old_len=%ld)",
- (long) arr_idx, (long) old_len));
- }
- }
-
- /* write_to_array_part: */
-
- /*
- * Write to array part?
- *
- * Note: array abandonding requires a property resize which uses
- * 'rechecks' valstack for temporaries and may cause any existing
- * valstack pointers to be invalidated. To protect against this,
- * tv_obj, tv_key, and tv_val are copies of the original inputs.
- */
-
- if (arr_idx != DUK__NO_ARRAY_INDEX &&
- DUK_HOBJECT_HAS_ARRAY_PART(orig)) {
- if (arr_idx < DUK_HOBJECT_GET_ASIZE(orig)) {
- goto no_array_growth;
- }
-
- /*
- * Array needs to grow, but we don't want it becoming too sparse.
- * If it were to become sparse, abandon array part, moving all
- * array entries into the entries part (for good).
- *
- * Since we don't keep track of actual density (used vs. size) of
- * the array part, we need to estimate somehow. The check is made
- * in two parts:
- *
- * - Check whether the resize need is small compared to the
- * current size (relatively); if so, resize without further
- * checking (essentially we assume that the original part is
- * "dense" so that the result would be dense enough).
- *
- * - Otherwise, compute the resize using an actual density
- * measurement based on counting the used array entries.
- */
-
- DUK_DDD(DUK_DDDPRINT("write to new array requires array resize, decide whether to do a "
- "fast resize without abandon check (arr_idx=%ld, old_size=%ld)",
- (long) arr_idx, (long) DUK_HOBJECT_GET_ASIZE(orig)));
-
- if (duk__abandon_array_slow_check_required(arr_idx, DUK_HOBJECT_GET_ASIZE(orig))) {
- duk_uint32_t old_used;
- duk_uint32_t old_size;
-
- DUK_DDD(DUK_DDDPRINT("=> fast check is NOT OK, do slow check for array abandon"));
-
- duk__compute_a_stats(thr, orig, &old_used, &old_size);
-
- DUK_DDD(DUK_DDDPRINT("abandon check, array stats: old_used=%ld, old_size=%ld, arr_idx=%ld",
- (long) old_used, (long) old_size, (long) arr_idx));
-
- /* Note: intentionally use approximations to shave a few instructions:
- * a_used = old_used (accurate: old_used + 1)
- * a_size = arr_idx (accurate: arr_idx + 1)
- */
- if (duk__abandon_array_density_check(old_used, arr_idx)) {
- DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
- "decided to abandon array part (would become too sparse)"));
-
- /* abandoning requires a props allocation resize and
- * 'rechecks' the valstack, invalidating any existing
- * valstack value pointers!
- */
- duk__abandon_array_checked(thr, orig);
- DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig));
-
- goto write_to_entry_part;
- }
-
- DUK_DDD(DUK_DDDPRINT("=> decided to keep array part"));
- } else {
- DUK_DDD(DUK_DDDPRINT("=> fast resize is OK"));
- }
-
- DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
- "decided to extend current allocation"));
-
- duk__grow_props_for_array_item(thr, orig, arr_idx);
-
- no_array_growth:
-
- /* Note: assume array part is comprehensive, so that either
- * the write goes to the array part, or we've abandoned the
- * array above (and will not come here).
- */
-
- DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(orig));
- DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(orig));
-
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, arr_idx);
- /* prev value must be unused, no decref */
- DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
- DUK_TVAL_SET_TVAL(tv, tv_val);
- DUK_TVAL_INCREF(thr, tv);
- DUK_DD(DUK_DDPRINT("put to new array entry: %ld -> %!T",
- (long) arr_idx, (duk_tval *) tv));
-
- /* Note: array part values are [[Writable]], [[Enumerable]],
- * and [[Configurable]] which matches the required attributes
- * here.
- */
- goto entry_updated;
- }
-
- write_to_entry_part:
-
- /*
- * Write to entry part
- */
-
- /* entry allocation updates hash part and increases the key
- * refcount; may need a props allocation resize but doesn't
- * 'recheck' the valstack.
- */
- e_idx = duk__alloc_entry_checked(thr, orig, key);
- DUK_ASSERT(e_idx >= 0);
-
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx);
- /* prev value can be garbage, no decref */
- DUK_TVAL_SET_TVAL(tv, tv_val);
- DUK_TVAL_INCREF(thr, tv);
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, orig, e_idx, DUK_PROPDESC_FLAGS_WEC);
- goto entry_updated;
-
- entry_updated:
-
- /*
- * Possible pending array length update, which must only be done
- * if the actual entry write succeeded.
- */
-
- if (new_array_length > 0) {
- /*
- * Note: zero works as a "no update" marker because the new length
- * can never be zero after a new property is written.
- *
- * Note: must re-lookup because calls above (e.g. duk__alloc_entry_checked())
- * may realloc and compact properties and hence change e_idx.
- */
-
- DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld",
- (long) new_array_length));
-
- rc = duk__get_own_propdesc_raw(thr, orig, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &desc, 0 /*flags*/); /* don't push value */
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- DUK_ASSERT(desc.e_idx >= 0);
-
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- /* no need for decref/incref because value is a number */
- DUK_TVAL_SET_FASTINT_U32(tv, new_array_length);
- }
-
- /*
- * Arguments exotic behavior not possible for new properties: all
- * magically bound properties are initially present in the arguments
- * object, and if they are deleted, the binding is also removed from
- * parameter map.
- */
-
- goto success_no_arguments_exotic;
-
- success_with_arguments_exotic:
-
- /*
- * Arguments objects have exotic [[DefineOwnProperty]] which updates
- * the internal 'map' of arguments for writes to currently mapped
- * arguments. More conretely, writes to mapped arguments generate
- * a write to a bound variable.
- *
- * The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing
- * data properties and new properties, but not for existing accessors.
- * Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we
- * have a Desc with 'Value' (and possibly other properties too), and
- * we end up in step 5.b.i.
- */
-
- if (arr_idx != DUK__NO_ARRAY_INDEX &&
- DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
- /* Note: only numbered indices are relevant, so arr_idx fast reject
- * is good (this is valid unless there are more than 4**32-1 arguments).
- */
-
- DUK_DDD(DUK_DDDPRINT("putprop successful, arguments exotic behavior needed"));
-
- /* Note: we can reuse 'desc' here */
-
- /* XXX: top of stack must contain value, which helper doesn't touch,
- * rework to use tv_val directly?
- */
-
- duk_push_tval(ctx, tv_val);
- (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
- duk_pop(ctx);
- }
- /* fall thru */
-
- success_no_arguments_exotic:
- /* shared exit path now */
- DUK_DDD(DUK_DDDPRINT("result: success"));
- duk_pop(ctx); /* remove key */
- return 1;
-
-#if defined(DUK_USE_ES6_PROXY)
- fail_proxy_rejected:
- DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects"));
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
- }
- /* Note: no key on stack */
- return 0;
-#endif
-
- fail_base_primitive:
- DUK_DDD(DUK_DDDPRINT("result: error, base primitive"));
- if (throw_flag) {
-#if defined(DUK_USE_PARANOID_ERRORS)
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
-#else
- DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
- duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
-#endif
- }
- duk_pop(ctx); /* remove key */
- return 0;
-
- fail_not_extensible:
- DUK_DDD(DUK_DDDPRINT("result: error, not extensible"));
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
- }
- duk_pop(ctx); /* remove key */
- return 0;
-
- fail_not_writable:
- DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
- }
- duk_pop(ctx); /* remove key */
- return 0;
-
-#if defined(DUK_USE_ROM_OBJECTS)
- fail_not_writable_no_pop:
- DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
- }
- return 0;
-#endif
-
- fail_array_length_partial:
- DUK_DDD(DUK_DDDPRINT("result: error, array length write only partially successful"));
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_WRITE_FAILED);
- }
- duk_pop(ctx); /* remove key */
- return 0;
-
- fail_no_setter:
- DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter"));
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
- }
- duk_pop(ctx); /* remove key */
- return 0;
-
- fail_internal:
- DUK_DDD(DUK_DDDPRINT("result: error, internal"));
- if (throw_flag) {
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- }
- duk_pop(ctx); /* remove key */
- return 0;
-}
-
-/*
- * Ecmascript compliant [[Delete]](P, Throw).
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
- duk_propdesc desc;
- duk_tval *tv;
- duk_uint32_t arr_idx;
- duk_bool_t throw_flag;
- duk_bool_t force_flag;
-
- throw_flag = (flags & DUK_DELPROP_FLAG_THROW);
- force_flag = (flags & DUK_DELPROP_FLAG_FORCE);
-
- DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)",
- (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag,
- (duk_heaphdr *) obj, (duk_heaphdr *) key));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
-
- /* 0 = don't push current value */
- if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
- DUK_DDD(DUK_DDDPRINT("property not found, succeed always"));
- goto success;
- }
-
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
- DUK_DD(DUK_DDPRINT("attempt to delprop on read-only target object"));
- goto fail_not_configurable;
- }
-#endif
-
- if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0 && !force_flag) {
- goto fail_not_configurable;
- }
- if (desc.a_idx < 0 && desc.e_idx < 0) {
- /* Currently there are no deletable virtual properties, but
- * with force_flag we might attempt to delete one.
- */
- goto fail_virtual;
- }
-
- if (desc.a_idx >= 0) {
- DUK_ASSERT(desc.e_idx < 0);
-
- tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
- DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
- goto success;
- } else {
- DUK_ASSERT(desc.a_idx < 0);
-
- /* remove hash entry (no decref) */
-#if defined(DUK_USE_HOBJECT_HASH_PART)
- if (desc.h_idx >= 0) {
- duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
-
- DUK_DDD(DUK_DDDPRINT("removing hash entry at h_idx %ld", (long) desc.h_idx));
- DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) > 0);
- DUK_ASSERT((duk_uint32_t) desc.h_idx < DUK_HOBJECT_GET_HSIZE(obj));
- h_base[desc.h_idx] = DUK__HASH_DELETED;
- } else {
- DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
- }
-#else
- DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
-#endif
-
- /* remove value */
- DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p",
- (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
- DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx));
- if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) {
- duk_hobject *tmp;
-
- tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
- DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
- DUK_UNREF(tmp);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
-
- tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
- DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
- DUK_UNREF(tmp);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
- } else {
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
- }
-#if 0
- /* Not strictly necessary because if key == NULL, flag MUST be ignored. */
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0);
-#endif
-
- /* remove key */
- DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p",
- (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
- DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx));
- DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx));
- DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL);
- DUK_HSTRING_DECREF(thr, key); /* side effects */
- goto success;
- }
-
- DUK_UNREACHABLE();
-
- success:
- /*
- * Argument exotic [[Delete]] behavior (E5 Section 10.6) is
- * a post-check, keeping arguments internal 'map' in sync with
- * any successful deletes (note that property does not need to
- * exist for delete to 'succeed').
- *
- * Delete key from 'map'. Since 'map' only contains array index
- * keys, we can use arr_idx for a fast skip.
- */
-
- DUK_DDD(DUK_DDDPRINT("delete successful, check for arguments exotic behavior"));
-
- if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
- /* Note: only numbered indices are relevant, so arr_idx fast reject
- * is good (this is valid unless there are more than 4**32-1 arguments).
- */
-
- DUK_DDD(DUK_DDDPRINT("delete successful, arguments exotic behavior needed"));
-
- /* Note: we can reuse 'desc' here */
- (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc);
- }
-
- DUK_DDD(DUK_DDDPRINT("delete successful"));
- return 1;
-
- fail_virtual:
- DUK_DDD(DUK_DDDPRINT("delete failed: property found, force flag, but virtual"));
-
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROPERTY_IS_VIRTUAL);
- }
- return 0;
-
- fail_not_configurable:
- DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable"));
-
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
- }
- return 0;
-}
-
-/*
- * DELPROP: Ecmascript property deletion.
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
- duk_hstring *key = NULL;
-#if defined(DUK_USE_ES6_PROXY)
- duk_propdesc desc;
-#endif
- duk_int_t entry_top;
- duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
- duk_bool_t rc;
-
- DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
- (void *) thr, (void *) tv_obj, (void *) tv_key,
- (duk_tval *) tv_obj, (duk_tval *) tv_key));
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(tv_obj != NULL);
- DUK_ASSERT(tv_key != NULL);
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /* Storing the entry top is cheaper here to ensure stack is correct at exit,
- * as there are several paths out.
- */
- entry_top = duk_get_top(ctx);
-
- if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
- DUK_TVAL_IS_NULL(tv_obj)) {
- DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
- goto fail_invalid_base_uncond;
- }
-
- duk_push_tval(ctx, tv_obj);
- duk_push_tval(ctx, tv_key);
-
- tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -2);
- if (DUK_TVAL_IS_OBJECT(tv_obj)) {
- duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
- DUK_ASSERT(obj != NULL);
-
-#if defined(DUK_USE_ES6_PROXY)
- if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
- duk_hobject *h_target;
- duk_bool_t tmp_bool;
-
- /* Note: proxy handling must happen before key is string coerced. */
-
- if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) {
- /* -> [ ... trap handler ] */
- DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key));
- duk_push_hobject(ctx, h_target); /* target */
- duk_push_tval(ctx, tv_key); /* P */
- duk_call_method(ctx, 2 /*nargs*/);
- tmp_bool = duk_to_boolean(ctx, -1);
- duk_pop(ctx);
- if (!tmp_bool) {
- goto fail_proxy_rejected; /* retval indicates delete failed */
- }
-
- /* Target object must be checked for a conflicting
- * non-configurable property.
- */
- arr_idx = duk__push_tval_to_hstring_arr_idx(ctx, tv_key, &key);
- DUK_ASSERT(key != NULL);
-
- if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
- int desc_reject;
-
- DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for "
- "conflicting property; desc.flags=0x%08lx, "
- "desc.get=%p, desc.set=%p",
- (duk_heaphdr *) key, (unsigned long) desc.flags,
- (void *) desc.get, (void *) desc.set));
-
- desc_reject = !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE);
- if (desc_reject) {
- /* unconditional */
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
- }
- }
- rc = 1; /* success */
- goto done_rc;
- }
-
- obj = h_target; /* resume delete to target */
- }
-#endif /* DUK_USE_ES6_PROXY */
-
- duk_to_string(ctx, -1);
- key = duk_get_hstring(ctx, -1);
- DUK_ASSERT(key != NULL);
-
- rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0);
- goto done_rc;
- } else if (DUK_TVAL_IS_STRING(tv_obj)) {
- /* XXX: unnecessary string coercion for array indices,
- * intentional to keep small.
- */
- duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
- DUK_ASSERT(h != NULL);
-
- duk_to_string(ctx, -1);
- key = duk_get_hstring(ctx, -1);
- DUK_ASSERT(key != NULL);
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- goto fail_not_configurable;
- }
-
- arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
-
- if (arr_idx != DUK__NO_ARRAY_INDEX &&
- arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
- goto fail_not_configurable;
- }
- } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
- /* XXX: unnecessary string coercion for array indices,
- * intentional to keep small; some overlap with string
- * handling.
- */
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
- DUK_ASSERT(h != NULL);
-
- duk_to_string(ctx, -1);
- key = duk_get_hstring(ctx, -1);
- DUK_ASSERT(key != NULL);
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- goto fail_not_configurable;
- }
-
- arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
-
- if (arr_idx != DUK__NO_ARRAY_INDEX &&
- arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
- goto fail_not_configurable;
- }
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
- /* Lightfunc virtual properties are non-configurable, so
- * reject if match any of them.
- */
-
- duk_to_string(ctx, -1);
- key = duk_get_hstring(ctx, -1);
- DUK_ASSERT(key != NULL);
-
- if (duk__key_is_lightfunc_ownprop(thr, key)) {
- goto fail_not_configurable;
- }
- }
-
- /* non-object base, no offending virtual property */
- rc = 1;
- goto done_rc;
-
- done_rc:
- duk_set_top(ctx, entry_top);
- return rc;
-
- fail_invalid_base_uncond:
- /* Note: unconditional throw */
- DUK_ASSERT(duk_get_top(ctx) == entry_top);
-#if defined(DUK_USE_PARANOID_ERRORS)
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
-#else
- DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
- duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
-#endif
- return 0;
-
-#if defined(DUK_USE_ES6_PROXY)
- fail_proxy_rejected:
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
- }
- duk_set_top(ctx, entry_top);
- return 0;
-#endif
-
- fail_not_configurable:
- if (throw_flag) {
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
- }
- duk_set_top(ctx, entry_top);
- return 0;
-}
-
-/*
- * Internal helper to define a property with specific flags, ignoring
- * normal semantics such as extensibility, write protection etc.
- * Overwrites any existing value and attributes unless caller requests
- * that value only be updated if it doesn't already exists.
- *
- * Does not support:
- * - virtual properties (error if write attempted)
- * - getter/setter properties (error if write attempted)
- * - non-default (!= WEC) attributes for array entries (error if attempted)
- * - array abandoning: if array part exists, it is always extended
- * - array 'length' updating
- *
- * Stack: [... in_val] -> []
- *
- * Used for e.g. built-in initialization and environment record
- * operations.
- */
-
-DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
- duk_propdesc desc;
- duk_uint32_t arr_idx;
- duk_int_t e_idx;
- duk_tval *tv1 = NULL;
- duk_tval *tv2 = NULL;
- duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK; /* mask out flags not actually stored */
-
- DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
- (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
- (unsigned long) flags, (duk_tval *) duk_get_tval(ctx, -1)));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
- DUK_ASSERT(duk_is_valid_index(ctx, -1)); /* contains value */
-
- arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
-
- if (duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
- if (desc.e_idx >= 0) {
- if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
- DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> skip as requested"));
- goto pop_exit;
- }
- DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> update value and attributes"));
- if (DUK_UNLIKELY(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx))) {
- DUK_D(DUK_DPRINT("existing property is an accessor, not supported"));
- goto error_internal;
- }
-
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, propflags);
- tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
- } else if (desc.a_idx >= 0) {
- if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
- DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> skip as requested"));
- goto pop_exit;
- }
- DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)"));
- if (propflags != DUK_PROPDESC_FLAGS_WEC) {
- DUK_D(DUK_DPRINT("existing property in array part, but propflags not WEC (0x%02lx)",
- (unsigned long) propflags));
- goto error_internal;
- }
-
- tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
- } else {
- if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
- DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested"));
- goto pop_exit;
- }
- DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> failure"));
- goto error_virtual;
- }
-
- goto write_value;
- }
-
- if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
- if (arr_idx != DUK__NO_ARRAY_INDEX) {
- DUK_DDD(DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)"));
- DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC);
-
- /* always grow the array, no sparse / abandon support here */
- if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
- duk__grow_props_for_array_item(thr, obj, arr_idx);
- }
-
- DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
- tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
- goto write_value;
- }
- }
-
- DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes"));
- e_idx = duk__alloc_entry_checked(thr, obj, key); /* increases key refcount */
- DUK_ASSERT(e_idx >= 0);
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags);
- tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
- /* new entry: previous value is garbage; set to undefined to share write_value */
- DUK_TVAL_SET_UNDEFINED(tv1);
- goto write_value;
-
- write_value:
- /* tv1 points to value storage */
-
- tv2 = duk_require_tval(ctx, -1); /* late lookup, avoid side effects */
- DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T",
- (duk_tval *) tv1, (duk_tval *) tv2));
-
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- goto pop_exit;
-
- pop_exit:
- duk_pop(ctx); /* remove in_val */
- return;
-
- error_internal:
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- return;
-
- error_virtual:
- DUK_ERROR_TYPE(thr, DUK_STR_REDEFINE_VIRT_PROP);
- return;
-}
-
-/*
- * Fast path for defining array indexed values without interning the key.
- * This is used by e.g. code for Array prototype and traceback creation so
- * must avoid interning.
- */
-
-DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
- duk_hstring *key;
- duk_tval *tv1, *tv2;
-
- DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
- "arr_idx=%ld, flags=0x%02lx, val=%!T",
- (void *) thr, obj, (long) arr_idx, (unsigned long) flags,
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
-
- if (DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
- arr_idx != DUK__NO_ARRAY_INDEX &&
- flags == DUK_PROPDESC_FLAGS_WEC) {
- DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0); /* covered by comparison */
-
- DUK_DDD(DUK_DDDPRINT("define property to array part (property may or may not exist yet)"));
-
- /* always grow the array, no sparse / abandon support here */
- if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
- duk__grow_props_for_array_item(thr, obj, arr_idx);
- }
-
- DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
- tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
- tv2 = duk_require_tval(ctx, -1);
-
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
-
- duk_pop(ctx); /* [ ...val ] -> [ ... ] */
- return;
- }
-
- DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path"));
-
- duk_push_uint(ctx, (duk_uint_t) arr_idx);
- key = duk_to_hstring(ctx, -1);
- DUK_ASSERT(key != NULL);
- duk_insert(ctx, -2); /* [ ... val key ] -> [ ... key val ] */
-
- duk_hobject_define_property_internal(thr, obj, key, flags);
-
- duk_pop(ctx); /* [ ... key ] -> [ ... ] */
-}
-
-/*
- * Internal helper for defining an accessor property, ignoring
- * normal semantics such as extensibility, write protection etc.
- * Overwrites any existing value and attributes. This is called
- * very rarely, so the implementation first sets a value to undefined
- * and then changes the entry to an accessor (this is to save code space).
- */
-
-DUK_INTERNAL void duk_hobject_define_accessor_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_hobject *getter, duk_hobject *setter, duk_small_uint_t propflags) {
- duk_context *ctx = (duk_context *) thr;
- duk_int_t e_idx;
- duk_int_t h_idx;
-
- DUK_DDD(DUK_DDDPRINT("define new accessor (internal): thr=%p, obj=%!O, key=%!O, "
- "getter=%!O, setter=%!O, flags=0x%02lx",
- (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
- (duk_heaphdr *) getter, (duk_heaphdr *) setter,
- (unsigned long) propflags));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- DUK_ASSERT((propflags & ~DUK_PROPDESC_FLAGS_MASK) == 0);
- /* setter and/or getter may be NULL */
- DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /* force the property to 'undefined' to create a slot for it */
- duk_push_undefined(ctx);
- duk_hobject_define_property_internal(thr, obj, key, propflags);
- duk_hobject_find_existing_entry(thr->heap, obj, key, &e_idx, &h_idx);
- DUK_DDD(DUK_DDDPRINT("accessor slot: e_idx=%ld, h_idx=%ld", (long) e_idx, (long) h_idx));
- DUK_ASSERT(e_idx >= 0);
- DUK_ASSERT((duk_uint32_t) e_idx < DUK_HOBJECT_GET_ENEXT(obj));
-
- /* no need to decref, as previous value is 'undefined' */
- DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, e_idx);
- DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, getter);
- DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, setter);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, getter);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, setter);
-}
-
-/*
- * Internal helpers for managing object 'length'
- */
-
-/* XXX: awkward helpers */
-
-DUK_INTERNAL void duk_hobject_set_length(duk_hthread *thr, duk_hobject *obj, duk_uint32_t length) {
- duk_context *ctx = (duk_context *) thr;
- duk_push_hobject(ctx, obj);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
- duk_push_u32(ctx, length);
- (void) duk_hobject_putprop(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -3),
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1),
- 0);
- duk_pop_n(ctx, 3);
-}
-
-DUK_INTERNAL void duk_hobject_set_length_zero(duk_hthread *thr, duk_hobject *obj) {
- duk_hobject_set_length(thr, obj, 0);
-}
-
-DUK_INTERNAL duk_uint32_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
- duk_context *ctx = (duk_context *) thr;
- duk_double_t val;
- duk_push_hobject(ctx, obj);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
- (void) duk_hobject_getprop(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1));
- val = duk_to_number(ctx, -1);
- duk_pop_n(ctx, 3);
- if (val >= 0.0 && val < DUK_DOUBLE_2TO32) {
- return (duk_uint32_t) val;
- }
- return 0;
-}
-
-/*
- * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4)
- *
- * This is an actual function call.
- */
-
-DUK_INTERNAL duk_ret_t duk_hobject_object_get_own_property_descriptor(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hobject *obj;
- duk_hstring *key;
- duk_propdesc pd;
- duk_bool_t rc;
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
-
- obj = duk_require_hobject_or_lfunc_coerce(ctx, 0);
- (void) duk_to_string(ctx, 1);
- key = duk_require_hstring(ctx, 1);
-
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- rc = duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE);
- if (!rc) {
- duk_push_undefined(ctx);
-
- /* [obj key undefined] */
- return 1;
- }
-
- duk_push_object(ctx);
-
- /* [obj key value desc] */
-
- if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
- /* If a setter/getter is missing (undefined), the descriptor must
- * still have the property present with the value 'undefined'.
- */
- if (pd.get) {
- duk_push_hobject(ctx, pd.get);
- } else {
- duk_push_undefined(ctx);
- }
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_GET);
- if (pd.set) {
- duk_push_hobject(ctx, pd.set);
- } else {
- duk_push_undefined(ctx);
- }
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_SET);
- } else {
- duk_dup(ctx, -2); /* [obj key value desc value] */
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_VALUE);
- duk_push_boolean(ctx, DUK_PROPDESC_IS_WRITABLE(&pd));
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_WRITABLE);
-
- /* [obj key value desc] */
- }
- duk_push_boolean(ctx, DUK_PROPDESC_IS_ENUMERABLE(&pd));
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
- duk_push_boolean(ctx, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
-
- /* [obj key value desc] */
- return 1;
-}
-
-/*
- * NormalizePropertyDescriptor() related helper.
- *
- * Internal helper which validates and normalizes a property descriptor
- * represented as an Ecmascript object (e.g. argument to defineProperty()).
- * The output of this conversion is a set of defprop_flags and possibly
- * some values pushed on the value stack; some subset of: property value,
- * getter, setter. Caller must manage stack top carefully because the
- * number of values pushed depends on the input property descriptor.
- *
- * The original descriptor object must not be altered in the process.
- */
-
-/* XXX: very basic optimization -> duk_get_prop_stridx_top */
-
-DUK_INTERNAL
-void duk_hobject_prepare_property_descriptor(duk_context *ctx,
- duk_idx_t idx_in,
- duk_uint_t *out_defprop_flags,
- duk_idx_t *out_idx_value,
- duk_hobject **out_getter,
- duk_hobject **out_setter) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_idx_t idx_value = -1;
- duk_hobject *getter = NULL;
- duk_hobject *setter = NULL;
- duk_bool_t is_data_desc = 0;
- duk_bool_t is_acc_desc = 0;
- duk_uint_t defprop_flags = 0;
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(out_defprop_flags != NULL);
- DUK_ASSERT(out_idx_value != NULL);
- DUK_ASSERT(out_getter != NULL);
- DUK_ASSERT(out_setter != NULL);
-
- /* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */
- idx_in = duk_require_normalize_index(ctx, idx_in);
- (void) duk_require_hobject(ctx, idx_in);
-
- /* The coercion order must match the ToPropertyDescriptor() algorithm
- * so that side effects in coercion happen in the correct order.
- * (This order also happens to be compatible with duk_def_prop(),
- * although it doesn't matter in practice.)
- */
-
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_VALUE)) {
- is_data_desc = 1;
- defprop_flags |= DUK_DEFPROP_HAVE_VALUE;
- idx_value = duk_get_top_index(ctx);
- /* Leave 'value' on stack */
- } else {
- duk_pop(ctx);
- }
-
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_WRITABLE)) {
- is_data_desc = 1;
- if (duk_to_boolean(ctx, -1)) {
- defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
- } else {
- defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
- }
- }
- duk_pop(ctx);
-
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_GET)) {
- duk_tval *tv = duk_require_tval(ctx, -1);
- duk_hobject *h_get;
-
- if (DUK_TVAL_IS_UNDEFINED(tv)) {
- /* undefined is accepted */
- DUK_ASSERT(getter == NULL);
- } else {
- /* NOTE: lightfuncs are coerced to full functions because
- * lightfuncs don't fit into a property value slot. This
- * has some side effects, see test-dev-lightfunc-accessor.js.
- */
- h_get = duk_get_hobject_or_lfunc_coerce(ctx, -1);
- if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) {
- goto type_error;
- }
- getter = h_get;
- }
- is_acc_desc = 1;
- defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
- /* Leave 'getter' on stack */
- } else {
- duk_pop(ctx);
- }
-
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_SET)) {
- duk_tval *tv = duk_require_tval(ctx, -1);
- duk_hobject *h_set;
-
- if (DUK_TVAL_IS_UNDEFINED(tv)) {
- /* undefined is accepted */
- DUK_ASSERT(setter == NULL);
- } else {
- /* NOTE: lightfuncs are coerced to full functions because
- * lightfuncs don't fit into a property value slot. This
- * has some side effects, see test-dev-lightfunc-accessor.js.
- */
- h_set = duk_get_hobject_or_lfunc_coerce(ctx, -1);
- if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) {
- goto type_error;
- }
- setter = h_set;
- }
- is_acc_desc = 1;
- defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
- /* Leave 'setter' on stack */
- } else {
- duk_pop(ctx);
- }
-
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_ENUMERABLE)) {
- if (duk_to_boolean(ctx, -1)) {
- defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
- } else {
- defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
- }
- }
- duk_pop(ctx);
-
- if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_CONFIGURABLE)) {
- if (duk_to_boolean(ctx, -1)) {
- defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
- } else {
- defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
- }
- }
- duk_pop(ctx);
-
- if (is_data_desc && is_acc_desc) {
- goto type_error;
- }
-
- *out_defprop_flags = defprop_flags;
- *out_idx_value = idx_value;
- *out_getter = getter;
- *out_setter = setter;
-
- /* [ ... value? getter? setter? ] */
- return;
-
- type_error:
- DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
-}
-
-/*
- * Object.defineProperty() related helper (E5 Section 15.2.3.6)
- *
- * Inlines all [[DefineOwnProperty]] exotic behaviors.
- *
- * Note: Ecmascript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
- * implemented directly, but Object.defineProperty() serves its purpose.
- * We don't need the [[DefineOwnProperty]] internally and we don't have a
- * property descriptor with 'missing values' so it's easier to avoid it
- * entirely.
- *
- * Note: this is only called for actual objects, not primitive values.
- * This must support virtual properties for full objects (e.g. Strings)
- * but not for plain values (e.g. strings). Lightfuncs, even though
- * primitive in a sense, are treated like objects and accepted as target
- * values.
- */
-
-/* XXX: this is a major target for size optimization */
-DUK_INTERNAL
-void duk_hobject_define_property_helper(duk_context *ctx,
- duk_uint_t defprop_flags,
- duk_hobject *obj,
- duk_hstring *key,
- duk_idx_t idx_value,
- duk_hobject *get,
- duk_hobject *set) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_uint32_t arr_idx;
- duk_tval tv;
- duk_bool_t has_enumerable;
- duk_bool_t has_configurable;
- duk_bool_t has_writable;
- duk_bool_t has_value;
- duk_bool_t has_get;
- duk_bool_t has_set;
- duk_bool_t is_enumerable;
- duk_bool_t is_configurable;
- duk_bool_t is_writable;
- duk_bool_t throw_flag;
- duk_bool_t force_flag;
- duk_small_uint_t new_flags;
- duk_propdesc curr;
- duk_uint32_t arridx_new_array_length; /* != 0 => post-update for array 'length' (used when key is an array index) */
- duk_uint32_t arrlen_old_len;
- duk_uint32_t arrlen_new_len;
- duk_bool_t pending_write_protect;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(obj != NULL);
- DUK_ASSERT(key != NULL);
- /* idx_value may be < 0 (no value), set and get may be NULL */
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
- /* All the flags fit in 16 bits, so will fit into duk_bool_t. */
-
- has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE);
- has_enumerable = (defprop_flags & DUK_DEFPROP_HAVE_ENUMERABLE);
- has_configurable = (defprop_flags & DUK_DEFPROP_HAVE_CONFIGURABLE);
- has_value = (defprop_flags & DUK_DEFPROP_HAVE_VALUE);
- has_get = (defprop_flags & DUK_DEFPROP_HAVE_GETTER);
- has_set = (defprop_flags & DUK_DEFPROP_HAVE_SETTER);
- is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE);
- is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE);
- is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE);
- throw_flag = 1; /* Object.defineProperty() calls [[DefineOwnProperty]] with Throw=true */
- force_flag = (defprop_flags & DUK_DEFPROP_FORCE);
-
- arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
-
- arridx_new_array_length = 0;
- pending_write_protect = 0;
- arrlen_old_len = 0;
- arrlen_new_len = 0;
-
- DUK_DDD(DUK_DDDPRINT("has_enumerable=%ld is_enumerable=%ld "
- "has_configurable=%ld is_configurable=%ld "
- "has_writable=%ld is_writable=%ld "
- "has_value=%ld value=%!T "
- "has_get=%ld get=%p=%!O "
- "has_set=%ld set=%p=%!O "
- "arr_idx=%ld",
- (long) has_enumerable, (long) is_enumerable,
- (long) has_configurable, (long) is_configurable,
- (long) has_writable, (long) is_writable,
- (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(ctx, idx_value) : NULL),
- (long) has_get, (void *) get, (duk_heaphdr *) get,
- (long) has_set, (void *) set, (duk_heaphdr *) set,
- (long) arr_idx));
-
- /*
- * Array exotic behaviors can be implemented at this point. The local variables
- * are essentially a 'value copy' of the input descriptor (Desc), which is modified
- * by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1).
- */
-
- if (!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
- goto skip_array_exotic;
- }
-
- if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
- /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */
- if (!has_value) {
- DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior"));
- goto skip_array_exotic;
- }
-
- DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', value present in descriptor -> exotic behavior"));
-
- /*
- * Get old and new length
- */
-
- /* Note: reuse 'curr' as a temp propdesc */
- arrlen_old_len = duk__get_old_array_length(thr, obj, &curr);
-
- duk_dup(ctx, idx_value);
- arrlen_new_len = duk__to_new_array_length_checked(thr);
- duk_push_u32(ctx, arrlen_new_len);
- duk_replace(ctx, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
-
- DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len));
-
- if (arrlen_new_len >= arrlen_old_len) {
- /* standard behavior, step 3.f.i */
- DUK_DDD(DUK_DDDPRINT("new length is same or higher as previous => standard behavior"));
- goto skip_array_exotic;
- }
- DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior"));
-
- /* XXX: consolidated algorithm step 15.f -> redundant? */
- if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && !force_flag) {
- /* Note: 'curr' refers to 'length' propdesc */
- goto fail_not_writable_array_length;
- }
-
- /* steps 3.h and 3.i */
- if (has_writable && !is_writable) {
- DUK_DDD(DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect"));
- is_writable = 1;
- pending_write_protect = 1;
- }
-
- /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */
- } else if (arr_idx != DUK__NO_ARRAY_INDEX) {
- /* XXX: any chance of unifying this with the 'length' key handling? */
-
- /* E5 Section 15.4.5.1, step 4 */
- duk_uint32_t old_len;
-
- /* Note: use 'curr' as a temp propdesc */
- old_len = duk__get_old_array_length(thr, obj, &curr);
-
- if (arr_idx >= old_len) {
- DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update "
- "(arr_idx=%ld, old_len=%ld)",
- (long) arr_idx, (long) old_len));
-
- if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- /* Note: 'curr' refers to 'length' propdesc */
- goto fail_not_writable_array_length;
- }
-
- /* actual update happens once write has been completed without
- * error below.
- */
- DUK_ASSERT(arr_idx != 0xffffffffUL);
- arridx_new_array_length = arr_idx + 1;
- } else {
- DUK_DDD(DUK_DDDPRINT("defineProperty does not require length update "
- "(arr_idx=%ld, old_len=%ld) -> standard behavior",
- (long) arr_idx, (long) old_len));
- }
- }
- skip_array_exotic:
-
- /* XXX: There is currently no support for writing buffer object
- * indexed elements here. Attempt to do so will succeed and
- * write a concrete property into the buffer object. This should
- * be fixed at some point but because buffers are a custom feature
- * anyway, this is relatively unimportant.
- */
-
- /*
- * Actual Object.defineProperty() default algorithm.
- */
-
- /*
- * First check whether property exists; if not, simple case. This covers
- * steps 1-4.
- */
-
- if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE)) {
- DUK_DDD(DUK_DDDPRINT("property does not exist"));
-
- if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj) && !force_flag) {
- goto fail_not_extensible;
- }
-
- /* XXX: share final setting code for value and flags? difficult because
- * refcount code is different. Share entry allocation? But can't allocate
- * until array index checked.
- */
-
- /* steps 4.a and 4.b are tricky */
- if (has_set || has_get) {
- duk_int_t e_idx;
-
- DUK_DDD(DUK_DDDPRINT("create new accessor property"));
-
- DUK_ASSERT(has_set || set == NULL);
- DUK_ASSERT(has_get || get == NULL);
- DUK_ASSERT(!has_value);
- DUK_ASSERT(!has_writable);
-
- new_flags = DUK_PROPDESC_FLAG_ACCESSOR; /* defaults, E5 Section 8.6.1, Table 7 */
- if (has_enumerable && is_enumerable) {
- new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
- }
- if (has_configurable && is_configurable) {
- new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
- }
-
- if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
- DUK_DDD(DUK_DDDPRINT("accessor cannot go to array part, abandon array"));
- duk__abandon_array_checked(thr, obj);
- }
-
- /* write to entry part */
- e_idx = duk__alloc_entry_checked(thr, obj, key);
- DUK_ASSERT(e_idx >= 0);
-
- DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
- DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
-
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
- goto success_exotics;
- } else {
- duk_int_t e_idx;
- duk_tval *tv2;
-
- DUK_DDD(DUK_DDDPRINT("create new data property"));
-
- DUK_ASSERT(!has_set);
- DUK_ASSERT(!has_get);
-
- new_flags = 0; /* defaults, E5 Section 8.6.1, Table 7 */
- if (has_writable && is_writable) {
- new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
- }
- if (has_enumerable && is_enumerable) {
- new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
- }
- if (has_configurable && is_configurable) {
- new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
- }
- if (has_value) {
- duk_tval *tv_tmp = duk_require_tval(ctx, idx_value);
- DUK_TVAL_SET_TVAL(&tv, tv_tmp);
- } else {
- DUK_TVAL_SET_UNDEFINED(&tv); /* default value */
- }
-
- if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
- if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
-#if 0
- DUK_DDD(DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part"));
- /* may become sparse...*/
-#endif
- /* XXX: handling for array part missing now; this doesn't affect
- * compliance but causes array entry writes using defineProperty()
- * to always abandon array part.
- */
- }
- DUK_DDD(DUK_DDDPRINT("new data property cannot go to array part, abandon array"));
- duk__abandon_array_checked(thr, obj);
- /* fall through */
- }
-
- /* write to entry part */
- e_idx = duk__alloc_entry_checked(thr, obj, key);
- DUK_ASSERT(e_idx >= 0);
- tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
- DUK_TVAL_SET_TVAL(tv2, &tv);
- DUK_TVAL_INCREF(thr, tv2);
-
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
- goto success_exotics;
- }
- DUK_UNREACHABLE();
- }
-
- /* we currently assume virtual properties are not configurable (as none of them are) */
- DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE));
-
- /* [obj key desc value get set curr_value] */
-
- /*
- * Property already exists. Steps 5-6 detect whether any changes need
- * to be made.
- */
-
- if (has_enumerable) {
- if (is_enumerable) {
- if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) {
- goto need_check;
- }
- } else {
- if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
- goto need_check;
- }
- }
- }
- if (has_configurable) {
- if (is_configurable) {
- if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
- goto need_check;
- }
- } else {
- if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
- goto need_check;
- }
- }
- }
- if (has_value) {
- duk_tval *tmp1;
- duk_tval *tmp2;
-
- /* attempt to change from accessor to data property */
- if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- goto need_check;
- }
-
- tmp1 = duk_require_tval(ctx, -1); /* curr value */
- tmp2 = duk_require_tval(ctx, idx_value); /* new value */
- if (!duk_js_samevalue(tmp1, tmp2)) {
- goto need_check;
- }
- }
- if (has_writable) {
- /* attempt to change from accessor to data property */
- if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- goto need_check;
- }
-
- if (is_writable) {
- if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- goto need_check;
- }
- } else {
- if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) {
- goto need_check;
- }
- }
- }
- if (has_set) {
- if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- if (set != curr.set) {
- goto need_check;
- }
- } else {
- goto need_check;
- }
- }
- if (has_get) {
- if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- if (get != curr.get) {
- goto need_check;
- }
- } else {
- goto need_check;
- }
- }
-
- /* property exists, either 'desc' is empty, or all values
- * match (SameValue)
- */
- goto success_no_exotics;
-
- need_check:
-
- /*
- * Some change(s) need to be made. Steps 7-11.
- */
-
- /* shared checks for all descriptor types */
- if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
- if (has_configurable && is_configurable) {
- goto fail_not_configurable;
- }
- if (has_enumerable) {
- if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
- if (!is_enumerable) {
- goto fail_not_configurable;
- }
- } else {
- if (is_enumerable) {
- goto fail_not_configurable;
- }
- }
- }
- }
-
- /* Reject attempt to change virtual properties: not part of the
- * standard algorithm, applies currently to e.g. virtual index
- * properties of buffer objects (which are virtual but writable).
- * (Cannot "force" modification of a virtual property.)
- */
- if (curr.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
- goto fail_virtual;
- }
-
- /* Reject attempt to change a read-only object. */
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
- DUK_DD(DUK_DDPRINT("attempt to define property on read-only target object"));
- goto fail_not_configurable;
- }
-#endif
-
- /* descriptor type specific checks */
- if (has_set || has_get) {
- /* IsAccessorDescriptor(desc) == true */
- DUK_ASSERT(!has_writable);
- DUK_ASSERT(!has_value);
-
- if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- /* curr and desc are accessors */
- if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
- if (has_set && set != curr.set) {
- goto fail_not_configurable;
- }
- if (has_get && get != curr.get) {
- goto fail_not_configurable;
- }
- }
- } else {
- duk_bool_t rc;
- duk_tval *tv1;
-
- /* curr is data, desc is accessor */
- if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
- goto fail_not_configurable;
- }
-
- DUK_DDD(DUK_DDDPRINT("convert property to accessor property"));
- if (curr.a_idx >= 0) {
- DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup"));
- duk__abandon_array_checked(thr, obj);
- duk_pop(ctx); /* remove old value */
- rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
- }
-
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
-
- tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- /* XXX: just decref */
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
-
- DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
- DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
- DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
- DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, curr.e_idx);
-
- DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx",
- (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
-
- /* re-lookup to update curr.flags
- * XXX: would be faster to update directly
- */
- duk_pop(ctx); /* remove old value */
- rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- }
- } else if (has_value || has_writable) {
- /* IsDataDescriptor(desc) == true */
- DUK_ASSERT(!has_set);
- DUK_ASSERT(!has_get);
-
- if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- duk_bool_t rc;
- duk_hobject *tmp;
-
- /* curr is accessor, desc is data */
- if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
- goto fail_not_configurable;
- }
-
- /* curr is accessor -> cannot be in array part */
- DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
-
- DUK_DDD(DUK_DDDPRINT("convert property to data property"));
-
- DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
- tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
- DUK_UNREF(tmp);
- DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
- tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
- DUK_UNREF(tmp);
- DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
-
- DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
- DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
- DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(thr->heap, obj, curr.e_idx);
-
- DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx",
- (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
-
- /* re-lookup to update curr.flags
- * XXX: would be faster to update directly
- */
- duk_pop(ctx); /* remove old value */
- rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- } else {
- /* curr and desc are data */
- if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
- if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) {
- goto fail_not_configurable;
- }
- /* Note: changing from writable to non-writable is OK */
- if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
- duk_tval *tmp1 = duk_require_tval(ctx, -1); /* curr value */
- duk_tval *tmp2 = duk_require_tval(ctx, idx_value); /* new value */
- if (!duk_js_samevalue(tmp1, tmp2)) {
- goto fail_not_configurable;
- }
- }
- }
- }
- } else {
- /* IsGenericDescriptor(desc) == true; this means in practice that 'desc'
- * only has [[Enumerable]] or [[Configurable]] flag updates, which are
- * allowed at this point.
- */
-
- DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set);
- }
-
- /*
- * Start doing property attributes updates. Steps 12-13.
- *
- * Start by computing new attribute flags without writing yet.
- * Property type conversion is done above if necessary.
- */
-
- new_flags = curr.flags;
-
- if (has_enumerable) {
- if (is_enumerable) {
- new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
- } else {
- new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE;
- }
- }
- if (has_configurable) {
- if (is_configurable) {
- new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
- } else {
- new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
- }
- }
- if (has_writable) {
- if (is_writable) {
- new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
- } else {
- new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
- }
- }
-
- /* XXX: write protect after flag? -> any chance of handling it here? */
-
- DUK_DDD(DUK_DDDPRINT("new flags that we want to write: 0x%02lx",
- (unsigned long) new_flags));
-
- /*
- * Check whether we need to abandon an array part (if it exists)
- */
-
- if (curr.a_idx >= 0) {
- duk_bool_t rc;
-
- DUK_ASSERT(curr.e_idx < 0);
-
- if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
- duk_tval *tv1, *tv2;
-
- DUK_DDD(DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place"));
-
- DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC); /* must have been, since in array part */
- DUK_ASSERT(!has_set);
- DUK_ASSERT(!has_get);
-
- tv2 = duk_require_tval(ctx, idx_value);
- tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- goto success_exotics;
- }
-
- DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup"));
- duk__abandon_array_checked(thr, obj);
- duk_pop(ctx); /* remove old value */
- rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
- }
-
- DUK_DDD(DUK_DDDPRINT("updating existing property in entry part"));
-
- /* array case is handled comprehensively above */
- DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
-
- DUK_DDD(DUK_DDDPRINT("update existing property attributes"));
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags);
-
- if (has_set) {
- duk_hobject *tmp;
-
- DUK_DDD(DUK_DDDPRINT("update existing property setter"));
- DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
-
- tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
- DUK_UNREF(tmp);
- DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
- }
- if (has_get) {
- duk_hobject *tmp;
-
- DUK_DDD(DUK_DDDPRINT("update existing property getter"));
- DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
-
- tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
- DUK_UNREF(tmp);
- DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects */
- }
- if (has_value) {
- duk_tval *tv1, *tv2;
-
- DUK_DDD(DUK_DDDPRINT("update existing property value"));
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
-
- tv2 = duk_require_tval(ctx, idx_value);
- tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
- }
-
- /*
- * Standard algorithm succeeded without errors, check for exotic post-behaviors.
- *
- * Arguments exotic behavior in E5 Section 10.6 occurs after the standard
- * [[DefineOwnProperty]] has completed successfully.
- *
- * Array exotic behavior in E5 Section 15.4.5.1 is implemented partly
- * prior to the default [[DefineOwnProperty]], but:
- * - for an array index key (e.g. "10") the final 'length' update occurs here
- * - for 'length' key the element deletion and 'length' update occurs here
- */
-
- success_exotics:
-
- /* [obj key desc value get set curr_value] */
-
- if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
- if (arridx_new_array_length > 0) {
- duk_tval *tmp;
- duk_bool_t rc;
-
- /*
- * Note: zero works as a "no update" marker because the new length
- * can never be zero after a new property is written.
- */
-
- /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */
-
- DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld",
- (long) arridx_new_array_length));
-
- /* Note: reuse 'curr' */
- rc = duk__get_own_propdesc_raw(thr, obj, DUK_HTHREAD_STRING_LENGTH(thr), DUK__NO_ARRAY_INDEX, &curr, 0 /*flags*/); /* don't push value */
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- DUK_ASSERT(curr.e_idx >= 0);
-
- tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
- /* no need for decref/incref because value is a number */
- DUK_TVAL_SET_FASTINT_U32(tmp, arridx_new_array_length);
- }
- if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) {
- /*
- * E5 Section 15.4.5.1, steps 3.k - 3.n. The order at the end combines
- * the error case 3.l.iii and the success case 3.m-3.n.
- *
- * Note: 'length' is always in entries part, so no array abandon issues for
- * 'writable' update.
- */
-
- /* XXX: investigate whether write protect can be handled above, if we
- * just update length here while ignoring its protected status
- */
-
- duk_tval *tmp;
- duk_uint32_t result_len;
- duk_bool_t rc;
-
- DUK_DDD(DUK_DDDPRINT("defineProperty successful, key is 'length', exotic array behavior, "
- "doing array element deletion and length update"));
-
- rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, force_flag, &result_len);
-
- /* update length (curr points to length, and we assume it's still valid) */
- DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len);
-
- DUK_ASSERT(curr.e_idx >= 0);
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
- tmp = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
- /* no decref needed for a number */
- DUK_TVAL_SET_FASTINT_U32(tmp, result_len);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tmp));
-
- if (pending_write_protect) {
- DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)"));
- DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
- }
-
- /*
- * XXX: shrink array allocation or entries compaction here?
- */
-
- if (!rc) {
- goto fail_array_length_partial;
- }
- }
- } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
- duk_hobject *map;
- duk_hobject *varenv;
-
- DUK_ASSERT(arridx_new_array_length == 0);
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); /* traits are separate; in particular, arguments not an array */
-
- map = NULL;
- varenv = NULL;
- if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) {
- goto success_no_exotics;
- }
- DUK_ASSERT(map != NULL);
- DUK_ASSERT(varenv != NULL);
-
- /* [obj key desc value get set curr_value varname] */
-
- if (has_set || has_get) {
- /* = IsAccessorDescriptor(Desc) */
- DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' "
- "changed to an accessor, delete arguments binding"));
-
- (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
- } else {
- /* Note: this order matters (final value before deleting map entry must be done) */
- DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
- "check for value update / binding deletion"));
-
- if (has_value) {
- duk_hstring *varname;
-
- DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
- "update bound value (variable/argument)"));
-
- varname = duk_require_hstring(ctx, -1);
- DUK_ASSERT(varname != NULL);
-
- DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
- "key=%!O, varname=%!O, value=%!T",
- (duk_heaphdr *) key,
- (duk_heaphdr *) varname,
- (duk_tval *) duk_require_tval(ctx, idx_value)));
-
- /* strict flag for putvar comes from our caller (currently: fixed) */
- duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, idx_value), throw_flag);
- }
- if (has_writable && !is_writable) {
- DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
- "changed to non-writable, delete arguments binding"));
-
- (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
- }
- }
-
- /* 'varname' is in stack in this else branch, leaving an unbalanced stack below,
- * but this doesn't matter now.
- */
- }
-
- success_no_exotics:
- return;
-
- fail_virtual:
- DUK_ERROR_TYPE(thr, DUK_STR_PROPERTY_IS_VIRTUAL);
- return;
-
- fail_not_writable_array_length:
- DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_NOT_WRITABLE);
- return;
-
- fail_not_extensible:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
- return;
-
- fail_not_configurable:
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
- return;
-
- fail_array_length_partial:
- DUK_ERROR_TYPE(thr, DUK_STR_ARRAY_LENGTH_WRITE_FAILED);
- return;
-}
-
-/*
- * Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_v;
- duk_hobject *h_obj;
- duk_propdesc desc;
- duk_bool_t ret;
-
- /* coercion order matters */
- h_v = duk_to_hstring(ctx, 0);
- DUK_ASSERT(h_v != NULL);
-
- h_obj = duk_push_this_coercible_to_object(ctx);
- DUK_ASSERT(h_obj != NULL);
-
- ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */
-
- duk_push_boolean(ctx, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
- return 1;
-}
-
-/*
- * Object.seal() and Object.freeze() (E5 Sections 15.2.3.8 and 15.2.3.9)
- *
- * Since the algorithms are similar, a helper provides both functions.
- * Freezing is essentially sealing + making plain properties non-writable.
- *
- * Note: virtual (non-concrete) properties which are non-configurable but
- * writable would pose some problems, but such properties do not currently
- * exist (all virtual properties are non-configurable and non-writable).
- * If they did exist, the non-configurability does NOT prevent them from
- * becoming non-writable. However, this change should be recorded somehow
- * so that it would turn up (e.g. when getting the property descriptor),
- * requiring some additional flags in the object.
- */
-
-DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze) {
- duk_uint_fast32_t i;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(obj != NULL);
-
- DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
-
-#if defined(DUK_USE_ROM_OBJECTS)
- if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
- DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject"));
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
- }
-#endif
-
- /*
- * Abandon array part because all properties must become non-configurable.
- * Note that this is now done regardless of whether this is always the case
- * (skips check, but performance problem if caller would do this many times
- * for the same object; not likely).
- */
-
- duk__abandon_array_checked(thr, obj);
- DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) == 0);
-
- for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
- duk_uint8_t *fp;
-
- /* since duk__abandon_array_checked() causes a resize, there should be no gaps in keys */
- DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != NULL);
-
- /* avoid multiple computations of flags address; bypasses macros */
- fp = DUK_HOBJECT_E_GET_FLAGS_PTR(thr->heap, obj, i);
- if (is_freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) {
- *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE);
- } else {
- *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
- }
- }
-
- DUK_HOBJECT_CLEAR_EXTENSIBLE(obj);
-
- /* no need to compact since we already did that in duk__abandon_array_checked()
- * (regardless of whether an array part existed or not.
- */
-
- return;
-}
-
-/*
- * Object.isSealed() and Object.isFrozen() (E5 Sections 15.2.3.11, 15.2.3.13)
- *
- * Since the algorithms are similar, a helper provides both functions.
- * Freezing is essentially sealing + making plain properties non-writable.
- *
- * Note: all virtual (non-concrete) properties are currently non-configurable
- * and non-writable (and there are no accessor virtual properties), so they don't
- * need to be considered here now.
- */
-
-DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) {
- duk_uint_fast32_t i;
-
- DUK_ASSERT(obj != NULL);
- DUK_UNREF(thr);
-
- /* Note: no allocation pressure, no need to check refcounts etc */
-
- /* must not be extensible */
- if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
- return 0;
- }
-
- /* all virtual properties are non-configurable and non-writable */
-
- /* entry part must not contain any configurable properties, or
- * writable properties (if is_frozen).
- */
- for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
- duk_small_uint_t flags;
-
- if (!DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i)) {
- continue;
- }
-
- /* avoid multiple computations of flags address; bypasses macros */
- flags = (duk_small_uint_t) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
-
- if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
- return 0;
- }
- if (is_frozen &&
- !(flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
- (flags & DUK_PROPDESC_FLAG_WRITABLE)) {
- return 0;
- }
- }
-
- /* array part must not contain any non-unused properties, as they would
- * be configurable and writable.
- */
- for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
- duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
- if (!DUK_TVAL_IS_UNUSED(tv)) {
- return 0;
- }
- }
-
- return 1;
-}
-
-/*
- * Object.preventExtensions() and Object.isExtensible() (E5 Sections 15.2.3.10, 15.2.3.13)
- *
- * Not needed, implemented by macros DUK_HOBJECT_{HAS,CLEAR,SET}_EXTENSIBLE
- * and the Object built-in bindings.
- */
-
-/* Undefine local defines */
-
-#undef DUK__NO_ARRAY_INDEX
-#undef DUK__HASH_INITIAL
-#undef DUK__HASH_PROBE_STEP
-#undef DUK__HASH_UNUSED
-#undef DUK__HASH_DELETED
-#undef DUK__VALSTACK_SPACE
-#line 1 "duk_hstring_misc.c"
-/*
- * Misc support functions
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL duk_ucodepoint_t duk_hstring_char_code_at_raw(duk_hthread *thr, duk_hstring *h, duk_uint_t pos) {
- duk_uint32_t boff;
- const duk_uint8_t *p, *p_start, *p_end;
- duk_ucodepoint_t cp;
-
- /* Caller must check character offset to be inside the string. */
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */
- DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));
-
- boff = duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
- DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O",
- (long) pos, (long) boff, (duk_heaphdr *) h));
- DUK_ASSERT_DISABLE(boff >= 0);
- DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h));
-
- p_start = DUK_HSTRING_GET_DATA(h);
- p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
- p = p_start + boff;
- DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p",
- (const void *) p_start, (const void *) p_end,
- (const void *) p));
-
- /* This may throw an error though not for valid E5 strings. */
- cp = duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
- return cp;
-}
-
-#if !defined(DUK_USE_HSTRING_CLEN)
-DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
- if (DUK_HSTRING_HAS_ASCII(h)) {
- /* Most practical strings will go here. */
- return DUK_HSTRING_GET_BYTELEN(h);
- } else {
- return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
- }
-}
-#endif /* !DUK_USE_HSTRING_CLEN */
-#line 1 "duk_hthread_alloc.c"
-/*
- * duk_hthread allocation and freeing.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Allocate initial stacks for a thread. Note that 'thr' must be reachable
- * as a garbage collection may be triggered by the allocation attempts.
- * Returns zero (without leaking memory) if init fails.
- */
-
-DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) {
- duk_size_t alloc_size;
- duk_size_t i;
-
- DUK_ASSERT(heap != NULL);
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->valstack == NULL);
- DUK_ASSERT(thr->valstack_end == NULL);
- DUK_ASSERT(thr->valstack_bottom == NULL);
- DUK_ASSERT(thr->valstack_top == NULL);
- DUK_ASSERT(thr->callstack == NULL);
- DUK_ASSERT(thr->catchstack == NULL);
-
- /* valstack */
- alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
- thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
- if (!thr->valstack) {
- goto fail;
- }
- DUK_MEMZERO(thr->valstack, alloc_size);
- thr->valstack_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
-#if !defined(DUK_USE_PREFER_SIZE)
- thr->valstack_size = DUK_VALSTACK_INITIAL_SIZE;
-#endif
- thr->valstack_bottom = thr->valstack;
- thr->valstack_top = thr->valstack;
-
- for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) {
- DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]);
- }
-
- /* callstack */
- alloc_size = sizeof(duk_activation) * DUK_CALLSTACK_INITIAL_SIZE;
- thr->callstack = (duk_activation *) DUK_ALLOC(heap, alloc_size);
- if (!thr->callstack) {
- goto fail;
- }
- DUK_MEMZERO(thr->callstack, alloc_size);
- thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE;
- DUK_ASSERT(thr->callstack_top == 0);
-
- /* catchstack */
- alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE;
- thr->catchstack = (duk_catcher *) DUK_ALLOC(heap, alloc_size);
- if (!thr->catchstack) {
- goto fail;
- }
- DUK_MEMZERO(thr->catchstack, alloc_size);
- thr->catchstack_size = DUK_CATCHSTACK_INITIAL_SIZE;
- DUK_ASSERT(thr->catchstack_top == 0);
-
- return 1;
-
- fail:
- DUK_FREE(heap, thr->valstack);
- DUK_FREE(heap, thr->callstack);
- DUK_FREE(heap, thr->catchstack);
-
- thr->valstack = NULL;
- thr->callstack = NULL;
- thr->catchstack = NULL;
- return 0;
-}
-
-/* For indirect allocs. */
-
-DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) {
- duk_hthread *thr = (duk_hthread *) ud;
- DUK_UNREF(heap);
- return (void *) thr->valstack;
-}
-
-DUK_INTERNAL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud) {
- duk_hthread *thr = (duk_hthread *) ud;
- DUK_UNREF(heap);
- return (void *) thr->callstack;
-}
-
-DUK_INTERNAL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud) {
- duk_hthread *thr = (duk_hthread *) ud;
- DUK_UNREF(heap);
- return (void *) thr->catchstack;
-}
-#line 1 "duk_hthread_builtins.c"
-/*
- * Initialize built-in objects. Current thread must have a valstack
- * and initialization errors may longjmp, so a setjmp() catch point
- * must exist.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Encoding constants, must match genbuiltins.py
- */
-
-#define DUK__CLASS_BITS 5
-#define DUK__BIDX_BITS 7
-#define DUK__STRIDX_BITS 9 /* XXX: try to optimize to 8 (would now be possible, <200 used) */
-#define DUK__NATIDX_BITS 8
-#define DUK__NUM_NORMAL_PROPS_BITS 6
-#define DUK__NUM_FUNC_PROPS_BITS 6
-#define DUK__PROP_FLAGS_BITS 3
-#define DUK__STRING_LENGTH_BITS 8
-#define DUK__STRING_CHAR_BITS 7
-#define DUK__LENGTH_PROP_BITS 3
-#define DUK__NARGS_BITS 3
-#define DUK__PROP_TYPE_BITS 3
-#define DUK__MAGIC_BITS 16
-
-#define DUK__NARGS_VARARGS_MARKER 0x07
-#define DUK__NO_CLASS_MARKER 0x00 /* 0 = DUK_HOBJECT_CLASS_UNUSED */
-#define DUK__NO_BIDX_MARKER 0x7f
-#define DUK__NO_STRIDX_MARKER 0xff
-
-#define DUK__PROP_TYPE_DOUBLE 0
-#define DUK__PROP_TYPE_STRING 1
-#define DUK__PROP_TYPE_STRIDX 2
-#define DUK__PROP_TYPE_BUILTIN 3
-#define DUK__PROP_TYPE_UNDEFINED 4
-#define DUK__PROP_TYPE_BOOLEAN_TRUE 5
-#define DUK__PROP_TYPE_BOOLEAN_FALSE 6
-#define DUK__PROP_TYPE_ACCESSOR 7
-
-/*
- * Create built-in objects by parsing an init bitstream generated
- * by genbuiltins.py.
- */
-
-#if defined(DUK_USE_ROM_OBJECTS)
-#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
-DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
- duk_context *ctx;
- duk_hobject *h1;
-#if defined(DUK_USE_ROM_GLOBAL_CLONE)
- duk_hobject *h2;
- duk_uint8_t *props;
- duk_size_t alloc_size;
-#endif
-
- ctx = (duk_context *) thr;
-
- /* XXX: refactor into internal helper, duk_clone_hobject() */
-
-#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
- /* Inherit from ROM-based global object: less RAM usage, less transparent. */
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
- DUK_BIDX_GLOBAL);
- h1 = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h1 != NULL);
-#elif defined(DUK_USE_ROM_GLOBAL_CLONE)
- /* Clone the properties of the ROM-based global object to create a
- * fully RAM-based global object. Uses more memory than the inherit
- * model but more compliant.
- */
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
- DUK_BIDX_OBJECT_PROTOTYPE);
- h1 = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h1 != NULL);
- h2 = thr->builtins[DUK_BIDX_GLOBAL];
- DUK_ASSERT(h2 != NULL);
-
- /* Copy the property table verbatim; this handles attributes etc.
- * For ROM objects it's not necessary (or possible) to update
- * refcounts so leave them as is.
- */
- alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2);
- DUK_ASSERT(alloc_size > 0);
- props = DUK_ALLOC(thr->heap, alloc_size);
- if (!props) {
- DUK_ERROR_ALLOC_DEFMSG(thr);
- return;
- }
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL);
- DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size);
-
- /* XXX: keep property attributes or tweak them here?
- * Properties will now be non-configurable even when they're
- * normally configurable for the global object.
- */
-
- DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL);
- DUK_HOBJECT_SET_PROPS(thr->heap, h1, props);
- DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2));
- DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2));
- DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2));
- DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2));
-#else
-#error internal error in defines
-#endif
-
- duk_hobject_compact_props(thr, h1);
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
- DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */
- thr->builtins[DUK_BIDX_GLOBAL] = h1;
- DUK_HOBJECT_INCREF(thr, h1);
- DUK_D(DUK_DPRINT("duplicated global object: %!O", h1));
-
-
- /* Create a fresh object environment for the global scope. This is
- * needed so that the global scope points to the newly created RAM-based
- * global object.
- */
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
- -1); /* no prototype */
- h1 = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h1 != NULL);
- duk_dup(ctx, -2);
- duk_dup(ctx, -1); /* -> [ ... new_global new_globalenv new_global new_global ] */
- duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */
-
- duk_hobject_compact_props(thr, h1);
- DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
- DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */
- thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1;
- DUK_HOBJECT_INCREF(thr, h1);
- DUK_D(DUK_DPRINT("duplicated global env: %!O", h1));
-
- duk_pop_2(ctx);
-}
-#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
-
-DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
- /* Setup builtins from ROM objects. All heaps/threads will share
- * the same readonly objects.
- */
- duk_small_uint_t i;
-
- for (i = 0; i < DUK_NUM_BUILTINS; i++) {
- duk_hobject *h;
- h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]);
- DUK_ASSERT(h != NULL);
- thr->builtins[i] = h;
- }
-
-#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
- /* By default the global object is read-only which is often much
- * more of an issue than having read-only built-in objects (like
- * RegExp, Date, etc). Use a RAM-based copy of the global object
- * and the global environment object for convenience.
- */
- duk__duplicate_ram_global_object(thr);
-#endif
-}
-#else /* DUK_USE_ROM_OBJECTS */
-DUK_LOCAL void duk__push_stridx(duk_context *ctx, duk_bitdecoder_ctx *bd) {
- duk_small_uint_t n;
-
- n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRIDX_BITS);
- DUK_ASSERT_DISABLE(n >= 0); /* unsigned */
- DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
- duk_push_hstring_stridx(ctx, n);
-}
-DUK_LOCAL void duk__push_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
- duk_small_uint_t n;
- duk_small_uint_t i;
- duk_uint8_t *p;
-
- n = (duk_small_uint_t) duk_bd_decode(bd, DUK__STRING_LENGTH_BITS);
- p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, n);
- for (i = 0; i < n; i++) {
- *p++ = (duk_uint8_t) duk_bd_decode(bd, DUK__STRING_CHAR_BITS);
- }
- duk_to_string(ctx, -1);
-}
-DUK_LOCAL void duk__push_stridx_or_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
- if (duk_bd_decode_flag(bd)) {
- duk__push_string(ctx, bd);
- } else {
- duk__push_stridx(ctx, bd);
- }
-}
-DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
- duk_double_union du;
- duk_small_uint_t i;
-
- for (i = 0; i < 8; i++) {
- /* Encoding endianness must match target memory layout,
- * build scripts and genbuiltins.py must ensure this.
- */
- du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
- }
-
- duk_push_number(ctx, du.d); /* push operation normalizes NaNs */
-}
-
-DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_bitdecoder_ctx bd_ctx;
- duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
- duk_hobject *h;
- duk_small_uint_t i, j;
-
- DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS));
-
- DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
- bd->data = (const duk_uint8_t *) duk_builtins_data;
- bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
-
- /*
- * First create all built-in bare objects on the empty valstack.
- *
- * Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value
- * stack indices matching their eventual thr->builtins[] index.
- *
- * Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS]
- * will exist on the value stack during init but won't be placed
- * into thr->builtins[]. These are objects referenced in some way
- * from thr->builtins[] roots but which don't need to be indexed by
- * Duktape through thr->builtins[] (e.g. user custom objects).
- */
-
- duk_require_stack(ctx, DUK_NUM_ALL_BUILTINS);
-
- DUK_DD(DUK_DDPRINT("create empty built-ins"));
- DUK_ASSERT_TOP(ctx, 0);
- for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
- duk_small_uint_t class_num;
- duk_small_int_t len = -1; /* must be signed */
-
- class_num = (duk_small_uint_t) duk_bd_decode(bd, DUK__CLASS_BITS);
- len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
-
- if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
- duk_small_uint_t natidx;
- duk_int_t c_nargs; /* must hold DUK_VARARGS */
- duk_c_function c_func;
- duk_int16_t magic;
-
- DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
- DUK_ASSERT(len >= 0);
-
- natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
- c_func = duk_bi_native_functions[natidx];
-
- c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/);
- if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
- c_nargs = DUK_VARARGS;
- }
-
- /* XXX: set magic directly here? (it could share the c_nargs arg) */
- duk_push_c_function_noexotic(ctx, c_func, c_nargs);
-
- h = duk_require_hobject(ctx, -1);
- DUK_ASSERT(h != NULL);
-
- /* Currently all built-in native functions are strict.
- * duk_push_c_function() now sets strict flag, so
- * assert for it.
- */
- DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));
-
- /* XXX: function properties */
-
- /* Built-in 'name' is not writable by default. Function '.name'
- * is writable to allow user code to set a '.name' on a native
- * function.
- */
- duk__push_stridx_or_string(ctx, bd);
- duk_xdef_prop_stridx(ctx,
- -2,
- DUK_STRIDX_NAME,
- (i == DUK_BIDX_FUNCTION_PROTOTYPE) ?
- DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE);
-
- /* Almost all global level Function objects are constructable
- * but not all: Function.prototype is a non-constructable,
- * callable Function.
- */
- if (duk_bd_decode_flag(bd)) {
- DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
- } else {
- DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
- }
-
- /* Cast converts magic to 16-bit signed value */
- magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0 /*def_value*/);
- ((duk_hnativefunction *) h)->magic = magic;
- } else {
- /* XXX: ARRAY_PART for Array prototype? */
-
- duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE,
- -1); /* no prototype or class yet */
-
- h = duk_require_hobject(ctx, -1);
- DUK_ASSERT(h != NULL);
- }
-
- DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
-
- if (i < DUK_NUM_BUILTINS) {
- thr->builtins[i] = h;
- DUK_HOBJECT_INCREF(thr, &h->hdr);
- }
-
- if (len >= 0) {
- /*
- * For top-level objects, 'length' property has the following
- * default attributes: non-writable, non-enumerable, non-configurable
- * (E5 Section 15).
- *
- * However, 'length' property for Array.prototype has attributes
- * expected of an Array instance which are different: writable,
- * non-enumerable, non-configurable (E5 Section 15.4.5.2).
- *
- * This is currently determined implicitly based on class; there are
- * no attribute flags in the init data.
- */
-
- duk_push_int(ctx, len);
- duk_xdef_prop_stridx(ctx,
- -2,
- DUK_STRIDX_LENGTH,
- (class_num == DUK_HOBJECT_CLASS_ARRAY ? /* only Array.prototype matches */
- DUK_PROPDESC_FLAGS_W : DUK_PROPDESC_FLAGS_NONE));
- }
-
- /* enable exotic behaviors last */
-
- if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
- DUK_HOBJECT_SET_EXOTIC_ARRAY(h);
- }
- if (class_num == DUK_HOBJECT_CLASS_STRING) {
- DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
- }
-
- /* some assertions */
-
- DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
- /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(h));
- DUK_ASSERT(!DUK_HOBJECT_HAS_COMPILEDFUNCTION(h));
- /* DUK_HOBJECT_FLAG_NATIVEFUNCTION varies */
- DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h));
- DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h)); /* currently, even for Array.prototype */
- /* DUK_HOBJECT_FLAG_STRICT varies */
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(h) || /* all native functions have NEWENV */
- DUK_HOBJECT_HAS_NEWENV(h));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
- DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
- DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h));
- /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
- /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));
-
- DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len));
- }
-
- /*
- * Then decode the builtins init data (see genbuiltins.py) to
- * init objects
- */
-
- DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
- for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
- duk_small_uint_t t;
- duk_small_uint_t num;
-
- DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
- h = duk_require_hobject(ctx, i);
- DUK_ASSERT(h != NULL);
-
- t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
- if (t != DUK__NO_BIDX_MARKER) {
- DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_require_hobject(ctx, t));
- }
-
- t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
- if (t != DUK__NO_BIDX_MARKER) {
- /* 'prototype' property for all built-in objects (which have it) has attributes:
- * [[Writable]] = false,
- * [[Enumerable]] = false,
- * [[Configurable]] = false
- */
- DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
- duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE);
- }
-
- t = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
- if (t != DUK__NO_BIDX_MARKER) {
- /* 'constructor' property for all built-in objects (which have it) has attributes:
- * [[Writable]] = true,
- * [[Enumerable]] = false,
- * [[Configurable]] = true
- */
- DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
- duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC);
- }
-
- /* normal valued properties */
- num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_NORMAL_PROPS_BITS);
- DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
- for (j = 0; j < num; j++) {
- duk_small_uint_t prop_flags;
-
- duk__push_stridx_or_string(ctx, bd);
-
- /*
- * Property attribute defaults are defined in E5 Section 15 (first
- * few pages); there is a default for all properties and a special
- * default for 'length' properties. Variation from the defaults is
- * signaled using a single flag bit in the bitstream.
- */
-
- if (duk_bd_decode_flag(bd)) {
- prop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
- } else {
- prop_flags = DUK_PROPDESC_FLAGS_WC;
- }
-
- t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
-
- DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
- (long) i, (long) j, duk_get_tval(ctx, -1), (unsigned long) prop_flags, (long) t));
-
- switch (t) {
- case DUK__PROP_TYPE_DOUBLE: {
- duk__push_double(ctx, bd);
- break;
- }
- case DUK__PROP_TYPE_STRING: {
- duk__push_string(ctx, bd);
- break;
- }
- case DUK__PROP_TYPE_STRIDX: {
- duk__push_stridx(ctx, bd);
- break;
- }
- case DUK__PROP_TYPE_BUILTIN: {
- duk_small_uint_t bidx;
-
- bidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__BIDX_BITS);
- DUK_ASSERT(bidx != DUK__NO_BIDX_MARKER);
- duk_dup(ctx, (duk_idx_t) bidx);
- break;
- }
- case DUK__PROP_TYPE_UNDEFINED: {
- duk_push_undefined(ctx);
- break;
- }
- case DUK__PROP_TYPE_BOOLEAN_TRUE: {
- duk_push_true(ctx);
- break;
- }
- case DUK__PROP_TYPE_BOOLEAN_FALSE: {
- duk_push_false(ctx);
- break;
- }
- case DUK__PROP_TYPE_ACCESSOR: {
- duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
- duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
- duk_c_function c_func_getter;
- duk_c_function c_func_setter;
-
- /* XXX: this is a bit awkward because there is no exposed helper
- * in the API style, only this internal helper.
- */
- DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
- (long) i, duk_get_tval(ctx, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) prop_flags));
-
- c_func_getter = duk_bi_native_functions[natidx_getter];
- c_func_setter = duk_bi_native_functions[natidx_setter];
- duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */
- duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */
-
- /* XXX: magic for getter/setter? use duk_def_prop()? */
-
- DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */
-
- prop_flags |= DUK_PROPDESC_FLAG_ACCESSOR; /* accessor flag not encoded explicitly */
- duk_hobject_define_accessor_internal(thr,
- duk_require_hobject(ctx, i),
- duk_get_hstring(ctx, -3),
- duk_require_hobject(ctx, -2),
- duk_require_hobject(ctx, -1),
- prop_flags);
- duk_pop_3(ctx); /* key, getter and setter, now reachable through object */
- goto skip_value;
- }
- default: {
- /* exhaustive */
- DUK_UNREACHABLE();
- }
- }
-
- DUK_ASSERT((prop_flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0);
- duk_xdef_prop(ctx, i, prop_flags);
-
- skip_value:
- continue; /* avoid empty label at the end of a compound statement */
- }
-
- /* native function properties */
- num = (duk_small_uint_t) duk_bd_decode(bd, DUK__NUM_FUNC_PROPS_BITS);
- DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
- for (j = 0; j < num; j++) {
- duk_hstring *h_key;
- duk_small_uint_t natidx;
- duk_int_t c_nargs; /* must hold DUK_VARARGS */
- duk_small_uint_t c_length;
- duk_int16_t magic;
- duk_c_function c_func;
- duk_hnativefunction *h_func;
-#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
- duk_small_int_t lightfunc_eligible;
-#endif
-
- duk__push_stridx_or_string(ctx, bd);
- h_key = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_key != NULL);
- DUK_UNREF(h_key);
- natidx = (duk_small_uint_t) duk_bd_decode(bd, DUK__NATIDX_BITS);
-
- c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
- c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/);
- if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
- c_nargs = DUK_VARARGS;
- }
-
- c_func = duk_bi_native_functions[natidx];
-
- DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld",
- (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length,
- (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));
-
- /* Cast converts magic to 16-bit signed value */
- magic = (duk_int16_t) duk_bd_decode_flagged(bd, DUK__MAGIC_BITS, 0);
-
-#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
- lightfunc_eligible =
- ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) &&
- (c_length <= DUK_LFUNC_LENGTH_MAX) &&
- (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
-
- if (h_key == DUK_HTHREAD_STRING_EVAL(thr) ||
- h_key == DUK_HTHREAD_STRING_YIELD(thr) ||
- h_key == DUK_HTHREAD_STRING_RESUME(thr) ||
- h_key == DUK_HTHREAD_STRING_REQUIRE(thr)) {
- /* These functions have trouble working as lightfuncs.
- * Some of them have specific asserts and some may have
- * additional properties (e.g. 'require.id' may be written).
- */
- DUK_D(DUK_DPRINT("reject as lightfunc: key=%!O, i=%d, j=%d", (duk_heaphdr *) h_key, (int) i, (int) j));
- lightfunc_eligible = 0;
- }
-
- if (lightfunc_eligible) {
- duk_tval tv_lfunc;
- duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
- duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
- DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
- duk_push_tval(ctx, &tv_lfunc);
- DUK_D(DUK_DPRINT("built-in function eligible as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld -> %!iT", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic, duk_get_tval(ctx, -1)));
- goto lightfunc_skip;
- }
-
- DUK_D(DUK_DPRINT("built-in function NOT ELIGIBLE as light function: i=%d, j=%d c_length=%ld, c_nargs=%ld, magic=%ld", (int) i, (int) j, (long) c_length, (long) c_nargs, (long) magic));
-#endif /* DUK_USE_LIGHTFUNC_BUILTINS */
-
- /* [ (builtin objects) name ] */
-
- duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs);
- h_func = duk_require_hnativefunction(ctx, -1);
- DUK_UNREF(h_func);
-
- /* Currently all built-in native functions are strict.
- * This doesn't matter for many functions, but e.g.
- * String.prototype.charAt (and other string functions)
- * rely on being strict so that their 'this' binding is
- * not automatically coerced.
- */
- DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);
-
- /* No built-in functions are constructable except the top
- * level ones (Number, etc).
- */
- DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));
-
- /* XXX: any way to avoid decoding magic bit; there are quite
- * many function properties and relatively few with magic values.
- */
- h_func->magic = magic;
-
- /* [ (builtin objects) name func ] */
-
- duk_push_int(ctx, c_length);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
-
- duk_dup(ctx, -2);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
-
- /* XXX: other properties of function instances; 'arguments', 'caller'. */
-
- DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
- (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* [ (builtin objects) name func ] */
-
- /*
- * The default property attributes are correct for all
- * function valued properties of built-in objects now.
- */
-
-#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
- lightfunc_skip:
-#endif
-
- duk_xdef_prop(ctx, i, DUK_PROPDESC_FLAGS_WC);
-
- /* [ (builtin objects) ] */
- }
- }
-
- /*
- * Special post-tweaks, for cases not covered by the init data format.
- *
- * - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
- * toGMTString is required to have the same Function object as
- * toUTCString in E5 Section B.2.6. Note that while Smjs respects
- * this, V8 does not (the Function objects are distinct).
- *
- * - Make DoubleError non-extensible.
- *
- * - Add info about most important effective compile options to Duktape.
- *
- * - Possibly remove some properties (values or methods) which are not
- * desirable with current feature options but are not currently
- * conditional in init data.
- */
-
- duk_get_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
- duk_xdef_prop_stridx(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
-
- h = duk_require_hobject(ctx, DUK_BIDX_DOUBLE_ERROR);
- DUK_ASSERT(h != NULL);
- DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
-
-#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
- DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
- (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW);
-#endif
-
-#if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
- DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
- (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW);
-#endif
-
- /* XXX: relocate */
- duk_push_string(ctx,
- /* Endianness indicator */
-#if defined(DUK_USE_INTEGER_LE)
- "l"
-#elif defined(DUK_USE_INTEGER_BE)
- "b"
-#elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */
- "m"
-#else
- "?"
-#endif
-#if defined(DUK_USE_DOUBLE_LE)
- "l"
-#elif defined(DUK_USE_DOUBLE_BE)
- "b"
-#elif defined(DUK_USE_DOUBLE_ME)
- "m"
-#else
- "?"
-#endif
- " "
- /* Packed or unpacked tval */
-#if defined(DUK_USE_PACKED_TVAL)
- "p"
-#else
- "u"
-#endif
-#if defined(DUK_USE_FASTINT)
- "f"
-#endif
- " "
- /* Low memory options */
-#if defined(DUK_USE_STRTAB_CHAIN)
- "c" /* chain */
-#elif defined(DUK_USE_STRTAB_PROBE)
- "p" /* probe */
-#else
- "?"
-#endif
-#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
- "n"
-#endif
-#if defined(DUK_USE_HEAPPTR16)
- "h"
-#endif
-#if defined(DUK_USE_DATAPTR16)
- "d"
-#endif
-#if defined(DUK_USE_FUNCPTR16)
- "f"
-#endif
-#if defined(DUK_USE_REFCOUNT16)
- "R"
-#endif
-#if defined(DUK_USE_STRHASH16)
- "H"
-#endif
-#if defined(DUK_USE_STRLEN16)
- "S"
-#endif
-#if defined(DUK_USE_BUFLEN16)
- "B"
-#endif
-#if defined(DUK_USE_OBJSIZES16)
- "O"
-#endif
-#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
- "L"
-#endif
-#if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS)
- /* XXX: This won't be shown in practice now
- * because this code is not run when builtins
- * are in ROM.
- */
- "Z"
-#endif
- " "
- /* Object property allocation layout */
-#if defined(DUK_USE_HOBJECT_LAYOUT_1)
- "p1"
-#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
- "p2"
-#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
- "p3"
-#else
- "p?"
-#endif
- " "
- /* Alignment guarantee */
-#if (DUK_USE_ALIGN_BY == 4)
- "a4"
-#elif (DUK_USE_ALIGN_BY == 8)
- "a8"
-#elif (DUK_USE_ALIGN_BY == 1)
- "a1"
-#else
-#error invalid DUK_USE_ALIGN_BY
-#endif
- " "
- /* Architecture, OS, and compiler strings */
- DUK_USE_ARCH_STRING
- " "
- DUK_USE_OS_STRING
- " "
- DUK_USE_COMPILER_STRING);
- duk_xdef_prop_stridx(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
-
- /*
- * InitJS code - Ecmascript code evaluated from a built-in source
- * which provides e.g. backward compatibility. User can also provide
- * JS code to be evaluated at startup.
- */
-
-#ifdef DUK_USE_BUILTIN_INITJS
- /* XXX: compression */
- DUK_DD(DUK_DDPRINT("running built-in initjs"));
- duk_eval_string(ctx, (const char *) duk_initjs_data); /* initjs data is NUL terminated */
- duk_pop(ctx);
-#endif /* DUK_USE_BUILTIN_INITJS */
-
-#ifdef DUK_USE_USER_INITJS
- /* XXX: compression (as an option) */
- DUK_DD(DUK_DDPRINT("running user initjs"));
- duk_eval_string_noresult(ctx, (const char *) DUK_USE_USER_INITJS);
-#endif /* DUK_USE_USER_INITJS */
-
- /*
- * Since built-ins are not often extended, compact them.
- */
-
- DUK_DD(DUK_DDPRINT("compact built-ins"));
- for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
- duk_hobject_compact_props(thr, duk_require_hobject(ctx, i));
- }
-
- DUK_D(DUK_DPRINT("INITBUILTINS END"));
-
-#ifdef DUK_USE_DDPRINT
- for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
- DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
- (long) i, (duk_heaphdr *) duk_require_hobject(ctx, i)));
- }
-#endif
-
- /*
- * Pop built-ins from stack: they are now INCREF'd and
- * reachable from the builtins[] array or indirectly
- * through builtins[].
- */
-
- duk_set_top(ctx, 0);
- DUK_ASSERT_TOP(ctx, 0);
-}
-#endif /* DUK_USE_ROM_OBJECTS */
-
-DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
- duk_small_uint_t i;
-
- for (i = 0; i < DUK_NUM_BUILTINS; i++) {
- thr_to->builtins[i] = thr_from->builtins[i];
- DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */
- }
-}
-#line 1 "duk_hthread_misc.c"
-/*
- * Thread support.
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) {
- DUK_ASSERT(thr != NULL);
-
- /* Order of unwinding is important */
-
- duk_hthread_catchstack_unwind(thr, 0);
-
- duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */
-
- thr->valstack_bottom = thr->valstack;
- duk_set_top((duk_context *) thr, 0); /* unwinds valstack, updating refcounts */
-
- thr->state = DUK_HTHREAD_STATE_TERMINATED;
-
- /* Here we could remove references to built-ins, but it may not be
- * worth the effort because built-ins are quite likely to be shared
- * with another (unterminated) thread, and terminated threads are also
- * usually garbage collected quite quickly. Also, doing DECREFs
- * could trigger finalization, which would run on the current thread
- * and have access to only some of the built-ins. Garbage collection
- * deals with this correctly already.
- */
-
- /* XXX: Shrink the stacks to minimize memory usage? May not
- * be worth the effort because terminated threads are usually
- * garbage collected quite soon.
- */
-}
-
-DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) {
- DUK_ASSERT(thr != NULL);
-
- if (thr->callstack_top > 0) {
- return thr->callstack + thr->callstack_top - 1;
- } else {
- return NULL;
- }
-}
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) {
- duk_instr_t *bcode;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(act != NULL);
- DUK_UNREF(thr);
-
- /* XXX: store 'bcode' pointer to activation for faster lookup? */
- if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
- bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func));
- return (duk_uint_fast32_t) (act->curr_pc - bcode);
- }
- return 0;
-}
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
-DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) {
- duk_instr_t *bcode;
- duk_uint_fast32_t ret;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(act != NULL);
- DUK_UNREF(thr);
-
- if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) {
- bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func));
- ret = (duk_uint_fast32_t) (act->curr_pc - bcode);
- if (ret > 0) {
- ret--;
- }
- return ret;
- }
- return 0;
-}
-
-/* Write bytecode executor's curr_pc back to topmost activation (if any). */
-DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) {
- duk_activation *act;
-
- DUK_ASSERT(thr != NULL);
-
- if (thr->ptr_curr_pc != NULL) {
- /* ptr_curr_pc != NULL only when bytecode executor is active. */
- DUK_ASSERT(thr->callstack_top > 0);
- act = thr->callstack + thr->callstack_top - 1;
- act->curr_pc = *thr->ptr_curr_pc;
- }
-}
-
-DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) {
- duk_activation *act;
-
- DUK_ASSERT(thr != NULL);
-
- if (thr->ptr_curr_pc != NULL) {
- /* ptr_curr_pc != NULL only when bytecode executor is active. */
- DUK_ASSERT(thr->callstack_top > 0);
- act = thr->callstack + thr->callstack_top - 1;
- act->curr_pc = *thr->ptr_curr_pc;
- thr->ptr_curr_pc = NULL;
- }
-}
-#line 1 "duk_hthread_stacks.c"
-/*
- * Manipulation of thread stacks (valstack, callstack, catchstack).
- *
- * Ideally unwinding of stacks should have no side effects, which would
- * then favor separate unwinding and shrink check primitives for each
- * stack type. A shrink check may realloc and thus have side effects.
- *
- * However, currently callstack unwinding itself has side effects, as it
- * needs to DECREF multiple objects, close environment records, etc.
- * Stacks must thus be unwound in the correct order by the caller.
- *
- * (XXX: This should be probably reworked so that there is a shared
- * unwind primitive which handles all stacks as requested, and knows
- * the proper order for unwinding.)
- *
- * Valstack entries above 'top' are always kept initialized to
- * "undefined unused". Callstack and catchstack entries above 'top'
- * are not zeroed and are left as garbage.
- *
- * Value stack handling is mostly a part of the API implementation.
- */
-
-/* include removed: duk_internal.h */
-
-/* check that there is space for at least one new entry */
-DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) {
- duk_activation *new_ptr;
- duk_size_t old_size;
- duk_size_t new_size;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
-
- if (thr->callstack_top < thr->callstack_size) {
- return;
- }
-
- old_size = thr->callstack_size;
- new_size = old_size + DUK_CALLSTACK_GROW_STEP;
-
- /* this is a bit approximate (errors out before max is reached); this is OK */
- if (new_size >= thr->callstack_max) {
- DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
- }
-
- DUK_DD(DUK_DDPRINT("growing callstack %ld -> %ld", (long) old_size, (long) new_size));
-
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
-
- DUK_ASSERT(new_size > 0);
- new_ptr = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
- if (!new_ptr) {
- /* No need for a NULL/zero-size check because new_size > 0) */
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
- thr->callstack = new_ptr;
- thr->callstack_size = new_size;
-
- /* note: any entries above the callstack top are garbage and not zeroed */
-}
-
-DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) {
- duk_size_t new_size;
- duk_activation *p;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
-
- if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) {
- return;
- }
-
- new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE;
- DUK_ASSERT(new_size >= thr->callstack_top);
-
- DUK_DD(DUK_DDPRINT("shrinking callstack %ld -> %ld", (long) thr->callstack_size, (long) new_size));
-
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
-
- /* shrink failure is not fatal */
- p = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
- if (p) {
- thr->callstack = p;
- thr->callstack_size = new_size;
- } else {
- /* Because new_size != 0, if condition doesn't need to be
- * (p != NULL || new_size == 0).
- */
- DUK_ASSERT(new_size != 0);
- DUK_D(DUK_DPRINT("callstack shrink failed, ignoring"));
- }
-
- /* note: any entries above the callstack top are garbage and not zeroed */
-}
-
-DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) {
- duk_size_t idx;
-
- DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld",
- (void *) thr,
- (thr != NULL ? (long) thr->callstack_top : (long) -1),
- (long) new_top));
-
- DUK_ASSERT(thr);
- DUK_ASSERT(thr->heap);
- DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) new_top <= thr->callstack_top); /* cannot grow */
-
- /*
- * The loop below must avoid issues with potential callstack
- * reallocations. A resize (and other side effects) may happen
- * e.g. due to finalizer/errhandler calls caused by a refzero or
- * mark-and-sweep. Arbitrary finalizers may run, because when
- * an environment record is refzero'd, it may refer to arbitrary
- * values which also become refzero'd.
- *
- * So, the pointer 'p' is re-looked-up below whenever a side effect
- * might have changed it.
- */
-
- idx = thr->callstack_top;
- while (idx > new_top) {
- duk_activation *act;
- duk_hobject *func;
-#ifdef DUK_USE_REFERENCE_COUNTING
- duk_hobject *tmp;
-#endif
-#ifdef DUK_USE_DEBUGGER_SUPPORT
- duk_heap *heap;
-#endif
-
- idx--;
- DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) idx < thr->callstack_size); /* true, despite side effect resizes */
-
- act = thr->callstack + idx;
- /* With lightfuncs, act 'func' may be NULL */
-
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- /*
- * Restore 'caller' property for non-strict callee functions.
- */
-
- func = DUK_ACT_GET_FUNC(act);
- if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
- duk_tval *tv_caller;
- duk_tval tv_tmp;
- duk_hobject *h_tmp;
-
- tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
-
- /* The act->prev_caller should only be set if the entry for 'caller'
- * exists (as it is only set in that case, and the property is not
- * configurable), but handle all the cases anyway.
- */
-
- if (tv_caller) {
- DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
- if (act->prev_caller) {
- /* Just transfer the refcount from act->prev_caller to tv_caller,
- * so no need for a refcount update. This is the expected case.
- */
- DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
- act->prev_caller = NULL;
- } else {
- DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
- DUK_ASSERT(act->prev_caller == NULL);
- }
- DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
- } else {
- h_tmp = act->prev_caller;
- if (h_tmp) {
- act->prev_caller = NULL;
- DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */
- }
- }
- act = thr->callstack + idx; /* avoid side effects */
- DUK_ASSERT(act->prev_caller == NULL);
- }
-#endif
-
- /*
- * Unwind debugger state. If we unwind while stepping
- * (either step over or step into), pause execution.
- */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- heap = thr->heap;
- if (heap->dbg_step_thread == thr &&
- heap->dbg_step_csindex == idx) {
- /* Pause for all step types: step into, step over, step out.
- * This is the only place explicitly handling a step out.
- */
- DUK_HEAP_SET_PAUSED(heap);
- DUK_ASSERT(heap->dbg_step_thread == NULL);
- }
-#endif
-
- /*
- * Close environment record(s) if they exist.
- *
- * Only variable environments are closed. If lex_env != var_env, it
- * cannot currently contain any register bound declarations.
- *
- * Only environments created for a NEWENV function are closed. If an
- * environment is created for e.g. an eval call, it must not be closed.
- */
-
- func = DUK_ACT_GET_FUNC(act);
- if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
- DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
- goto skip_env_close;
- }
- /* func is NULL for lightfunc */
-
- DUK_ASSERT(act->lex_env == act->var_env);
- if (act->var_env != NULL) {
- DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
- (void *) act->var_env, (duk_heaphdr *) act->var_env));
- duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom);
- act = thr->callstack + idx; /* avoid side effect issues */
- }
-
-#if 0
- if (act->lex_env != NULL) {
- if (act->lex_env == act->var_env) {
- /* common case, already closed, so skip */
- DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env "
- "already closed -> skip closing lex_env"));
- ;
- } else {
- DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O",
- (void *) act->lex_env, (duk_heaphdr *) act->lex_env));
- duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom);
- act = thr->callstack + idx; /* avoid side effect issues */
- }
- }
-#endif
-
- DUK_ASSERT((act->lex_env == NULL) ||
- ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
-
- DUK_ASSERT((act->var_env == NULL) ||
- ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
- (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
-
- skip_env_close:
-
- /*
- * Update preventcount
- */
-
- if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
- DUK_ASSERT(thr->callstack_preventcount >= 1);
- thr->callstack_preventcount--;
- }
-
- /*
- * Reference count updates
- *
- * Note: careful manipulation of refcounts. The top is
- * not updated yet, so all the activations are reachable
- * for mark-and-sweep (which may be triggered by decref).
- * However, the pointers are NULL so this is not an issue.
- */
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- tmp = act->var_env;
-#endif
- act->var_env = NULL;
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
- act = thr->callstack + idx; /* avoid side effect issues */
-#endif
-
-#ifdef DUK_USE_REFERENCE_COUNTING
- tmp = act->lex_env;
-#endif
- act->lex_env = NULL;
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
- act = thr->callstack + idx; /* avoid side effect issues */
-#endif
-
- /* Note: this may cause a corner case situation where a finalizer
- * may see a currently reachable activation whose 'func' is NULL.
- */
-#ifdef DUK_USE_REFERENCE_COUNTING
- tmp = DUK_ACT_GET_FUNC(act);
-#endif
- act->func = NULL;
-#ifdef DUK_USE_REFERENCE_COUNTING
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
- act = thr->callstack + idx; /* avoid side effect issues */
- DUK_UNREF(act);
-#endif
- }
-
- thr->callstack_top = new_top;
-
- /*
- * We could clear the book-keeping variables for the topmost activation,
- * but don't do so now.
- */
-#if 0
- if (thr->callstack_top > 0) {
- duk_activation *act = thr->callstack + thr->callstack_top - 1;
- act->idx_retval = 0;
- }
-#endif
-
- /* Note: any entries above the callstack top are garbage and not zeroed.
- * Also topmost activation idx_retval is garbage (not zeroed), and must
- * be ignored.
- */
-}
-
-DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) {
- duk_catcher *new_ptr;
- duk_size_t old_size;
- duk_size_t new_size;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
-
- if (thr->catchstack_top < thr->catchstack_size) {
- return;
- }
-
- old_size = thr->catchstack_size;
- new_size = old_size + DUK_CATCHSTACK_GROW_STEP;
-
- /* this is a bit approximate (errors out before max is reached); this is OK */
- if (new_size >= thr->catchstack_max) {
- DUK_ERROR_RANGE(thr, DUK_STR_CATCHSTACK_LIMIT);
- }
-
- DUK_DD(DUK_DDPRINT("growing catchstack %ld -> %ld", (long) old_size, (long) new_size));
-
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
-
- DUK_ASSERT(new_size > 0);
- new_ptr = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
- if (!new_ptr) {
- /* No need for a NULL/zero-size check because new_size > 0) */
- DUK_ERROR_ALLOC_DEFMSG(thr);
- }
- thr->catchstack = new_ptr;
- thr->catchstack_size = new_size;
-
- /* note: any entries above the catchstack top are garbage and not zeroed */
-}
-
-DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) {
- duk_size_t new_size;
- duk_catcher *p;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */
- DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
-
- if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) {
- return;
- }
-
- new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE;
- DUK_ASSERT(new_size >= thr->catchstack_top);
-
- DUK_DD(DUK_DDPRINT("shrinking catchstack %ld -> %ld", (long) thr->catchstack_size, (long) new_size));
-
- /*
- * Note: must use indirect variant of DUK_REALLOC() because underlying
- * pointer may be changed by mark-and-sweep.
- */
-
- /* shrink failure is not fatal */
- p = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
- if (p) {
- thr->catchstack = p;
- thr->catchstack_size = new_size;
- } else {
- /* Because new_size != 0, if condition doesn't need to be
- * (p != NULL || new_size == 0).
- */
- DUK_ASSERT(new_size != 0);
- DUK_D(DUK_DPRINT("catchstack shrink failed, ignoring"));
- }
-
- /* note: any entries above the catchstack top are garbage and not zeroed */
-}
-
-DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) {
- duk_size_t idx;
-
- DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld",
- (void *) thr,
- (thr != NULL ? (long) thr->catchstack_top : (long) -1),
- (long) new_top));
-
- DUK_ASSERT(thr);
- DUK_ASSERT(thr->heap);
- DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) new_top <= thr->catchstack_top); /* cannot grow */
-
- /*
- * Since there are no references in the catcher structure,
- * unwinding is quite simple. The only thing we need to
- * look out for is popping a possible lexical environment
- * established for an active catch clause.
- */
-
- idx = thr->catchstack_top;
- while (idx > new_top) {
- duk_catcher *p;
- duk_activation *act;
- duk_hobject *env;
-
- idx--;
- DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
- DUK_ASSERT((duk_size_t) idx < thr->catchstack_size);
-
- p = thr->catchstack + idx;
-
- if (DUK_CAT_HAS_LEXENV_ACTIVE(p)) {
- DUK_DDD(DUK_DDDPRINT("unwinding catchstack idx %ld, callstack idx %ld, callstack top %ld: lexical environment active",
- (long) idx, (long) p->callstack_index, (long) thr->callstack_top));
-
- /* XXX: Here we have a nasty dependency: the need to manipulate
- * the callstack means that catchstack must always be unwound by
- * the caller before unwinding the callstack. This should be fixed
- * later.
- */
-
- /* Note that multiple catchstack entries may refer to the same
- * callstack entry.
- */
- act = thr->callstack + p->callstack_index;
- DUK_ASSERT(act >= thr->callstack);
- DUK_ASSERT(act < thr->callstack + thr->callstack_top);
-
- DUK_DDD(DUK_DDDPRINT("catchstack_index=%ld, callstack_index=%ld, lex_env=%!iO",
- (long) idx, (long) p->callstack_index,
- (duk_heaphdr *) act->lex_env));
-
- env = act->lex_env; /* current lex_env of the activation (created for catcher) */
- DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
- act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
- DUK_HOBJECT_DECREF(thr, env);
-
- /* There is no need to decref anything else than 'env': if 'env'
- * becomes unreachable, refzero will handle decref'ing its prototype.
- */
- }
- }
-
- thr->catchstack_top = new_top;
-
- /* note: any entries above the catchstack top are garbage and not zeroed */
-}
-#line 1 "duk_js_call.c"
-/*
- * Call handling.
- *
- * 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 */
-
-/*
- * 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,
- duk_jmpbuf *old_jmpbuf_ptr);
-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,
- duk_jmpbuf *old_jmpbuf_ptr);
-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) {
- /* 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.
- *
- * If we were to execute the interrupt handler here, the counts
- * would match. You can enable this block manually to check
- * that this is the case.
- */
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
-
-#if defined(DUK_USE_INTERRUPT_DEBUG_FIXUP)
- if (entry_curr_thread == NULL) {
- thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
- thr->heap->inst_count_interrupt += thr->interrupt_init;
- DUK_DD(DUK_DDPRINT("debug test: updated interrupt count on exit to "
- "user code, instruction counts: executor=%ld, interrupt=%ld",
- (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
- DUK_ASSERT(thr->heap->inst_count_exec == thr->heap->inst_count_interrupt);
- }
-#else
- DUK_UNREF(thr);
- DUK_UNREF(entry_curr_thread);
-#endif
-}
-#endif
-
-/*
- * Arguments object creation.
- *
- * 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_context *ctx = (duk_context *) thr;
- duk_hobject *arg; /* 'arguments' */
- duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
- duk_idx_t i_arg;
- duk_idx_t i_map;
- duk_idx_t i_mappednames;
- duk_idx_t i_formals;
- duk_idx_t i_argbase;
- duk_idx_t n_formals;
- duk_idx_t idx;
- duk_bool_t need_map;
-
- DUK_DDD(DUK_DDDPRINT("creating arguments object for func=%!iO, varenv=%!iO, "
- "idx_argbase=%ld, num_stack_args=%ld",
- (duk_heaphdr *) func, (duk_heaphdr *) varenv,
- (long) idx_argbase, (long) num_stack_args));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
- DUK_ASSERT(varenv != NULL);
- DUK_ASSERT(idx_argbase >= 0); /* assumed to bottom relative */
- DUK_ASSERT(num_stack_args >= 0);
-
- need_map = 0;
-
- i_argbase = idx_argbase;
- DUK_ASSERT(i_argbase >= 0);
-
- duk_push_hobject(ctx, func);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_FORMALS);
- formals = duk_get_hobject(ctx, -1);
- n_formals = 0;
- if (formals) {
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH);
- n_formals = (duk_idx_t) duk_require_int(ctx, -1);
- duk_pop(ctx);
- }
- duk_remove(ctx, -2); /* leave formals on stack for later use */
- i_formals = duk_require_top_index(ctx);
-
- DUK_ASSERT(n_formals >= 0);
- DUK_ASSERT(formals != NULL || n_formals == 0);
-
- DUK_DDD(DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%ld",
- (duk_heaphdr *) func, (duk_heaphdr *) formals,
- (long) n_formals));
-
- /* [ ... formals ] */
-
- /*
- * Create required objects:
- * - 'arguments' object: array-like, but not an array
- * - 'map' object: internal object, tied to 'arguments'
- * - 'mappedNames' object: temporary value used during construction
- */
-
- i_arg = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_FLAG_ARRAY_PART |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
- DUK_BIDX_OBJECT_PROTOTYPE);
- DUK_ASSERT(i_arg >= 0);
- arg = duk_require_hobject(ctx, -1);
- DUK_ASSERT(arg != NULL);
-
- i_map = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- -1); /* no prototype */
- DUK_ASSERT(i_map >= 0);
-
- i_mappednames = duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
- -1); /* no prototype */
- DUK_ASSERT(i_mappednames >= 0);
-
- /* [ ... formals arguments map mappedNames ] */
-
- DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
- "arguments at index %ld -> %!O "
- "map at index %ld -> %!O "
- "mappednames at index %ld -> %!O",
- (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
- (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
- (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
-
- /*
- * Init arguments properties, map, etc.
- */
-
- duk_push_int(ctx, num_stack_args);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
-
- /*
- * Init argument related properties
- */
-
- /* step 11 */
- idx = num_stack_args - 1;
- while (idx >= 0) {
- DUK_DDD(DUK_DDDPRINT("arg idx %ld, argbase=%ld, argidx=%ld",
- (long) idx, (long) i_argbase, (long) (i_argbase + idx)));
-
- DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx));
- duk_dup(ctx, i_argbase + idx);
- duk_xdef_prop_index_wec(ctx, i_arg, (duk_uarridx_t) idx);
- DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx));
-
- /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
- if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) {
- DUK_ASSERT(formals != NULL);
-
- DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)",
- (long) idx, (long) n_formals));
-
- duk_get_prop_index(ctx, i_formals, idx);
- DUK_ASSERT(duk_is_string(ctx, -1));
-
- 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 ] */
-
- need_map = 1;
-
- DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld",
- (const char *) duk_get_string(ctx, -1),
- (long) idx));
- duk_dup(ctx, -1); /* name */
- duk_push_uint(ctx, (duk_uint_t) idx); /* index */
- duk_to_string(ctx, -1);
- duk_xdef_prop_wec(ctx, i_mappednames); /* out of spec, must be configurable */
-
- DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s",
- (long) idx,
- duk_get_string(ctx, -1)));
- duk_dup(ctx, -1); /* name */
- duk_xdef_prop_index_wec(ctx, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
- } else {
- /* duk_has_prop() popped the second 'name' */
- }
-
- /* [ ... name ] */
- duk_pop(ctx); /* pop 'name' */
- }
-
- idx--;
- }
-
- DUK_DDD(DUK_DDDPRINT("actual arguments processed"));
-
- /* step 12 */
- if (need_map) {
- DUK_DDD(DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object"));
-
- /* should never happen for a strict callee */
- DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
-
- duk_dup(ctx, i_map);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
-
- /* The variable environment for magic variable bindings needs to be
- * given by the caller and recorded in the arguments object.
- *
- * See E5 Section 10.6, the creation of setters/getters.
- *
- * The variable environment also provides access to the callee, so
- * an explicit (internal) callee property is not needed.
- */
-
- duk_push_hobject(ctx, varenv);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
- }
-
- /* steps 13-14 */
- if (DUK_HOBJECT_HAS_STRICT(func)) {
- /* 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.
- */
-
- DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
-
- duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_NONE);
- } else {
- DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value"));
- duk_push_hobject(ctx, func);
- duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
- }
-
- /* set exotic behavior only after we're done */
- if (need_map) {
- /* 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.
- */
-
- /* cannot be strict (never mapped variables) */
- DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
-
- DUK_DDD(DUK_DDDPRINT("enabling exotic behavior for arguments object"));
- DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(arg);
- } else {
- DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
- }
-
- DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
- "arguments at index %ld -> %!O "
- "map at index %ld -> %!O "
- "mappednames at index %ld -> %!O",
- (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
- (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 ] */
-
- 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_context *ctx = (duk_context *) thr;
-
- DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(env != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
-
- /* [ ... arg1 ... argN envobj ] */
-
- duk__create_arguments_object(thr,
- func,
- env,
- duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
- num_stack_args);
-
- /* [ ... 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 ] */
-}
-
-/*
- * Helper for handling a "bound function" chain when a call is being made.
- *
- * Follows the bound function chain until a non-bound function is found.
- * Prepends the bound arguments to the value stack (at idx_func + 2),
- * updating 'num_stack_args' in the process. The 'this' binding is also
- * updated if necessary (at idx_func + 1). Note that for constructor calls
- * the 'this' binding is never updated by [[BoundThis]].
- *
- * XXX: bound function chains could be collapsed at bound function creation
- * time so that each bound function would point directly to a non-bound
- * 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_context *ctx = (duk_context *) thr;
- duk_idx_t num_stack_args;
- duk_tval *tv_func;
- duk_hobject *func;
- duk_uint_t sanity;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(p_num_stack_args != NULL);
-
- /* On entry, item at idx_func is a bound, non-lightweight function,
- * but we don't rely on that below.
- */
-
- num_stack_args = *p_num_stack_args;
-
- sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
- do {
- duk_idx_t i, len;
-
- tv_func = duk_require_tval(ctx, idx_func);
- DUK_ASSERT(tv_func != NULL);
-
- if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
- /* Lightweight function: never bound, so terminate. */
- break;
- } else if (DUK_TVAL_IS_OBJECT(tv_func)) {
- func = DUK_TVAL_GET_OBJECT(tv_func);
- if (!DUK_HOBJECT_HAS_BOUND(func)) {
- /* Normal non-bound function. */
- break;
- }
- } else {
- /* Function.prototype.bind() should never let this happen,
- * ugly error message is enough.
- */
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- }
- DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv_func) != NULL);
-
- /* XXX: this could be more compact by accessing the internal properties
- * directly as own properties (they cannot be inherited, and are not
- * externally visible).
- */
-
- DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p, num_stack_args=%ld: %!T",
- (void *) DUK_TVAL_GET_OBJECT(tv_func), (long) num_stack_args, tv_func));
-
- /* [ ... func this arg1 ... argN ] */
-
- if (is_constructor_call) {
- /* See: tests/ecmascript/test-spec-bound-constructor.js */
- DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
- } else {
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_THIS);
- duk_replace(ctx, idx_func + 1); /* idx_this = idx_func + 1 */
- }
-
- /* [ ... func this arg1 ... argN ] */
-
- /* XXX: duk_get_length? */
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_ARGS); /* -> [ ... func this arg1 ... argN _Args ] */
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */
- len = (duk_idx_t) duk_require_int(ctx, -1);
- duk_pop(ctx);
- for (i = 0; i < len; i++) {
- /* XXX: very slow - better to bulk allocate a gap, and copy
- * from args_array directly (we know it has a compact array
- * part, etc).
- */
-
- /* [ ... func this <some bound args> arg1 ... argN _Args ] */
- duk_get_prop_index(ctx, -1, i);
- duk_insert(ctx, idx_func + 2 + i); /* idx_args = idx_func + 2 */
- }
- num_stack_args += len; /* must be updated to work properly (e.g. creation of 'arguments') */
- duk_pop(ctx);
-
- /* [ ... func this <bound args> arg1 ... argN ] */
-
- duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_TARGET);
- duk_replace(ctx, idx_func); /* replace in stack */
-
- DUK_DDD(DUK_DDDPRINT("bound function handled, num_stack_args=%ld, idx_func=%ld, curr func=%!T",
- (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func)));
- } while (--sanity > 0);
-
- if (sanity == 0) {
- DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
- }
-
- DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
-
-#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)) {
- func = DUK_TVAL_GET_OBJECT(tv_func);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func) ||
- DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
- }
-#endif
-
- /* write back */
- *p_num_stack_args = num_stack_args;
-}
-
-/*
- * Helper for setting up var_env and lex_env of an activation,
- * 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_tval *tv;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(act != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func));
- DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
- if (tv) {
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
- act->lex_env = DUK_TVAL_GET_OBJECT(tv);
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARENV(thr));
- if (tv) {
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
- act->var_env = DUK_TVAL_GET_OBJECT(tv);
- } else {
- act->var_env = act->lex_env;
- }
- } else {
- act->lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- act->var_env = act->lex_env;
- }
-
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->lex_env);
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, act->var_env);
-}
-
-/*
- * Helper for updating callee '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;
- duk_activation *act_callee;
- duk_activation *act_caller;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound chain resolved */
- DUK_ASSERT(thr->callstack_top >= 1);
-
- if (DUK_HOBJECT_HAS_STRICT(func)) {
- /* Strict functions don't get their 'caller' updated. */
- return;
- }
-
- 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) {
- /* If caller is global/eval code, 'caller' should be set to
- * 'null'.
- *
- * XXX: there is no exotic flag to infer this correctly now.
- * The NEWENV flag is used now which works as intended for
- * everything (global code, non-strict eval code, and functions)
- * except strict eval code. Bound functions are never an issue
- * because 'func' has been resolved to a non-bound function.
- */
-
- if (act_caller) {
- /* act_caller->func may be NULL in some finalization cases,
- * just treat like we don't know the caller.
- */
- if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) {
- /* Setting to NULL causes 'caller' to be set to
- * 'null' as desired.
- */
- act_caller = NULL;
- }
- }
-
- if (DUK_TVAL_IS_OBJECT(tv_caller)) {
- h_tmp = DUK_TVAL_GET_OBJECT(tv_caller);
- DUK_ASSERT(h_tmp != NULL);
- act_callee->prev_caller = h_tmp;
-
- /* Previous value doesn't need refcount changes because its ownership
- * is transferred to prev_caller.
- */
-
- if (act_caller) {
- DUK_ASSERT(act_caller->func != NULL);
- DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
- DUK_TVAL_INCREF(thr, tv_caller);
- } else {
- DUK_TVAL_SET_NULL(tv_caller); /* no incref */
- }
- } else {
- /* 'caller' must only take on 'null' or function value */
- DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
- DUK_ASSERT(act_callee->prev_caller == NULL);
- if (act_caller && act_caller->func) {
- /* Tolerate act_caller->func == NULL which happens in
- * some finalization cases; treat like unknown caller.
- */
- DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
- DUK_TVAL_INCREF(thr, tv_caller);
- } else {
- DUK_TVAL_SET_NULL(tv_caller); /* no incref */
- }
- }
- }
-}
-#endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
-
-/*
- * Determine the effective 'this' binding and coerce the current value
- * on the valstack to the effective one (in-place, at idx_this).
- *
- * The current this value in the valstack (at idx_this) represents either:
- * - the caller's requested 'this' binding; or
- * - a 'this' binding accumulated from the bound function chain
- *
- * The final 'this' binding for the target function may still be
- * different, and is determined as described in E5 Section 10.4.3.
- *
- * For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
- * that the caller has provided the correct 'this' binding explicitly
- * when calling, i.e.:
- *
- * - global code: this=global object
- * - direct eval: this=copy from eval() caller's this binding
- * - other eval: this=global object
- *
- * Note: this function may cause a recursive function call with arbitrary
- * 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_context *ctx = (duk_context *) thr;
- duk_tval *tv_this;
- duk_hobject *obj_global;
-
- if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
- /* Lightfuncs are always considered strict. */
- DUK_DDD(DUK_DDDPRINT("this binding: strict -> use directly"));
- return;
- }
-
- /* XXX: byte offset */
- tv_this = thr->valstack_bottom + idx_this;
- switch (DUK_TVAL_GET_TAG(tv_this)) {
- case DUK_TAG_OBJECT:
- case DUK_TAG_LIGHTFUNC: /* lightfuncs are treated like objects and not coerced */
- DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
- break;
- case DUK_TAG_UNDEFINED:
- case DUK_TAG_NULL:
- DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object"));
- obj_global = thr->builtins[DUK_BIDX_GLOBAL];
- /* XXX: avoid this check somehow */
- if (DUK_LIKELY(obj_global != NULL)) {
- DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
- DUK_TVAL_SET_OBJECT(tv_this, obj_global);
- DUK_HOBJECT_INCREF(thr, obj_global);
- } else {
- /* This may only happen if built-ins are being "torn down".
- * This behavior is out of specification scope.
- */
- DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead"));
- DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
- DUK_TVAL_SET_UNDEFINED(tv_this); /* nothing to incref */
- }
- break;
- default:
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
- DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
- duk_to_object(ctx, idx_this); /* may have side effects */
- break;
- }
-}
-
-/*
- * Shared helper for non-bound func lookup.
- *
- * 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_hthread *thr = (duk_hthread *) ctx;
- duk_tval *tv_func;
- duk_hobject *func;
-
- for (;;) {
- /* Use loop to minimize code size of relookup after bound function case */
- tv_func = DUK_GET_TVAL_POSIDX(ctx, idx_func);
- DUK_ASSERT(tv_func != NULL);
-
- if (DUK_TVAL_IS_OBJECT(tv_func)) {
- func = DUK_TVAL_GET_OBJECT(tv_func);
- if (!DUK_HOBJECT_IS_CALLABLE(func)) {
- goto not_callable_error;
- }
- if (DUK_HOBJECT_HAS_BOUND(func)) {
- duk__handle_bound_chain_for_call(thr, idx_func, out_num_stack_args, call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL);
-
- /* The final object may be a normal function or a lightfunc.
- * We need to re-lookup tv_func because it may have changed
- * (also value stack may have been resized). Loop again to
- * do that; we're guaranteed not to come here again.
- */
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(ctx, idx_func)) ||
- DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(ctx, idx_func)));
- continue;
- }
- } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
- func = NULL;
- } else {
- goto not_callable_error;
- }
- break;
- }
-
- DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_func) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_func))) ||
- DUK_TVAL_IS_LIGHTFUNC(tv_func));
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
- DUK_HOBJECT_IS_NATIVEFUNCTION(func)));
-
- *out_tv_func = tv_func;
- return func;
-
- not_callable_error:
- DUK_ASSERT(tv_func != NULL);
-#if defined(DUK_USE_PARANOID_ERRORS)
- DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
-#else
- DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(ctx, tv_func));
-#endif
- DUK_UNREACHABLE();
- return NULL; /* never executed */
-}
-
-/*
- * 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_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 */
-
- if (nregs >= 0) {
- DUK_ASSERT(nargs >= 0);
- DUK_ASSERT(nregs >= nargs);
- vs_min_size += nregs;
- } else {
- /* 'func' wants stack "as is" */
- 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_INTERNAL_EXTRA; /* + spare */
-
- /* 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)) {
- DUK_DDD(DUK_DDDPRINT(("final size smaller, set top before resize")));
-
- DUK_ASSERT(nregs >= 0); /* can't happen when keeping current stack size */
- duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
- duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
- adjusted_top = 1;
- }
-
- (void) duk_valstack_resize_raw((duk_context *) thr,
- vs_min_size,
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
-
- if (!adjusted_top) {
- if (nregs >= 0) {
- DUK_ASSERT(nregs >= nargs);
- duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
- duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
- }
- }
-}
-
-/*
- * 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);
- }
- }
-}
-
-/*
- * 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):
- *
- * [ func this arg1 ... argN ]
- *
- * Output stack (thr):
- *
- * [ 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
- * such as an insane num_stack_args argument. If there is no catchpoint for
- * such errors, the fatal error handler is called.
- *
- * 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_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;
- 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_jmpbuf *old_jmpbuf_ptr = NULL;
- duk_jmpbuf our_jmpbuf;
- 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_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);
-
- /* 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);
-#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 */
-
- 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_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));
-
- old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
- thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- try {
-#else
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
- if (DUK_SETJMP(our_jmpbuf.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);
-
- /* Success path handles */
- DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
- DUK_ASSERT(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));
-
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- 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,
- old_jmpbuf_ptr);
-
- /* 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_FMT1(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_UNREF(exc);
- 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,
- old_jmpbuf_ptr);
- return DUK_EXEC_ERROR;
- }
- } catch (...) {
- DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_API(thr, "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_UNREF(exc);
- 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,
- old_jmpbuf_ptr);
- 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;
-
- 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);
-
- 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)));
-
- /*
- * Store entry state.
- */
-
- 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 */
-
- /* 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);
-
- 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));
-
-
- /*
- * Thread state check and book-keeping.
- */
-
- if (thr == thr->heap->curr_thread) {
- /* same thread */
- if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
- /* should actually never happen, but check anyway */
- goto thread_state_error;
- }
- } else {
- /* different thread */
- DUK_ASSERT(thr->heap->curr_thread == NULL ||
- thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
- if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
- goto thread_state_error;
- }
- DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
- thr->state = DUK_HTHREAD_STATE_RUNNING;
-
- /* Note: multiple threads may be simultaneously in the RUNNING
- * state, but not in the same "resume chain".
- */
- }
- DUK_ASSERT(thr->heap->curr_thread == thr);
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
-
- /*
- * C call recursion depth check, which provides a reasonable upper
- * bound on maximum C stack size (arbitrary C stack growth is only
- * 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 {
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
- /* XXX: error message is a bit misleading: we reached a recursion
- * limit which is also essentially the same as a C callstack limit
- * (except perhaps with some relaxed threading assumptions).
- */
- DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
- }
- thr->heap->call_recursion_depth++;
- }
-
- /*
- * Check the function type, handle bound function chains, and prepare
- * parameters for the rest of the call handling. Also figure out the
- * effective 'this' binding, which replaces the current value at
- * idx_func + 1.
- *
- * If the target function is a 'bound' one, follow the chain of 'bound'
- * functions until a non-bound function is found. During this process,
- * bound arguments are 'prepended' to existing ones, and the "this"
- * binding is overridden. See E5 Section 15.3.4.5.1.
- *
- * Lightfunc detection happens here too. Note that lightweight functions
- * can be wrapped by (non-lightweight) bound functions so we must resolve
- * the bound function chain first.
- */
-
- func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
- DUK_TVAL_SET_TVAL(&tv_func_copy, tv_func);
- tv_func = &tv_func_copy; /* local copy to avoid relookups */
-
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPILEDFUNCTION(func) ||
- DUK_HOBJECT_IS_NATIVEFUNCTION(func)));
-
- duk__coerce_effective_this_binding(thr, func, idx_func + 1);
- DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
- (duk_tval *) duk_get_tval(ctx, idx_func + 1)));
-
- /* [ ... func this arg1 ... argN ] */
-
- /*
- * 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.
- */
-
- duk_hthread_callstack_grow(thr);
-
- if (thr->callstack_top > 0) {
- /*
- * Update idx_retval of current activation.
- *
- * Although it might seem this is not necessary (bytecode executor
- * does this for Ecmascript-to-Ecmascript calls; other calls are
- * handled here), this turns out to be necessary for handling yield
- * and resume. For them, an Ecmascript-to-native call happens, and
- * the Ecmascript call's idx_retval must be set for things to work.
- */
-
- (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func;
- }
-
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- act = thr->callstack + thr->callstack_top;
- thr->callstack_top++;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
- DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func));
-
- act->flags = 0;
-
- /* 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;
- }
- if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
- act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
- }
-
- /* 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 (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_TYPE(thr, 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;
-#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_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++;
- }
-
- /* XXX: Is this INCREF necessary? 'func' is always a borrowed
- * reference reachable through the value stack? If changed, stack
- * unwind code also needs to be fixed to match.
- */
- DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
-
-#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 ] */
-
- /*
- * Environment record creation and 'arguments' object creation.
- * Named function expression name binding is handled by the
- * compiler; the compiled function's parent env will contain
- * the (immutable) binding already.
- *
- * This handling is now identical for C and Ecmascript functions.
- * C functions always have the 'NEWENV' flag set, so their
- * environment record initialization is delayed (which is good).
- *
- * Delayed creation (on demand) is handled in duk_js_var.c.
- */
-
- DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
-
- 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.
- */
-
- /* 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 ] */
-
- DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
-
- /* [ ... 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_oldenv_for_call(thr, func, act);
-
- 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);
- }
-
- /* [ ... func this arg1 ... argN ] */
-
- /*
- * Setup value stack: clamp to 'nargs', fill up to 'nregs'
- *
- * Value stack may either grow or shrink, depending on the
- * number of func registers and the number of actual arguments.
- * If nregs >= 0, func wants args clamped to 'nargs'; else it
- * 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_func + 2,
- nregs,
- nargs,
- func);
-
- /*
- * Determine call type, then finalize activation, shift to
- * new value stack bottom, and call the target.
- */
-
- if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- /*
- * Ecmascript call
- */
-
- duk_tval *tv_ret;
- duk_tval *tv_funret;
-
- 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_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) */
-
- /*
- * 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.
- */
-
- /* 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"));
-
- /* Unwind. */
-
- 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);
-
- 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. */
-
- /* [ ... 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_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
- } else {
- /*
- * Native call.
- */
-
- duk_tval *tv_ret;
- duk_tval *tv_funret;
-
- 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);
-
- /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
-
- /* For native calls must be NULL so we don't sync back */
- DUK_ASSERT(thr->ptr_curr_pc == NULL);
-
- 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);
- }
-
- /* Automatic error throwing, retval check. */
-
- 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);
-
- /* 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
- * 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.
- */
-
- /* 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;
-
- 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 */
-
- thr->heap->call_recursion_depth = entry_call_recursion_depth;
-
- /* 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
-
-#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
- duk__interrupt_fixup(thr, entry_curr_thread);
-#endif
-
- return;
-
- thread_state_error:
- DUK_ERROR_FMT1(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,
- duk_jmpbuf *old_jmpbuf_ptr) {
- duk_context *ctx;
- duk_tval *tv_ret;
-
- ctx = (duk_context *) thr;
-
- DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
- (duk_tval *) &thr->heap->lj.value1));
-
- /* 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);
-
- /* 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);
-
- /* 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;
-
- /* 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;
- 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 */
-
- /* [ ... errobj ] */
-
- /* 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.
- */
-
- /* 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);
-
-
- /* 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;
-
- 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 */
-
- thr->heap->call_recursion_depth = entry_call_recursion_depth;
-
- /* 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
-
-#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
- duk__interrupt_fixup(thr, entry_curr_thread);
-#endif
-}
-
-/*
- * 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_xxx().
- *
- * 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_context *ctx = (duk_context *) thr;
- duk_size_t entry_valstack_bottom_index;
- 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_jmpbuf *old_jmpbuf_ptr = NULL;
- duk_jmpbuf our_jmpbuf;
- duk_idx_t idx_retbase;
- duk_int_t retval;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
-
- /* Note: careful with indices like '-x'; if 'x' is zero, it refers to bottom */
- entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
- 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 */
- idx_retbase = duk_get_top(ctx) - num_stack_args; /* Note: not a valid stack index if num_stack_args == 0 */
-
- /* Note: cannot portably debug print a function pointer, hence 'func' not printed! */
- DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
- "valstack_top=%ld, idx_retbase=%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,
- (long) num_stack_rets,
- (long) duk_get_top(ctx),
- (long) idx_retbase,
- (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));
-
- 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.
- */
-
- DUK_ERROR_API(thr, DUK_STR_INVALID_CALL_ARGS);
- }
-
- /* setjmp catchpoint setup */
-
- old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
- thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- try {
-#else
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
- if (DUK_SETJMP(our_jmpbuf.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));
-
- /* Note: either pointer may be NULL (at entry), so don't assert */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- retval = DUK_EXEC_SUCCESS;
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- } catch (duk_internal_exception &exc) {
- DUK_UNREF(exc);
-#else
- } else {
- /* Error path. */
-#endif
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
-
- /* 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_FMT1(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_UNREF(exc);
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
- retval = DUK_EXEC_ERROR;
- }
- } catch (...) {
- DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
- try {
- DUK_ERROR_API(thr, "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_UNREF(exc);
- duk__handle_safe_call_error(thr,
- idx_retbase,
- num_stack_rets,
- entry_valstack_bottom_index,
- entry_callstack_top,
- entry_catchstack_top,
- old_jmpbuf_ptr);
- retval = DUK_EXEC_ERROR;
- }
- }
-#endif
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
-
- 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);
-
- return retval;
-}
-
-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_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.
- */
-
- if (thr == thr->heap->curr_thread) {
- /* same thread */
- if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
- /* should actually never happen, but check anyway */
- goto thread_state_error;
- }
- } else {
- /* different thread */
- DUK_ASSERT(thr->heap->curr_thread == NULL ||
- thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
- if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
- goto thread_state_error;
- }
- DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
- thr->state = DUK_HTHREAD_STATE_RUNNING;
-
- /* Note: multiple threads may be simultaneously in the RUNNING
- * state, but not in the same "resume chain".
- */
- }
-
- DUK_ASSERT(thr->heap->curr_thread == thr);
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
-
- /*
- * Recursion limit check.
- *
- * Note: there is no need for an "ignore recursion limit" flag
- * for duk_handle_safe_call now.
- */
-
- DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
- DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
- if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
- /* XXX: error message is a bit misleading: we reached a recursion
- * limit which is also essentially the same as a C callstack limit
- * (except perhaps with some relaxed threading assumptions).
- */
- DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
- }
- thr->heap->call_recursion_depth++;
-
- /*
- * Valstack spare check
- */
-
- duk_require_stack(ctx, 0); /* internal spare */
-
- /*
- * Make the C call
- */
-
- rc = func(ctx);
-
- DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
-
- /*
- * Valstack manipulation for results.
- */
-
- /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
- DUK_ASSERT(thr->callstack_top == entry_callstack_top);
- DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
- DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
- DUK_ASSERT((duk_size_t) (thr->valstack_bottom - thr->valstack) == entry_valstack_bottom_index);
- DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
- DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
-
- if (rc < 0) {
- duk_error_throw_from_negative_rc(thr, rc);
- }
- DUK_ASSERT(rc >= 0);
-
- if (duk_get_top(ctx) < rc) {
- 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;
-
- thread_state_error:
- DUK_ERROR_FMT1(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,
- duk_jmpbuf *old_jmpbuf_ptr) {
- duk_context *ctx;
-
- 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. */
- thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
-
- 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);
- thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
-
- /* [ ... | (crud) ] */
-
- /* 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);
-
- 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_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;
-
- /* XXX: because we unwind stacks above, thr->heap->curr_thread is at
- * risk of pointing to an already freed thread. This was indeed the
- * case in test-bug-multithread-valgrind.c, until duk_handle_call()
- * was fixed to restore thr->heap->curr_thread before rethrowing an
- * uncaught error.
- */
- 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 */
-
- thr->heap->call_recursion_depth = entry_call_recursion_depth;
-
- /* stack discipline consistency check */
- DUK_ASSERT(duk_get_top(ctx) == idx_retbase + num_stack_rets);
-
- /* A debugger forced interrupt check is not needed here, as
- * problematic safe calls are not caused by side effects.
- */
-
-#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
- duk__interrupt_fixup(thr, entry_curr_thread);
-#endif
-}
-
-/*
- * Helper for handling an Ecmascript-to-Ecmascript call or an Ecmascript
- * function (initial) Duktape.Thread.resume().
- *
- * Compared to normal calls handled by duk_handle_call(), there are a
- * bunch of differences:
- *
- * - the call is never protected
- * - there is no C recursion depth increase (hence an "ignore recursion
- * limit" flag is not applicable)
- * - instead of making the call, this helper just performs the thread
- * setup and returns; the bytecode executor then restarts execution
- * internally
- * - ecmascript functions are never 'vararg' functions (they access
- * varargs through the 'arguments' object)
- *
- * The callstack of the target contains an earlier Ecmascript call in case
- * of an Ecmascript-to-Ecmascript call (whose idx_retval is updated), or
- * is empty in case of an initial Duktape.Thread.resume().
- *
- * The first thing to do here is to figure out whether an ecma-to-ecma
- * call is actually possible. It's not always the case if the target is
- * a bound function; the final function may be native. In that case,
- * 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_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) */
- 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 => never for ecma calls) */
- duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => never for ecma calls) */
- duk_hobject *func; /* 'func' on stack (borrowed reference) */
- duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) */
- duk_activation *act;
- duk_hobject *env;
- duk_bool_t use_tailcall;
- duk_instr_t **entry_ptr_curr_pc;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(!((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 && (call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0));
-
- /* XXX: assume these? */
- DUK_ASSERT(thr->valstack != NULL);
- DUK_ASSERT(thr->callstack != NULL);
- DUK_ASSERT(thr->catchstack != NULL);
-
- /* no need to handle thread state book-keeping here */
- DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ||
- (thr->state == DUK_HTHREAD_STATE_RUNNING &&
- thr->heap->curr_thread == thr));
-
- /* 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. If we end up not making the
- * call we must restore the value.
- */
- entry_ptr_curr_pc = thr->ptr_curr_pc;
- duk_hthread_sync_and_null_currpc(thr);
-
- /* if a tail call:
- * - an Ecmascript activation must be on top of the callstack
- * - there cannot be any active catchstack entries
- */
-#if defined(DUK_USE_ASSERTIONS)
- if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
- duk_size_t our_callstack_index;
- duk_size_t i;
-
- DUK_ASSERT(thr->callstack_top >= 1);
- our_callstack_index = thr->callstack_top - 1;
- DUK_ASSERT_DISABLE(our_callstack_index >= 0);
- DUK_ASSERT(our_callstack_index < thr->callstack_size);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index)));
-
- /* No entry in the catchstack which would actually catch a
- * throw can refer to the callstack entry being reused.
- * There *can* be catchstack entries referring to the current
- * callstack entry as long as they don't catch (e.g. label sites).
- */
-
- for (i = 0; i < thr->catchstack_top; i++) {
- DUK_ASSERT(thr->catchstack[i].callstack_index < our_callstack_index || /* refer to callstack entries below current */
- DUK_CAT_GET_TYPE(thr->catchstack + i) == DUK_CAT_TYPE_LABEL); /* or a non-catching entry */
- }
- }
-#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;
-
- DUK_DD(DUK_DDPRINT("handle_ecma_call_setup: thr=%p, "
- "num_stack_args=%ld, call_flags=0x%08lx (resume=%ld, tailcall=%ld), "
- "idx_func=%ld, idx_args=%ld, entry_valstack_bottom_index=%ld",
- (void *) thr,
- (long) num_stack_args,
- (unsigned long) call_flags,
- (long) ((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ? 1 : 0),
- (long) ((call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0 ? 1 : 0),
- (long) idx_func,
- (long) idx_args,
- (long) entry_valstack_bottom_index));
-
- 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);
- }
-
- /*
- * Check the function type, handle bound function chains, and prepare
- * parameters for the rest of the call handling. Also figure out the
- * effective 'this' binding, which replaces the current value at
- * idx_func + 1.
- *
- * If the target function is a 'bound' one, follow the chain of 'bound'
- * functions until a non-bound function is found. During this process,
- * bound arguments are 'prepended' to existing ones, and the "this"
- * binding is overridden. See E5 Section 15.3.4.5.1.
- *
- * If the final target function cannot be handled by an ecma-to-ecma
- * call, return to the caller with a return value indicating this case.
- * The bound chain is resolved and the caller can resume with a plain
- * function call.
- */
-
- func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
- if (func == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- DUK_DDD(DUK_DDDPRINT("final target is a lightfunc/nativefunc, cannot do ecma-to-ecma call"));
- thr->ptr_curr_pc = entry_ptr_curr_pc;
- return 0;
- }
- /* XXX: tv_func is not actually needed */
-
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(func));
-
- duk__coerce_effective_this_binding(thr, func, idx_func + 1);
- DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
- duk_get_tval(ctx, idx_func + 1)));
-
- nargs = ((duk_hcompiledfunction *) func)->nargs;
- nregs = ((duk_hcompiledfunction *) func)->nregs;
- DUK_ASSERT(nregs >= nargs);
-
- /* [ ... func this arg1 ... argN ] */
-
- /*
- * Preliminary activation record and valstack manipulation.
- * The concrete actions depend on whether the we're dealing
- * with a tail call (reuse an existing activation), a resume,
- * or a normal call.
- *
- * The basic actions, in varying order, are:
- *
- * - Check stack size for call handling
- * - Grow call stack if necessary (non-tail-calls)
- * - Update current activation (idx_retval) if necessary
- * (non-tail, non-resume calls)
- * - Move start of args (idx_args) to valstack bottom
- * (tail calls)
- *
- * Don't touch valstack_bottom or valstack_top yet so that Duktape API
- * calls work normally.
- */
-
- /* XXX: some overlapping code; cleanup */
- use_tailcall = call_flags & DUK_CALL_FLAG_IS_TAILCALL;
-#if !defined(DUK_USE_TAILCALL)
- DUK_ASSERT(use_tailcall == 0); /* compiler ensures this */
-#endif
- if (use_tailcall) {
- /* tailcall cannot be flagged to resume calls, and a
- * previous frame must exist
- */
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0);
-
- act = thr->callstack + thr->callstack_top - 1;
- if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
- /* See: test-bug-tailcall-preventyield-assert.c. */
- DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD"));
- use_tailcall = 0;
- } else if (DUK_HOBJECT_HAS_NOTAIL(func)) {
- DUK_D(DUK_DPRINT("tail call prevented by function having a notail flag"));
- use_tailcall = 0;
- }
- }
-
- if (use_tailcall) {
- duk_tval *tv1, *tv2;
- duk_size_t cs_index;
- duk_int_t i_stk; /* must be signed for loop structure */
- duk_idx_t i_arg;
-
- /*
- * Tailcall handling
- *
- * Although the callstack entry is reused, we need to explicitly unwind
- * the current activation (or simulate an unwind). In particular, the
- * current activation must be closed, otherwise something like
- * test-bug-reduce-judofyr.js results. Also catchstack needs be unwound
- * because there may be non-error-catching label entries in valid tail calls.
- */
-
- DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
- (long) (thr->callstack_top - 1)));
-
- /* 'act' already set above */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
-
- /* Unwind catchstack entries referring to the callstack entry we're reusing */
- cs_index = thr->callstack_top - 1;
- DUK_ASSERT(thr->catchstack_top <= DUK_INT_MAX); /* catchstack limits */
- for (i_stk = (duk_int_t) (thr->catchstack_top - 1); i_stk >= 0; i_stk--) {
- duk_catcher *cat = thr->catchstack + i_stk;
- if (cat->callstack_index != cs_index) {
- /* 'i' is the first entry we'll keep */
- break;
- }
- }
- duk_hthread_catchstack_unwind(thr, i_stk + 1);
-
- /* Unwind the topmost callstack entry before reusing it */
- DUK_ASSERT(thr->callstack_top > 0);
- duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
-
- /* Then reuse the unwound activation; callstack was not shrunk so there is always space */
- thr->callstack_top++;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
- act = thr->callstack + thr->callstack_top - 1;
-
- /* Start filling in the activation */
- act->func = func; /* don't want an intermediate exposed state with func == NULL */
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- act->prev_caller = NULL;
-#endif
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- /* don't want an intermediate exposed state with invalid pc */
- act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- act->prev_line = 0;
-#endif
- DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-#if defined(DUK_USE_REFERENCE_COUNTING)
- DUK_HOBJECT_INCREF(thr, func);
- act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
-#endif
-
-#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
- * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- * is in use.
- */
- duk__update_func_caller_prop(thr, func);
- act = thr->callstack + thr->callstack_top - 1;
-#endif
-
- act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
- DUK_ACT_FLAG_STRICT | DUK_ACT_FLAG_TAILCALLED :
- DUK_ACT_FLAG_TAILCALLED);
-
- DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
- DUK_ASSERT(act->var_env == NULL); /* already NULLed (by unwind) */
- DUK_ASSERT(act->lex_env == NULL); /* already NULLed (by unwind) */
- act->idx_bottom = entry_valstack_bottom_index; /* tail call -> reuse current "frame" */
- DUK_ASSERT(nregs >= 0);
-#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
- act->idx_retval = 0;
-#endif
-
- /*
- * Manipulate valstack so that args are on the current bottom and the
- * previous caller's 'this' binding (which is the value preceding the
- * current bottom) is replaced with the new 'this' binding:
- *
- * [ ... this_old | (crud) func this_new arg1 ... argN ]
- * --> [ ... this_new | arg1 ... argN ]
- *
- * For tail calling to work properly, the valstack bottom must not grow
- * here; otherwise crud would accumulate on the valstack.
- */
-
- tv1 = thr->valstack_bottom - 1;
- tv2 = thr->valstack_bottom + idx_func + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
- DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
-
- for (i_arg = 0; i_arg < idx_args; i_arg++) {
- /* XXX: block removal API primitive */
- /* Note: 'func' is popped from valstack here, but it is
- * already reachable from the activation.
- */
- duk_remove(ctx, 0);
- }
- idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
- idx_args = 0;
-
- /* [ ... this_new | arg1 ... argN ] */
- } else {
- DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
- (long) (thr->callstack_top)));
-
- duk_hthread_callstack_grow(thr);
-
- if (call_flags & DUK_CALL_FLAG_IS_RESUME) {
- DUK_DDD(DUK_DDDPRINT("is resume -> no update to current activation (may not even exist)"));
- } else {
- DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval"));
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
- DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(act)));
- act->idx_retval = entry_valstack_bottom_index + idx_func;
- }
-
- DUK_ASSERT(thr->callstack_top < thr->callstack_size);
- act = thr->callstack + thr->callstack_top;
- thr->callstack_top++;
- DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(func));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
-
- act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
- DUK_ACT_FLAG_STRICT :
- 0);
- act->func = func;
- act->var_env = NULL;
- act->lex_env = NULL;
-#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
- act->prev_caller = NULL;
-#endif
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(func));
- act->curr_pc = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) func);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- act->prev_line = 0;
-#endif
- act->idx_bottom = entry_valstack_bottom_index + idx_args;
- DUK_ASSERT(nregs >= 0);
-#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
- act->idx_retval = 0;
-#endif
- DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
-
- DUK_HOBJECT_INCREF(thr, func); /* act->func */
-
-#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)
- *
- * idx_args updated to match
- */
-
- /*
- * Environment record creation and 'arguments' object creation.
- * Named function expression name binding is handled by the
- * compiler; the compiled function's parent env will contain
- * the (immutable) binding already.
- *
- * 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)) {
- /* use existing env (e.g. for non-strict eval); cannot have
- * an own 'arguments' object (but can refer to the existing one)
- */
-
- duk__handle_oldenv_for_call(thr, func, act);
-
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
- goto env_done;
- }
-
- DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
-
- if (!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);
-
- /* [ ... arg1 ... argN envobj ] */
-
- /* original input stack before nargs/nregs handling must be
- * intact for 'arguments' object
- */
- DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
- duk__handle_createargs_for_call(thr, func, env, num_stack_args);
-
- /* [ ... arg1 ... argN envobj ] */
-
- act = thr->callstack + thr->callstack_top - 1;
- act->lex_env = env;
- act->var_env = env;
- DUK_HOBJECT_INCREF(thr, act->lex_env);
- DUK_HOBJECT_INCREF(thr, act->var_env);
- duk_pop(ctx);
-
- env_done:
- /* [ ... arg1 ... argN ] */
-
- /*
- * Setup value stack: clamp to 'nargs', fill up to 'nregs'
- */
-
- duk__adjust_valstack_and_top(thr,
- num_stack_args,
- idx_args,
- nregs,
- nargs,
- func);
-
- /*
- * Shift to new valstack_bottom.
- */
-
- 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);
-
- /*
- * Return to bytecode executor, which will resume execution from
- * the topmost activation.
- */
-
- return 1;
-}
-#line 1 "duk_js_compiler.c"
-/*
- * Ecmascript compiler.
- *
- * Parses an input string and generates a function template result.
- * Compilation may happen in multiple contexts (global code, eval
- * code, function code).
- *
- * The parser uses a traditional top-down recursive parsing for the
- * statement level, and an operator precedence based top-down approach
- * for the expression level. The attempt is to minimize the C stack
- * depth. Bytecode is generated directly without an intermediate
- * representation (tree), at the cost of needing two passes over each
- * function.
- *
- * The top-down recursive parser functions are named "duk__parse_XXX".
- *
- * Recursion limits are in key functions to prevent arbitrary C recursion:
- * function body parsing, statement parsing, and expression parsing.
- *
- * See doc/compiler.rst for discussion on the design.
- *
- * A few typing notes:
- *
- * - duk_regconst_t: unsigned, no marker value for "none"
- * - duk_reg_t: signed, < 0 = none
- * - PC values: duk_int_t, negative values used as markers
- */
-
-/* include removed: duk_internal.h */
-
-/* if highest bit of a register number is set, it refers to a constant instead */
-#define DUK__CONST_MARKER DUK_JS_CONST_MARKER
-
-/* for array and object literals */
-#define DUK__MAX_ARRAY_INIT_VALUES 20
-#define DUK__MAX_OBJECT_INIT_PAIRS 10
-
-/* XXX: hack, remove when const lookup is not O(n) */
-#define DUK__GETCONST_MAX_CONSTS_CHECK 256
-
-/* These limits are based on bytecode limits. Max temps is limited
- * by duk_hcompiledfunction nargs/nregs fields being 16 bits.
- */
-#define DUK__MAX_CONSTS DUK_BC_BC_MAX
-#define DUK__MAX_FUNCS DUK_BC_BC_MAX
-#define DUK__MAX_TEMPS 0xffffL
-
-/* Initial bytecode size allocation. */
-#define DUK__BC_INITIAL_INSTS 256
-
-#define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \
- DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
- duk__recursion_increase((comp_ctx)); \
- } while (0)
-
-#define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \
- DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
- duk__recursion_decrease((comp_ctx)); \
- } while (0)
-
-/* Value stack slot limits: these are quite approximate right now, and
- * because they overlap in control flow, some could be eliminated.
- */
-#define DUK__COMPILE_ENTRY_SLOTS 8
-#define DUK__FUNCTION_INIT_REQUIRE_SLOTS 16
-#define DUK__FUNCTION_BODY_REQUIRE_SLOTS 16
-#define DUK__PARSE_STATEMENTS_SLOTS 16
-#define DUK__PARSE_EXPR_SLOTS 16
-
-/* Temporary structure used to pass a stack allocated region through
- * duk_safe_call().
- */
-typedef struct {
- duk_small_uint_t flags;
- duk_compiler_ctx comp_ctx_alloc;
- duk_lexer_point lex_pt_alloc;
-} duk__compiler_stkstate;
-
-/*
- * Prototypes
- */
-
-/* lexing */
-DUK_LOCAL_DECL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
-DUK_LOCAL_DECL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
-DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx);
-
-/* function helpers */
-DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg);
-DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_bool_t force_no_namebind);
-DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
-
-/* code emission */
-DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc);
-DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins);
-#if 0 /* unused */
-DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op);
-#endif
-DUK_LOCAL_DECL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c);
-DUK_LOCAL_DECL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b);
-#if 0 /* unused */
-DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
-#endif
-DUK_LOCAL_DECL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc);
-DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc);
-DUK_LOCAL_DECL void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b, duk_regconst_t c);
-DUK_LOCAL_DECL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b);
-DUK_LOCAL_DECL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc);
-DUK_LOCAL_DECL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags);
-DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
-DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
-DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
-DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
-DUK_LOCAL_DECL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc);
-DUK_LOCAL_DECL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
-DUK_LOCAL_DECL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
-DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
-DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx);
-
-/* ivalue/ispec helpers */
-DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
-DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
-DUK_LOCAL_DECL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
-DUK_LOCAL_DECL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
-DUK_LOCAL_DECL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next);
-DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL
-duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
- duk_ispec *x,
- duk_reg_t forced_reg,
- duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg);
-DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg);
-DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
-DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
-DUK_LOCAL_DECL
-duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
- duk_ivalue *x,
- duk_reg_t forced_reg,
- duk_small_uint_t flags);
-DUK_LOCAL_DECL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
-#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
-#endif
-DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg);
-DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
-DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
-
-/* identifier handling */
-DUK_LOCAL_DECL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
-
-/* label handling */
-DUK_LOCAL_DECL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id);
-DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags);
-DUK_LOCAL_DECL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest);
-DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len);
-
-/* top-down expression parser */
-DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res);
-DUK_LOCAL_DECL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx);
-
-/* exprtop is the top level variant which resets nud/led counts */
-DUK_LOCAL_DECL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-
-/* convenience helpers */
-#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-#endif
-#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-#endif
-DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg);
-DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-#if 0 /* unused */
-DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-#endif
-DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-DUK_LOCAL_DECL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-#if 0 /* unused */
-DUK_LOCAL_DECL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-#endif
-DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg);
-DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-#if 0 /* unused */
-DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
-#endif
-
-/* expression parsing helpers */
-DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, duk_small_uint_t new_key_flags);
-
-/* statement parsing */
-DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
-DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags);
-DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
-DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
-DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
-DUK_LOCAL_DECL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
-DUK_LOCAL_DECL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
-DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem);
-DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id);
-DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof);
-
-DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token);
-DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
-DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget);
-DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget);
-
-/*
- * Parser control values for tokens. The token table is ordered by the
- * DUK_TOK_XXX defines.
- *
- * The binding powers are for lbp() use (i.e. for use in led() context).
- * Binding powers are positive for typing convenience, and bits at the
- * top should be reserved for flags. Binding power step must be higher
- * than 1 so that binding power "lbp - 1" can be used for right associative
- * operators. Currently a step of 2 is used (which frees one more bit for
- * flags).
- */
-
-/* XXX: actually single step levels would work just fine, clean up */
-
-/* binding power "levels" (see doc/compiler.rst) */
-#define DUK__BP_INVALID 0 /* always terminates led() */
-#define DUK__BP_EOF 2
-#define DUK__BP_CLOSING 4 /* token closes expression, e.g. ')', ']' */
-#define DUK__BP_FOR_EXPR DUK__BP_CLOSING /* bp to use when parsing a top level Expression */
-#define DUK__BP_COMMA 6
-#define DUK__BP_ASSIGNMENT 8
-#define DUK__BP_CONDITIONAL 10
-#define DUK__BP_LOR 12
-#define DUK__BP_LAND 14
-#define DUK__BP_BOR 16
-#define DUK__BP_BXOR 18
-#define DUK__BP_BAND 20
-#define DUK__BP_EQUALITY 22
-#define DUK__BP_RELATIONAL 24
-#define DUK__BP_SHIFT 26
-#define DUK__BP_ADDITIVE 28
-#define DUK__BP_MULTIPLICATIVE 30
-#define DUK__BP_POSTFIX 32
-#define DUK__BP_CALL 34
-#define DUK__BP_MEMBER 36
-
-#define DUK__TOKEN_LBP_BP_MASK 0x1f
-#define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */
-#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */
-#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* spare */
-
-#define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
-
-#define DUK__MK_LBP(bp) ((bp) >> 1) /* bp is assumed to be even */
-#define DUK__MK_LBP_FLAGS(bp,flags) (((bp) >> 1) | (flags))
-
-DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
- DUK__MK_LBP(DUK__BP_EOF), /* DUK_TOK_EOF */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_IDENTIFIER */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BREAK */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CASE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CATCH */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONTINUE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEBUGGER */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEFAULT */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DELETE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DO */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ELSE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FINALLY */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FOR */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FUNCTION */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IF */
- DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_IN */
- DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_INSTANCEOF */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_NEW */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_RETURN */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SWITCH */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_THIS */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_THROW */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPORT */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SUPER */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NULL */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_TRUE */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_FALSE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_GET */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SET */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPLEMENTS */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_INTERFACE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LET */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PACKAGE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PRIVATE */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PROTECTED */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PUBLIC */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_STATIC */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_YIELD */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LCURLY */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RCURLY */
- DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_LBRACKET */
- DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RBRACKET */
- DUK__MK_LBP(DUK__BP_CALL), /* DUK_TOK_LPAREN */
- DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RPAREN */
- DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_PERIOD */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SEMICOLON */
- DUK__MK_LBP(DUK__BP_COMMA), /* DUK_TOK_COMMA */
- DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LT */
- DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GT */
- DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LE */
- DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GE */
- DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_EQ */
- DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_NEQ */
- DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SEQ */
- DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SNEQ */
- DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_ADD */
- DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_SUB */
- DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MUL */
- DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_DIV */
- DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MOD */
- DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_INCREMENT */
- DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_DECREMENT */
- DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ALSHIFT */
- DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ARSHIFT */
- DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_RSHIFT */
- DUK__MK_LBP(DUK__BP_BAND), /* DUK_TOK_BAND */
- DUK__MK_LBP(DUK__BP_BOR), /* DUK_TOK_BOR */
- DUK__MK_LBP(DUK__BP_BXOR), /* DUK_TOK_BXOR */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LNOT */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BNOT */
- DUK__MK_LBP(DUK__BP_LAND), /* DUK_TOK_LAND */
- DUK__MK_LBP(DUK__BP_LOR), /* DUK_TOK_LOR */
- DUK__MK_LBP(DUK__BP_CONDITIONAL), /* DUK_TOK_QUESTION */
- DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_COLON */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EQUALSIGN */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ADD_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_SUB_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MUL_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_DIV_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MOD_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ALSHIFT_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ARSHIFT_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_RSHIFT_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */
- DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */
- DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */
-};
-
-/*
- * Misc helpers
- */
-
-DUK_LOCAL void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
- DUK_ASSERT(comp_ctx != NULL);
- DUK_ASSERT(comp_ctx->recursion_depth >= 0);
- if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT);
- }
- comp_ctx->recursion_depth++;
-}
-
-DUK_LOCAL void duk__recursion_decrease(duk_compiler_ctx *comp_ctx) {
- DUK_ASSERT(comp_ctx != NULL);
- DUK_ASSERT(comp_ctx->recursion_depth > 0);
- comp_ctx->recursion_depth--;
-}
-
-DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
- DUK_UNREF(comp_ctx);
- DUK_ASSERT(h != NULL);
- return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h);
-}
-
-DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
- DUK_ASSERT(h != NULL);
- return (comp_ctx->curr_func.is_strict &&
- DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h));
-}
-
-/*
- * Parser duk__advance() token eating functions
- */
-
-/* XXX: valstack handling is awkward. Add a valstack helper which
- * avoids dup():ing; valstack_copy(src, dst)?
- */
-
-DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t regexp;
-
- DUK_ASSERT(comp_ctx->curr_token.t >= 0 && comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
-
- /*
- * Use current token to decide whether a RegExp can follow.
- *
- * We can use either 't' or 't_nores'; the latter would not
- * recognize keywords. Some keywords can be followed by a
- * RegExp (e.g. "return"), so using 't' is better. This is
- * not trivial, see doc/compiler.rst.
- */
-
- regexp = 1;
- if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) {
- regexp = 0;
- }
- if (comp_ctx->curr_func.reject_regexp_in_adv) {
- comp_ctx->curr_func.reject_regexp_in_adv = 0;
- regexp = 0;
- }
-
- if (expect >= 0 && comp_ctx->curr_token.t != expect) {
- DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
- (long) expect, (long) comp_ctx->curr_token.t));
- DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
- }
-
- /* make current token the previous; need to fiddle with valstack "backing store" */
- DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
- duk_copy(ctx, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
- duk_copy(ctx, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
-
- /* parse new token */
- duk_lexer_parse_js_input_element(&comp_ctx->lex,
- &comp_ctx->curr_token,
- comp_ctx->curr_func.is_strict,
- regexp);
-
- DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T "
- "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T",
- (long) comp_ctx->curr_token.t,
- (long) comp_ctx->curr_token.t_nores,
- (long) comp_ctx->curr_token.start_line,
- (long) comp_ctx->curr_token.lineterm,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok11_idx),
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok12_idx),
- (long) comp_ctx->prev_token.t,
- (long) comp_ctx->prev_token.t_nores,
- (long) comp_ctx->prev_token.start_line,
- (long) comp_ctx->prev_token.lineterm,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok21_idx),
- (duk_tval *) duk_get_tval(ctx, comp_ctx->tok22_idx)));
-}
-
-/* advance, expecting current token to be a specific token; parse next token in regexp context */
-DUK_LOCAL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
- duk__advance_helper(comp_ctx, expect);
-}
-
-/* advance, whatever the current token is; parse next token in regexp context */
-DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) {
- duk__advance_helper(comp_ctx, -1);
-}
-
-/*
- * Helpers for duk_compiler_func.
- */
-
-/* init function state: inits valstack allocations */
-DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
- duk_compiler_func *func = &comp_ctx->curr_func;
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_idx_t entry_top;
-
- entry_top = duk_get_top(ctx);
-
- DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- func->h_name = NULL;
- func->h_consts = NULL;
- func->h_funcs = NULL;
- func->h_decls = NULL;
- func->h_labelnames = NULL;
- func->h_labelinfos = NULL;
- func->h_argnames = NULL;
- func->h_varmap = NULL;
-#endif
-
- duk_require_stack(ctx, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
-
- DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
- /* code_idx = entry_top + 0 */
-
- duk_push_array(ctx);
- func->consts_idx = entry_top + 1;
- func->h_consts = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 1);
- DUK_ASSERT(func->h_consts != NULL);
-
- duk_push_array(ctx);
- func->funcs_idx = entry_top + 2;
- func->h_funcs = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 2);
- DUK_ASSERT(func->h_funcs != NULL);
- DUK_ASSERT(func->fnum_next == 0);
-
- duk_push_array(ctx);
- func->decls_idx = entry_top + 3;
- func->h_decls = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 3);
- DUK_ASSERT(func->h_decls != NULL);
-
- duk_push_array(ctx);
- func->labelnames_idx = entry_top + 4;
- func->h_labelnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 4);
- DUK_ASSERT(func->h_labelnames != NULL);
-
- duk_push_dynamic_buffer(ctx, 0);
- func->labelinfos_idx = entry_top + 5;
- func->h_labelinfos = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 5);
- DUK_ASSERT(func->h_labelinfos != NULL);
- DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos));
-
- duk_push_array(ctx);
- func->argnames_idx = entry_top + 6;
- func->h_argnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 6);
- DUK_ASSERT(func->h_argnames != NULL);
-
- duk_push_object_internal(ctx);
- func->varmap_idx = entry_top + 7;
- func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 7);
- DUK_ASSERT(func->h_varmap != NULL);
-}
-
-/* reset function state (prepare for pass 2) */
-DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
- duk_compiler_func *func = &comp_ctx->curr_func;
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
-
- /* reset bytecode buffer but keep current size; pass 2 will
- * require same amount or more.
- */
- DUK_BW_RESET_SIZE(thr, &func->bw_code);
-
- duk_hobject_set_length_zero(thr, func->h_consts);
- /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
- func->fnum_next = 0;
- /* duk_hobject_set_length_zero(thr, func->h_funcs); */
- duk_hobject_set_length_zero(thr, func->h_labelnames);
- duk_hbuffer_reset(thr, func->h_labelinfos);
- /* keep func->h_argnames; it is fixed for all passes */
-
- /* truncated in case pass 3 needed */
- duk_push_object_internal(ctx);
- duk_replace(ctx, func->varmap_idx);
- func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, func->varmap_idx);
- DUK_ASSERT(func->h_varmap != NULL);
-}
-
-/* cleanup varmap from any null entries, compact it, etc; returns number
- * of final entries after cleanup.
- */
-DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *h_varmap;
- duk_hstring *h_key;
- duk_tval *tv;
- duk_uint32_t i, e_next;
- duk_int_t ret;
-
- /* [ ... varmap ] */
-
- h_varmap = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
- DUK_ASSERT(h_varmap != NULL);
-
- ret = 0;
- e_next = DUK_HOBJECT_GET_ENEXT(h_varmap);
- for (i = 0; i < e_next; i++) {
- h_key = DUK_HOBJECT_E_GET_KEY(thr->heap, h_varmap, i);
- if (!h_key) {
- continue;
- }
-
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i));
-
- /* The entries can either be register numbers or 'null' values.
- * Thus, no need to DECREF them and get side effects. DECREF'ing
- * the keys (strings) can cause memory to be freed but no side
- * effects as strings don't have finalizers. This is why we can
- * rely on the object properties not changing from underneath us.
- */
-
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h_varmap, i);
- if (!DUK_TVAL_IS_NUMBER(tv)) {
- DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv));
- DUK_HOBJECT_E_SET_KEY(thr->heap, h_varmap, i, NULL);
- DUK_HSTRING_DECREF(thr, h_key);
- /* when key is NULL, value is garbage so no need to set */
- } else {
- ret++;
- }
- }
-
- duk_compact(ctx, -1);
-
- return ret;
-}
-
-/* convert duk_compiler_func into a function template, leaving the result
- * on top of stack.
- */
-/* XXX: awkward and bloated asm -- use faster internal accesses */
-DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx, duk_bool_t force_no_namebind) {
- duk_compiler_func *func = &comp_ctx->curr_func;
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_hcompiledfunction *h_res;
- duk_hbuffer_fixed *h_data;
- duk_size_t consts_count;
- duk_size_t funcs_count;
- duk_size_t code_count;
- duk_size_t code_size;
- duk_size_t data_size;
- duk_size_t i;
- duk_tval *p_const;
- duk_hobject **p_func;
- duk_instr_t *p_instr;
- duk_compiler_instr *q_instr;
- duk_tval *tv;
-
- DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
-
- /*
- * Push result object and init its flags
- */
-
- /* Valstack should suffice here, required on function valstack init */
-
- (void) duk_push_compiledfunction(ctx);
- h_res = (duk_hcompiledfunction *) DUK_GET_HOBJECT_NEGIDX(ctx, -1); /* XXX: specific getter */
- DUK_ASSERT(h_res != NULL);
-
- if (func->is_function) {
- DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
- DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
-
- if (!func->is_arguments_shadowed) {
- /* arguments object would be accessible; note that shadowing
- * bindings are arguments or function declarations, neither
- * of which are deletable, so this is safe.
- */
-
- if (func->id_access_arguments || func->may_direct_eval) {
- DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or "
- "indirectly -> set CREATEARGS"));
- DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res);
- }
- }
- } else if (func->is_eval && func->is_strict) {
- DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV"));
- DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
- } else {
- /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
- * global code: env is is global env
- */
- DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV"));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res));
- }
-
- if (func->is_function && !func->is_decl && func->h_name != NULL && !force_no_namebind) {
- /* Object literal set/get functions have a name (property
- * name) but must not have a lexical name binding, see
- * test-bug-getset-func-name.js.
- */
- DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
- DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
- }
-
- if (func->is_strict) {
- DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
- DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
- }
-
- if (func->is_notail) {
- DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
- DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
- }
-
- /*
- * Build function fixed size 'data' buffer, which contains bytecode,
- * constants, and inner function references.
- *
- * During the building phase 'data' is reachable but incomplete.
- * Only incref's occur during building (no refzero or GC happens),
- * so the building process is atomic.
- */
-
- consts_count = duk_hobject_get_length(thr, func->h_consts);
- funcs_count = duk_hobject_get_length(thr, func->h_funcs) / 3;
- code_count = DUK_BW_GET_SIZE(thr, &func->bw_code) / sizeof(duk_compiler_instr);
- code_size = code_count * sizeof(duk_instr_t);
-
- data_size = consts_count * sizeof(duk_tval) +
- funcs_count * sizeof(duk_hobject *) +
- code_size;
-
- DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> "
- "data_size=%ld*%ld + %ld*%ld + %ld = %ld",
- (long) consts_count, (long) funcs_count, (long) code_size,
- (long) consts_count, (long) sizeof(duk_tval),
- (long) funcs_count, (long) sizeof(duk_hobject *),
- (long) code_size, (long) data_size));
-
- duk_push_fixed_buffer(ctx, data_size);
- h_data = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
- DUK_ASSERT(h_data != NULL);
-
- DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
- DUK_HEAPHDR_INCREF(thr, h_data);
-
- p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data);
- for (i = 0; i < consts_count; i++) {
- DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* const limits */
- tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_consts, (duk_uarridx_t) i);
- DUK_ASSERT(tv != NULL);
- DUK_TVAL_SET_TVAL(p_const, tv);
- p_const++;
- DUK_TVAL_INCREF(thr, tv); /* may be a string constant */
-
- DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval *) tv));
- }
-
- p_func = (duk_hobject **) p_const;
- DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, h_res, p_func);
- for (i = 0; i < funcs_count; i++) {
- duk_hobject *h;
- DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX); /* func limits */
- tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_funcs, (duk_uarridx_t) (i * 3));
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- h = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(h != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(h));
- *p_func++ = h;
- DUK_HOBJECT_INCREF(thr, h);
-
- DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO",
- (void *) h, (duk_heaphdr *) h));
- }
-
- p_instr = (duk_instr_t *) p_func;
- DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, h_res, p_instr);
-
- /* copy bytecode instructions one at a time */
- q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code);
- for (i = 0; i < code_count; i++) {
- p_instr[i] = q_instr[i].ins;
- }
- /* Note: 'q_instr' is still used below */
-
- DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
-
- duk_pop(ctx); /* 'data' (and everything in it) is reachable through h_res now */
-
- /*
- * Init object properties
- *
- * Properties should be added in decreasing order of access frequency.
- * (Not very critical for function templates.)
- */
-
- DUK_DDD(DUK_DDDPRINT("init function properties"));
-
- /* [ ... res ] */
-
- /* _Varmap: omitted if function is guaranteed not to do slow path identifier
- * accesses or if it would turn out to be empty of actual register mappings
- * after a cleanup. When debugging is enabled, we always need the varmap to
- * be able to lookup variables at any point.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (1) {
-#else
- if (func->id_access_slow || /* directly uses slow accesses */
- func->may_direct_eval || /* may indirectly slow access through a direct eval */
- funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
-#endif
- duk_int_t num_used;
- duk_dup(ctx, func->varmap_idx);
- num_used = duk__cleanup_varmap(comp_ctx);
- DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
- (duk_tval *) duk_get_tval(ctx, -1), (long) num_used));
-
- if (num_used > 0) {
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
- } else {
- DUK_DDD(DUK_DDDPRINT("varmap is empty after cleanup -> no need to add"));
- duk_pop(ctx);
- }
- }
-
- /* _Formals: omitted if function is guaranteed not to need a (non-strict) arguments object */
- if (1) {
- /* XXX: Add a proper condition. If formals list is omitted, recheck
- * handling for 'length' in duk_js_push_closure(); it currently relies
- * on _Formals being set. Removal may need to be conditional to debugging
- * being enabled/disabled too.
- */
- duk_dup(ctx, func->argnames_idx);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
- }
-
- /* name */
- if (func->h_name) {
- duk_push_hstring(ctx, func->h_name);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
- }
-
- /* _Source */
-#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
- if (0) {
- /* XXX: Currently function source code is not stored, as it is not
- * required by the standard. Source code should not be stored by
- * default (user should enable it explicitly), and the source should
- * probably be compressed with a trivial text compressor; average
- * compression of 20-30% is quite easy to achieve even with a trivial
- * compressor (RLE + backwards lookup).
- *
- * Debugging needs source code to be useful: sometimes input code is
- * not found in files as it may be generated and then eval()'d, given
- * by dynamic C code, etc.
- *
- * Other issues:
- *
- * - Need tokenizer indices for start and end to substring
- * - Always normalize function declaration part?
- * - If we keep _Formals, only need to store body
- */
-
- /*
- * For global or eval code this is straightforward. For functions
- * created with the Function constructor we only get the source for
- * the body and must manufacture the "function ..." part.
- *
- * For instance, for constructed functions (v8):
- *
- * > a = new Function("foo", "bar", "print(foo)");
- * [Function]
- * > a.toString()
- * 'function anonymous(foo,bar) {\nprint(foo)\n}'
- *
- * Similarly for e.g. getters (v8):
- *
- * > x = { get a(foo,bar) { print(foo); } }
- * { a: [Getter] }
- * > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
- * 'function a(foo,bar) { print(foo); }'
- */
-
-#if 0
- duk_push_string(ctx, "XXX");
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
-#endif
- }
-#endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
-
- /* _Pc2line */
-#if defined(DUK_USE_PC2LINE)
- if (1) {
- /*
- * Size-optimized pc->line mapping.
- */
-
- DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
- duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
-
- /* XXX: if assertions enabled, walk through all valid PCs
- * and check line mapping.
- */
- }
-#endif /* DUK_USE_PC2LINE */
-
- /* fileName */
- if (comp_ctx->h_filename) {
- /*
- * Source filename (or equivalent), for identifying thrown errors.
- */
-
- duk_push_hstring(ctx, comp_ctx->h_filename);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
- }
-
- /*
- * Init remaining result fields
- *
- * 'nregs' controls how large a register frame is allocated.
- *
- * 'nargs' controls how many formal arguments are written to registers:
- * r0, ... r(nargs-1). The remaining registers are initialized to
- * undefined.
- */
-
- DUK_ASSERT(func->temp_max >= 0);
- 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;
- h_res->end_line = (duk_uint32_t) func->max_line;
-#endif
-
- DUK_DD(DUK_DDPRINT("converted function: %!ixT",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /*
- * Compact the function template.
- */
-
- duk_compact(ctx, -1);
-
- /*
- * Debug dumping
- */
-
-#ifdef DUK_USE_DDDPRINT
- {
- duk_hcompiledfunction *h;
- duk_instr_t *p, *p_start, *p_end;
-
- h = (duk_hcompiledfunction *) duk_get_hobject(ctx, -1);
- p_start = (duk_instr_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, h);
- p_end = (duk_instr_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, h);
-
- p = p_start;
- while (p < p_end) {
- DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!C) a=%ld b=%ld c=%ld",
- (long) (p - p_start),
- (duk_instr_t) (*p),
- (unsigned long) (*p),
- (long) DUK_DEC_OP(*p),
- (long) DUK_DEC_OP(*p),
- (long) DUK_DEC_A(*p),
- (long) DUK_DEC_B(*p),
- (long) DUK_DEC_C(*p)));
- p++;
- }
- }
-#endif
-}
-
-/*
- * Code emission helpers
- *
- * Some emission helpers understand the range of target and source reg/const
- * values and automatically emit shuffling code if necessary. This is the
- * case when the slot in question (A, B, C) is used in the standard way and
- * for opcodes the emission helpers explicitly understand (like DUK_OP_CALL).
- *
- * The standard way is that:
- * - slot A is a target register
- * - slot B is a source register/constant
- * - slot C is a source register/constant
- *
- * If a slot is used in a non-standard way the caller must indicate this
- * somehow. If a slot is used as a target instead of a source (or vice
- * versa), this can be indicated with a flag to trigger proper shuffling
- * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not
- * register/const related at all, the caller must ensure that the raw value
- * fits into the corresponding slot so as to not trigger shuffling. The
- * caller must set a "no shuffle" flag to ensure compilation fails if
- * shuffling were to be triggered because of an internal error.
- *
- * For slots B and C the raw slot size is 9 bits but one bit is reserved for
- * the reg/const indicator. To use the full 9-bit range for a raw value,
- * shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag.
- * Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots.
- *
- * There is call handling specific understanding in the A-B-C emitter to
- * convert call setup and call instructions into indirect ones if necessary.
- */
-
-/* Code emission flags, passed in the 'opcode' field. Opcode + flags
- * fit into 16 bits for now, so use duk_small_uint.t.
- */
-#define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8)
-#define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9)
-#define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10)
-#define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */
-#define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */
-#define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */
-#define DUK__EMIT_FLAG_B_IS_TARGETSOURCE (1 << 14) /* slot B is both a target and a source (used by extraops like DUK_EXTRAOP_INSTOF */
-#define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */
-
-/* XXX: clarify on when and where DUK__CONST_MARKER is allowed */
-/* XXX: opcode specific assertions on when consts are allowed */
-
-/* XXX: macro smaller than call? */
-DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) {
- duk_compiler_func *func;
- func = &comp_ctx->curr_func;
- return (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &func->bw_code) / sizeof(duk_compiler_instr));
-}
-
-DUK_LOCAL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc) {
- DUK_ASSERT(pc >= 0);
- DUK_ASSERT((duk_size_t) pc < (duk_size_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr)));
- return ((duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code)) + pc;
-}
-
-/* emit instruction; could return PC but that's not needed in the majority
- * of cases.
- */
-DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
-#if defined(DUK_USE_PC2LINE)
- duk_int_t line;
-#endif
- duk_compiler_instr *instr;
-
- DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I",
- (unsigned long) ins,
- (long) comp_ctx->curr_token.start_line,
- (long) comp_ctx->prev_token.start_line,
- (long) duk__get_current_pc(comp_ctx),
- (duk_instr_t) ins));
-
- instr = (duk_compiler_instr *) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
- DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
-
-#if defined(DUK_USE_PC2LINE)
- /* The line number tracking is a bit inconsistent right now, which
- * affects debugger accuracy. Mostly call sites emit opcodes when
- * they have parsed a token (say a terminating semicolon) and called
- * duk__advance(). In this case the line number of the previous
- * token is the most accurate one (except in prologue where
- * prev_token.start_line is 0). This is probably not 100% correct
- * right now.
- */
- /* approximation, close enough */
- line = comp_ctx->prev_token.start_line;
- if (line == 0) {
- line = comp_ctx->curr_token.start_line;
- }
-#endif
-
- instr->ins = ins;
-#if defined(DUK_USE_PC2LINE)
- instr->line = line;
-#endif
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (line < comp_ctx->curr_func.min_line) {
- comp_ctx->curr_func.min_line = line;
- }
- if (line > comp_ctx->curr_func.max_line) {
- comp_ctx->curr_func.max_line = line;
- }
-#endif
-
- /* Limit checks for bytecode byte size and line number. */
- if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
- goto fail_bc_limit;
- }
-#if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS)
-#if defined(DUK_USE_BUFLEN16)
- /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */
- if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
- goto fail_bc_limit;
- }
-#else
- if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
- goto fail_bc_limit;
- }
-#endif
-#endif
-
- return;
-
- fail_bc_limit:
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
-}
-
-/* Update function min/max line from current token. Needed to improve
- * function line range information for debugging, so that e.g. opening
- * curly brace is covered by line range even when no opcodes are emitted
- * for the line containing the brace.
- */
-DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) {
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- duk_int_t line;
-
- line = comp_ctx->curr_token.start_line;
- if (line == 0) {
- return;
- }
- if (line < comp_ctx->curr_func.min_line) {
- comp_ctx->curr_func.min_line = line;
- }
- if (line > comp_ctx->curr_func.max_line) {
- comp_ctx->curr_func.max_line = line;
- }
-#else
- DUK_UNREF(comp_ctx);
-#endif
-}
-
-#if 0 /* unused */
-DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) {
- duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0));
-}
-#endif
-
-/* Important main primitive. */
-DUK_LOCAL void duk__emit_a_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b, duk_regconst_t c) {
- duk_instr_t ins = 0;
- duk_int_t a_out = -1;
- duk_int_t b_out = -1;
- duk_int_t c_out = -1;
- duk_int_t tmp;
-
- DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
- (unsigned long) op_flags, (long) a, (long) b, (long) c));
-
- /* We could rely on max temp/const checks: if they don't exceed BC
- * limit, nothing here can either (just asserts would be enough).
- * Currently we check for the limits, which provides additional
- * protection against creating invalid bytecode due to compiler
- * bugs.
- */
-
- DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
- DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
-
- /* Input shuffling happens before the actual operation, while output
- * shuffling happens afterwards. Output shuffling decisions are still
- * made at the same time to reduce branch clutter; output shuffle decisions
- * are recorded into X_out variables.
- */
-
- /* Slot A */
-
-#if defined(DUK_USE_SHUFFLE_TORTURE)
- if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
-#else
- if (a <= DUK_BC_A_MAX) {
-#endif
- ;
- } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
- DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a));
- goto error_outofregs;
- } else if (a <= DUK_BC_BC_MAX) {
- comp_ctx->curr_func.needs_shuffle = 1;
- tmp = comp_ctx->curr_func.shuffle1;
- if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
- } else {
- duk_small_int_t op = op_flags & 0xff;
- if (op == DUK_OP_CSVAR || op == DUK_OP_CSREG || op == DUK_OP_CSPROP) {
- /* Special handling for call setup instructions. The target
- * is expressed indirectly, but there is no output shuffling.
- */
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) == 0);
- duk__emit_load_int32_noshuffle(comp_ctx, tmp, a);
- DUK_ASSERT(DUK_OP_CSVARI == DUK_OP_CSVAR + 1);
- DUK_ASSERT(DUK_OP_CSREGI == DUK_OP_CSREG + 1);
- DUK_ASSERT(DUK_OP_CSPROPI == DUK_OP_CSPROP + 1);
- op_flags++; /* indirect opcode follows direct */
- } else {
- /* Output shuffle needed after main operation */
- a_out = a;
- }
- }
- a = tmp;
- } else {
- DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld", (long) a));
- goto error_outofregs;
- }
-
- /* Slot B */
-
- if (b & DUK__CONST_MARKER) {
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
- DUK_ASSERT((op_flags & 0xff) != DUK_OP_CALL);
- DUK_ASSERT((op_flags & 0xff) != DUK_OP_NEW);
- b = b & ~DUK__CONST_MARKER;
-#if defined(DUK_USE_SHUFFLE_TORTURE)
- if (0) {
-#else
- if (b <= 0xff) {
-#endif
- ins |= DUK_ENC_OP_A_B_C(0, 0, 0x100, 0); /* const flag for B */
- } else if (b <= DUK_BC_BC_MAX) {
- comp_ctx->curr_func.needs_shuffle = 1;
- tmp = comp_ctx->curr_func.shuffle2;
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b));
- b = tmp;
- } else {
- DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld", (long) b));
- goto error_outofregs;
- }
- } else {
-#if defined(DUK_USE_SHUFFLE_TORTURE)
- if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) {
-#else
- if (b <= 0xff) {
-#endif
- ;
- } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) {
- if (b > DUK_BC_B_MAX) {
- /* Note: 0xff != DUK_BC_B_MAX */
- DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld", (long) b));
- goto error_outofregs;
- }
- } else if (b <= DUK_BC_BC_MAX) {
- comp_ctx->curr_func.needs_shuffle = 1;
- tmp = comp_ctx->curr_func.shuffle2;
- if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) {
- /* Output shuffle needed after main operation */
- b_out = b;
- }
- if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET) || (op_flags & DUK__EMIT_FLAG_B_IS_TARGETSOURCE)) {
- duk_small_int_t op = op_flags & 0xff;
- if (op == DUK_OP_CALL || op == DUK_OP_NEW ||
- op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
- /* Special handling for CALL/NEW/MPUTOBJ/MPUTARR shuffling.
- * For each, slot B identifies the first register of a range
- * of registers, so normal shuffling won't work. Instead,
- * an indirect version of the opcode is used.
- */
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
- duk__emit_load_int32_noshuffle(comp_ctx, tmp, b);
- DUK_ASSERT(DUK_OP_CALLI == DUK_OP_CALL + 1);
- DUK_ASSERT(DUK_OP_NEWI == DUK_OP_NEW + 1);
- DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
- DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1);
- op_flags++; /* indirect opcode follows direct */
- } else {
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b));
- }
- }
- b = tmp;
- } else {
- DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld", (long) b));
- goto error_outofregs;
- }
- }
-
- /* Slot C */
-
- if (c & DUK__CONST_MARKER) {
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
- c = c & ~DUK__CONST_MARKER;
-#if defined(DUK_USE_SHUFFLE_TORTURE)
- if (0) {
-#else
- if (c <= 0xff) {
-#endif
- ins |= DUK_ENC_OP_A_B_C(0, 0, 0, 0x100); /* const flag for C */
- } else if (c <= DUK_BC_BC_MAX) {
- comp_ctx->curr_func.needs_shuffle = 1;
- tmp = comp_ctx->curr_func.shuffle3;
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c));
- c = tmp;
- } else {
- DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld", (long) c));
- goto error_outofregs;
- }
- } else {
-#if defined(DUK_USE_SHUFFLE_TORTURE)
- if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) {
-#else
- if (c <= 0xff) {
-#endif
- ;
- } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) {
- if (c > DUK_BC_C_MAX) {
- /* Note: 0xff != DUK_BC_C_MAX */
- DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld", (long) c));
- goto error_outofregs;
- }
- } else if (c <= DUK_BC_BC_MAX) {
- comp_ctx->curr_func.needs_shuffle = 1;
- tmp = comp_ctx->curr_func.shuffle3;
- if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) {
- /* Output shuffle needed after main operation */
- c_out = c;
- } else {
- duk_small_int_t op = op_flags & 0xff;
- if (op == DUK_OP_EXTRA &&
- (a == DUK_EXTRAOP_INITGET || a == DUK_EXTRAOP_INITSET)) {
- /* Special shuffling for INITGET/INITSET, where slot C
- * identifies a register pair and cannot be shuffled
- * normally. Use an indirect variant instead.
- */
- DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
- duk__emit_load_int32_noshuffle(comp_ctx, tmp, c);
- DUK_ASSERT(DUK_EXTRAOP_INITGETI == DUK_EXTRAOP_INITGET + 1);
- DUK_ASSERT(DUK_EXTRAOP_INITSETI == DUK_EXTRAOP_INITSET + 1);
- a++; /* indirect opcode follows direct */
- } else {
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
- }
- }
- c = tmp;
- } else {
- DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld", (long) c));
- goto error_outofregs;
- }
- }
-
- /* Main operation */
-
- DUK_ASSERT_DISABLE(a >= DUK_BC_A_MIN); /* unsigned */
- DUK_ASSERT(a <= DUK_BC_A_MAX);
- DUK_ASSERT_DISABLE(b >= DUK_BC_B_MIN); /* unsigned */
- DUK_ASSERT(b <= DUK_BC_B_MAX);
- DUK_ASSERT_DISABLE(c >= DUK_BC_C_MIN); /* unsigned */
- DUK_ASSERT(c <= DUK_BC_C_MAX);
-
- ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
- duk__emit(comp_ctx, ins);
-
- /* NEXTENUM needs a jump slot right after the main instruction.
- * When the JUMP is taken, output spilling is not needed so this
- * workaround is possible. The jump slot PC is exceptionally
- * plumbed through comp_ctx to minimize call sites.
- */
- if (op_flags & DUK__EMIT_FLAG_RESERVE_JUMPSLOT) {
- comp_ctx->emit_jumpslot_pc = duk__get_current_pc(comp_ctx);
- duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
- }
-
- /* Output shuffling: only one output register is realistically possible.
- *
- * (Zero would normally be an OK marker value: if the target register
- * was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE
- * this is no longer true, so use -1 as a marker instead.)
- */
-
- if (a_out >= 0) {
- DUK_ASSERT(b_out < 0);
- DUK_ASSERT(c_out < 0);
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
- } else if (b_out >= 0) {
- DUK_ASSERT(a_out < 0);
- DUK_ASSERT(c_out < 0);
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out));
- } else if (c_out >= 0) {
- DUK_ASSERT(b_out < 0);
- DUK_ASSERT(c_out < 0);
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out));
- }
-
- return;
-
- error_outofregs:
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
-}
-
-DUK_LOCAL void duk__emit_a_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t b) {
- duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, b, 0);
-}
-
-#if 0 /* unused */
-DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
- duk__emit_a_b_c(comp_ctx, op_flags | DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C, a, 0, 0);
-}
-#endif
-
-DUK_LOCAL void duk__emit_a_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a, duk_regconst_t bc) {
- duk_instr_t ins;
- duk_int_t tmp;
-
- /* allow caller to give a const number with the DUK__CONST_MARKER */
- bc = bc & (~DUK__CONST_MARKER);
-
- DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
- DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
- DUK_ASSERT_DISABLE(bc >= DUK_BC_BC_MIN); /* unsigned */
- DUK_ASSERT(bc <= DUK_BC_BC_MAX);
- DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
-
- if (bc <= DUK_BC_BC_MAX) {
- ;
- } else {
- /* No BC shuffling now. */
- goto error_outofregs;
- }
-
-#if defined(DUK_USE_SHUFFLE_TORTURE)
- if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
-#else
- if (a <= DUK_BC_A_MAX) {
-#endif
- ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc);
- duk__emit(comp_ctx, ins);
- } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
- goto error_outofregs;
- } else if (a <= DUK_BC_BC_MAX) {
- comp_ctx->curr_func.needs_shuffle = 1;
- tmp = comp_ctx->curr_func.shuffle1;
- ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
- if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
- duk__emit(comp_ctx, ins);
- } else {
- duk__emit(comp_ctx, ins);
- duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a));
- }
- } else {
- goto error_outofregs;
- }
- return;
-
- error_outofregs:
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
-}
-
-DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) {
- duk_instr_t ins;
-
- DUK_ASSERT_DISABLE(op >= DUK_BC_OP_MIN); /* unsigned */
- DUK_ASSERT(op <= DUK_BC_OP_MAX);
- DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */
- DUK_ASSERT(abc <= DUK_BC_ABC_MAX);
- DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
-
- if (abc <= DUK_BC_ABC_MAX) {
- ;
- } else {
- goto error_outofregs;
- }
- ins = DUK_ENC_OP_ABC(op, abc);
- DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!C) abc=%ld (%!I)",
- (unsigned long) ins, (long) comp_ctx->curr_token.start_line,
- (long) duk__get_current_pc(comp_ctx), (long) op, (long) op,
- (long) abc, (duk_instr_t) ins));
- duk__emit(comp_ctx, ins);
- return;
-
- error_outofregs:
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
-}
-
-DUK_LOCAL void duk__emit_extraop_b_c(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b, duk_regconst_t c) {
- DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
- DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
- /* Setting "no shuffle A" is covered by the assert, but it's needed
- * with DUK_USE_SHUFFLE_TORTURE.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
- extraop_flags & 0xff,
- b,
- c);
-}
-
-DUK_LOCAL void duk__emit_extraop_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags, duk_regconst_t b) {
- DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
- DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
- /* Setting "no shuffle A" is covered by the assert, but it's needed
- * with DUK_USE_SHUFFLE_TORTURE.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | (extraop_flags & ~0xff), /* transfer flags */
- extraop_flags & 0xff,
- b,
- 0);
-}
-
-DUK_LOCAL void duk__emit_extraop_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop, duk_regconst_t bc) {
- DUK_ASSERT_DISABLE(extraop >= DUK_BC_EXTRAOP_MIN); /* unsigned */
- DUK_ASSERT(extraop <= DUK_BC_EXTRAOP_MAX);
- /* Setting "no shuffle A" is covered by the assert, but it's needed
- * with DUK_USE_SHUFFLE_TORTURE.
- */
- duk__emit_a_bc(comp_ctx,
- DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- extraop,
- bc);
-}
-
-DUK_LOCAL void duk__emit_extraop_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t extraop_flags) {
- DUK_ASSERT_DISABLE((extraop_flags & 0xff) >= DUK_BC_EXTRAOP_MIN); /* unsigned */
- DUK_ASSERT((extraop_flags & 0xff) <= DUK_BC_EXTRAOP_MAX);
- /* Setting "no shuffle A" is covered by the assert, but it's needed
- * with DUK_USE_SHUFFLE_TORTURE.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_EXTRA | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_B |
- DUK__EMIT_FLAG_NO_SHUFFLE_C | (extraop_flags & ~0xff), /* transfer flags */
- extraop_flags & 0xff,
- 0,
- 0);
-}
-
-DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
- /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
- * would only shuffle once (instead of twice). The current code works
- * though, and has a smaller compiler footprint.
- */
-
- if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) &&
- (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) {
- DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg, (long) val));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS));
- } else {
- duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT;
- duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1);
- DUK_ASSERT(lo >= 0);
- DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld",
- (long) reg, (long) val, (long) hi, (long) lo));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo);
- }
-}
-
-DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
- duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
-}
-
-#if defined(DUK_USE_SHUFFLE_TORTURE)
-/* Used by duk__emit*() calls so that we don't shuffle the loadints that
- * are needed to handle indirect opcodes.
- */
-DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
- duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
-}
-#else
-DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
- /* When torture not enabled, can just use the same helper because
- * 'reg' won't get spilled.
- */
- DUK_ASSERT(reg <= DUK_BC_A_MAX);
- duk__emit_load_int32(comp_ctx, reg, val);
-}
-#endif
-
-DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) {
- duk_int_t curr_pc;
- duk_int_t offset;
-
- curr_pc = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
- offset = (duk_int_t) target_pc - (duk_int_t) curr_pc - 1;
- DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN);
- DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX);
- duk__emit_abc(comp_ctx, DUK_OP_JUMP, (duk_regconst_t) (offset + DUK_BC_JUMP_BIAS));
-}
-
-DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
- duk_int_t ret;
-
- ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */
- duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
- return ret;
-}
-
-/* Insert an empty jump in the middle of code emitted earlier. This is
- * currently needed for compiling for-in.
- */
-DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
-#if defined(DUK_USE_PC2LINE)
- duk_int_t line;
-#endif
- duk_compiler_instr *instr;
- duk_size_t offset;
-
- offset = jump_pc * sizeof(duk_compiler_instr),
- instr = (duk_compiler_instr *) (void *)
- DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr,
- &comp_ctx->curr_func.bw_code,
- offset,
- sizeof(duk_compiler_instr));
-
-#if defined(DUK_USE_PC2LINE)
- line = comp_ctx->curr_token.start_line; /* approximation, close enough */
-#endif
- instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
-#if defined(DUK_USE_PC2LINE)
- instr->line = line;
-#endif
-
- DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
- if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
- goto fail_bc_limit;
- }
- return;
-
- fail_bc_limit:
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
-}
-
-/* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
- * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this).
- */
-DUK_LOCAL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc) {
- duk_compiler_instr *instr;
- duk_int_t offset;
-
- /* allow negative PCs, behave as a no-op */
- if (jump_pc < 0) {
- DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld",
- (long) jump_pc, (long) target_pc));
- return;
- }
- DUK_ASSERT(jump_pc >= 0);
-
- /* XXX: range assert */
- instr = duk__get_instr_ptr(comp_ctx, jump_pc);
- DUK_ASSERT(instr != NULL);
-
- /* XXX: range assert */
- offset = target_pc - jump_pc - 1;
-
- instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS);
- DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld",
- (long) jump_pc, (long) target_pc, (long) offset));
-}
-
-DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
- duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx));
-}
-
-DUK_LOCAL void duk__patch_trycatch(duk_compiler_ctx *comp_ctx, duk_int_t ldconst_pc, duk_int_t trycatch_pc, duk_regconst_t reg_catch, duk_regconst_t const_varname, duk_small_uint_t flags) {
- duk_compiler_instr *instr;
-
- DUK_ASSERT((reg_catch & DUK__CONST_MARKER) == 0);
-
- instr = duk__get_instr_ptr(comp_ctx, ldconst_pc);
- DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST);
- DUK_ASSERT(instr != NULL);
- if (const_varname & DUK__CONST_MARKER) {
- /* Have a catch variable. */
- const_varname = const_varname & (~DUK__CONST_MARKER);
- if (reg_catch > DUK_BC_BC_MAX || const_varname > DUK_BC_BC_MAX) {
- /* Catch attempts to use out-of-range reg/const. Without this
- * check Duktape 0.12.0 could generate invalid code which caused
- * an assert failure on execution. This error is triggered e.g.
- * for functions with a lot of constants and a try-catch statement.
- * Shuffling or opcode semantics change is needed to fix the issue.
- * See: test-bug-trycatch-many-constants.js.
- */
- DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)",
- (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname));
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
- }
- instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname);
- } else {
- /* No catch variable, e.g. a try-finally; replace LDCONST with
- * NOP to avoid a bogus LDCONST.
- */
- instr->ins = DUK_ENC_OP_A(DUK_OP_EXTRA, DUK_EXTRAOP_NOP);
- }
-
- instr = duk__get_instr_ptr(comp_ctx, trycatch_pc);
- DUK_ASSERT(instr != NULL);
- DUK_ASSERT_DISABLE(flags >= DUK_BC_A_MIN);
- DUK_ASSERT(flags <= DUK_BC_A_MAX);
- instr->ins = DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH, flags, reg_catch);
-}
-
-DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
- 0 /*false*/,
- regconst,
- 0 /*unused*/);
-}
-
-DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
- 1 /*true*/,
- regconst,
- 0 /*unused*/);
-}
-
-DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
- duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_INVALID, 0);
-}
-
-/*
- * Peephole optimizer for finished bytecode.
- *
- * Does not remove opcodes; currently only straightens out unconditional
- * jump chains which are generated by several control structures.
- */
-
-DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
- duk_compiler_instr *bc;
- duk_small_uint_t iter;
- duk_int_t i, n;
- duk_int_t count_opt;
-
- bc = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code);
-#if defined(DUK_USE_BUFLEN16)
- /* No need to assert, buffer size maximum is 0xffff. */
-#else
- DUK_ASSERT((duk_size_t) DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr) <= (duk_size_t) DUK_INT_MAX); /* bytecode limits */
-#endif
- n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
-
- for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) {
- count_opt = 0;
-
- for (i = 0; i < n; i++) {
- duk_instr_t ins;
- duk_int_t target_pc1;
- duk_int_t target_pc2;
-
- ins = bc[i].ins;
- if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
- continue;
- }
-
- target_pc1 = i + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
- DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1));
- DUK_ASSERT(target_pc1 >= 0);
- DUK_ASSERT(target_pc1 < n);
-
- /* Note: if target_pc1 == i, we'll optimize a jump to itself.
- * This does not need to be checked for explicitly; the case
- * is rare and max iter breaks us out.
- */
-
- ins = bc[target_pc1].ins;
- if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
- continue;
- }
-
- target_pc2 = target_pc1 + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
-
- DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
- (long) i, (long) target_pc1, (long) target_pc2));
-
- bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS);
-
- count_opt++;
- }
-
- DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt, (long) (iter + 1)));
-
- if (count_opt == 0) {
- break;
- }
- }
-}
-
-/*
- * Intermediate value helpers
- */
-
-#define DUK__ISREG(comp_ctx,x) (((x) & DUK__CONST_MARKER) == 0)
-#define DUK__ISCONST(comp_ctx,x) (((x) & DUK__CONST_MARKER) != 0)
-#define DUK__ISTEMP(comp_ctx,x) (DUK__ISREG((comp_ctx), (x)) && (duk_regconst_t) (x) >= (duk_regconst_t) ((comp_ctx)->curr_func.temp_first))
-#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
-#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
-#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
-#define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx))
-#define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count))
-
-/* Flags for intermediate value coercions. A flag for using a forced reg
- * is not needed, the forced_reg argument suffices and generates better
- * code (it is checked as it is used).
- */
-#define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
-#define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */
-#define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
-
-/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
-
-#if 0 /* enable manually for dumping */
-#define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
-#define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0)
-
-DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) {
- DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
- (long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->valstack_idx)));
-}
-DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
- "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} "
- "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
- (long) x->t, (long) x->op,
- (long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->x1.valstack_idx),
- (long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx,
- duk_get_tval((duk_context *) comp_ctx->thr, x->x2.valstack_idx)));
-}
-#else
-#define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
-#define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
-#endif
-
-DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
- duk_context *ctx = (duk_context *) comp_ctx->thr;
-
- dst->t = src->t;
- dst->regconst = src->regconst;
- duk_copy(ctx, src->valstack_idx, dst->valstack_idx);
-}
-
-DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
- duk_context *ctx = (duk_context *) comp_ctx->thr;
-
- dst->t = src->t;
- dst->op = src->op;
- dst->x1.t = src->x1.t;
- dst->x1.regconst = src->x1.regconst;
- dst->x2.t = src->x2.t;
- dst->x2.regconst = src->x2.regconst;
- duk_copy(ctx, src->x1.valstack_idx, dst->x1.valstack_idx);
- duk_copy(ctx, src->x2.valstack_idx, dst->x2.valstack_idx);
-}
-
-/* XXX: to util */
-DUK_LOCAL duk_bool_t duk__is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
- duk_small_int_t c;
- duk_int32_t t;
-
- c = DUK_FPCLASSIFY(x);
- if (c == DUK_FP_NORMAL || (c == DUK_FP_ZERO && !DUK_SIGNBIT(x))) {
- /* Don't allow negative zero as it will cause trouble with
- * LDINT+LDINTX. But positive zero is OK.
- */
- t = (duk_int32_t) x;
- if ((duk_double_t) t == x) {
- *ival = t;
- return 1;
- }
- }
-
- return 0;
-}
-
-DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
- duk_reg_t res;
-
- res = comp_ctx->curr_func.temp_next;
- comp_ctx->curr_func.temp_next += num;
-
- if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT);
- }
-
- /* maintain highest 'used' temporary, needed to figure out nregs of function */
- if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) {
- comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next;
- }
-
- return res;
-}
-
-DUK_LOCAL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
- return duk__alloctemps(comp_ctx, 1);
-}
-
-DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next) {
- comp_ctx->curr_func.temp_next = temp_next;
- if (temp_next > comp_ctx->curr_func.temp_max) {
- comp_ctx->curr_func.temp_max = temp_next;
- }
-}
-
-/* get const for value at valstack top */
-DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_compiler_func *f = &comp_ctx->curr_func;
- duk_tval *tv1;
- duk_int_t i, n, n_check;
-
- n = (duk_int_t) duk_get_length(ctx, f->consts_idx);
-
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(tv1 != NULL);
-
-#if defined(DUK_USE_FASTINT)
- /* Explicit check for fastint downgrade. */
- DUK_TVAL_CHKFAST_INPLACE(tv1);
-#endif
-
- /* Sanity workaround for handling functions with a large number of
- * constants at least somewhat reasonably. Otherwise checking whether
- * we already have the constant would grow very slow (as it is O(N^2)).
- */
- n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n);
- for (i = 0; i < n_check; i++) {
- duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, f->h_consts, i);
-
- /* Strict equality is NOT enough, because we cannot use the same
- * constant for e.g. +0 and -0.
- */
- if (duk_js_samevalue(tv1, tv2)) {
- DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
- (duk_tval *) tv1, (long) i));
- duk_pop(ctx);
- return (duk_regconst_t) (i | DUK__CONST_MARKER);
- }
- }
-
- if (n > DUK__MAX_CONSTS) {
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT);
- }
-
- DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
- (duk_tval *) tv1, (long) n));
- (void) duk_put_prop_index(ctx, f->consts_idx, n); /* invalidates tv1, tv2 */
- return (duk_regconst_t) (n | DUK__CONST_MARKER);
-}
-
-/* Get the value represented by an duk_ispec to a register or constant.
- * The caller can control the result by indicating whether or not:
- *
- * (1) a constant is allowed (sometimes the caller needs the result to
- * be in a register)
- *
- * (2) a temporary register is required (usually when caller requires
- * the register to be safely mutable; normally either a bound
- * register or a temporary register are both OK)
- *
- * (3) a forced register target needs to be used
- *
- * Bytecode may be emitted to generate the necessary value. The return
- * value is either a register or a constant.
- */
-
-DUK_LOCAL
-duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
- duk_ispec *x,
- duk_reg_t forced_reg,
- duk_small_uint_t flags) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
-
- DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
- "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
- (long) x->t,
- (long) x->regconst,
- (duk_tval *) duk_get_tval(ctx, x->valstack_idx),
- (long) forced_reg,
- (unsigned long) flags,
- (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
- (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
- (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
-
- switch (x->t) {
- case DUK_ISPEC_VALUE: {
- duk_tval *tv;
-
- tv = DUK_GET_TVAL_POSIDX(ctx, x->valstack_idx);
- DUK_ASSERT(tv != NULL);
-
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED: {
- /* Note: although there is no 'undefined' literal, undefined
- * values can occur during compilation as a result of e.g.
- * the 'void' operator.
- */
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDUNDEF, (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
- }
- case DUK_TAG_NULL: {
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_extraop_bc(comp_ctx, DUK_EXTRAOP_LDNULL, (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
- }
- case DUK_TAG_BOOLEAN: {
- duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_extraop_bc(comp_ctx,
- (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_EXTRAOP_LDTRUE : DUK_EXTRAOP_LDFALSE),
- (duk_regconst_t) dest);
- return (duk_regconst_t) dest;
- }
- case DUK_TAG_POINTER: {
- DUK_UNREACHABLE();
- break;
- }
- case DUK_TAG_STRING: {
- duk_hstring *h;
- duk_reg_t dest;
- duk_regconst_t constidx;
-
- h = DUK_TVAL_GET_STRING(tv);
- DUK_UNREF(h);
- DUK_ASSERT(h != NULL);
-
-#if 0 /* XXX: to be implemented? */
- /* Use special opcodes to load short strings */
- if (DUK_HSTRING_GET_BYTELEN(h) <= 2) {
- /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */
- } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) {
- /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
- }
-#endif
- duk_dup(ctx, x->valstack_idx);
- constidx = duk__getconst(comp_ctx);
-
- if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
- return constidx;
- }
-
- dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
- return (duk_regconst_t) dest;
- }
- case DUK_TAG_OBJECT: {
- DUK_UNREACHABLE();
- break;
- }
- case DUK_TAG_BUFFER: {
- DUK_UNREACHABLE();
- break;
- }
- case DUK_TAG_LIGHTFUNC: {
- DUK_UNREACHABLE();
- break;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default: {
- /* number */
- duk_reg_t dest;
- duk_regconst_t constidx;
- duk_double_t dval;
- duk_int32_t ival;
-
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- dval = DUK_TVAL_GET_NUMBER(tv);
-
- if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
- /* A number can be loaded either through a constant, using
- * LDINT, or using LDINT+LDINTX. LDINT is always a size win,
- * LDINT+LDINTX is not if the constant is used multiple times.
- * Currently always prefer LDINT+LDINTX over a double constant.
- */
-
- if (duk__is_whole_get_int32(dval, &ival)) {
- dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_load_int32(comp_ctx, dest, ival);
- return (duk_regconst_t) dest;
- }
- }
-
- duk_dup(ctx, x->valstack_idx);
- constidx = duk__getconst(comp_ctx);
-
- if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
- return constidx;
- } else {
- dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
- return (duk_regconst_t) dest;
- }
- }
- } /* end switch */
- }
- case DUK_ISPEC_REGCONST: {
- if (forced_reg >= 0) {
- if (x->regconst & DUK__CONST_MARKER) {
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst);
- } else if (x->regconst != (duk_regconst_t) forced_reg) {
- duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
- } else {
- ; /* already in correct reg */
- }
- return (duk_regconst_t) forced_reg;
- }
-
- DUK_ASSERT(forced_reg < 0);
- if (x->regconst & DUK__CONST_MARKER) {
- if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
- duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, x->regconst);
- return (duk_regconst_t) dest;
- }
- return x->regconst;
- }
-
- DUK_ASSERT(forced_reg < 0 && !(x->regconst & DUK__CONST_MARKER));
- if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISTEMP(comp_ctx, x->regconst)) {
- duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, (duk_regconst_t) dest, x->regconst);
- return (duk_regconst_t) dest;
- }
- return x->regconst;
- }
- default: {
- break;
- }
- }
-
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- return 0;
-}
-
-DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg) {
- DUK_ASSERT(forced_reg >= 0);
- (void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
-}
-
-/* Coerce an duk_ivalue to a 'plain' value by generating the necessary
- * arithmetic operations, property access, or variable access bytecode.
- * The duk_ivalue argument ('x') is converted into a plain value as a
- * side effect.
- */
-DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
-
- DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
- "forced_reg=%ld",
- (long) x->t, (long) x->op,
- (long) x->x1.t, (long) x->x1.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
- (long) x->x2.t, (long) x->x2.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
- (long) forced_reg));
-
- switch (x->t) {
- case DUK_IVAL_PLAIN: {
- return;
- }
- /* XXX: support unary arithmetic ivalues (useful?) */
- case DUK_IVAL_ARITH:
- case DUK_IVAL_ARITH_EXTRAOP: {
- duk_regconst_t arg1;
- duk_regconst_t arg2;
- duk_reg_t dest;
- duk_tval *tv1;
- duk_tval *tv2;
-
- DUK_DDD(DUK_DDDPRINT("arith to plain conversion"));
-
- /* inline arithmetic check for constant values */
- /* XXX: use the exactly same arithmetic function here as in executor */
- if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
- tv1 = DUK_GET_TVAL_POSIDX(ctx, x->x1.valstack_idx);
- tv2 = DUK_GET_TVAL_POSIDX(ctx, x->x2.valstack_idx);
- DUK_ASSERT(tv1 != NULL);
- DUK_ASSERT(tv2 != NULL);
-
- DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T",
- (duk_tval *) tv1,
- (duk_tval *) tv2));
-
- if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) {
- duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1);
- duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2);
- duk_double_t d3;
- duk_bool_t accept = 1;
-
- DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
- (double) d1, (double) d2, (long) x->op));
- switch (x->op) {
- case DUK_OP_ADD: d3 = d1 + d2; break;
- case DUK_OP_SUB: d3 = d1 - d2; break;
- case DUK_OP_MUL: d3 = d1 * d2; break;
- case DUK_OP_DIV: d3 = d1 / d2; break;
- default: accept = 0; break;
- }
-
- if (accept) {
- duk_double_union du;
- du.d = d3;
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
- d3 = du.d;
-
- x->t = DUK_IVAL_PLAIN;
- DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
- DUK_TVAL_SET_NUMBER(tv1, d3); /* old value is number: no refcount */
- return;
- }
- } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) {
- /* inline string concatenation */
- duk_dup(ctx, x->x1.valstack_idx);
- duk_dup(ctx, x->x2.valstack_idx);
- duk_concat(ctx, 2);
- duk_replace(ctx, x->x1.valstack_idx);
- x->t = DUK_IVAL_PLAIN;
- DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
- return;
- }
- }
-
- arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
- arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
-
- /* If forced reg, use it as destination. Otherwise try to
- * use either coerced ispec if it is a temporary.
- *
- * When using extraops, avoid reusing arg2 as dest because that
- * would lead to an LDREG shuffle below. We still can't guarantee
- * dest != arg2 because we may have a forced_reg.
- */
- if (forced_reg >= 0) {
- dest = forced_reg;
- } else if (DUK__ISTEMP(comp_ctx, arg1)) {
- dest = (duk_reg_t) arg1;
- } else if (DUK__ISTEMP(comp_ctx, arg2) && x->t != DUK_IVAL_ARITH_EXTRAOP) {
- dest = (duk_reg_t) arg2;
- } else {
- dest = DUK__ALLOCTEMP(comp_ctx);
- }
-
- /* Extraop arithmetic opcodes must have destination same as
- * first source. If second source matches destination we need
- * a temporary register to avoid clobbering the second source.
- *
- * XXX: change calling code to avoid this situation in most cases.
- */
-
- if (x->t == DUK_IVAL_ARITH_EXTRAOP) {
- if (!(DUK__ISREG(comp_ctx, arg1) && (duk_reg_t) arg1 == dest)) {
- if (DUK__ISREG(comp_ctx, arg2) && (duk_reg_t) arg2 == dest) {
- /* arg2 would be clobbered so reassign it to a temp. */
- duk_reg_t tempreg;
- tempreg = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, tempreg, arg2);
- arg2 = tempreg;
- }
-
- if (DUK__ISREG(comp_ctx, arg1)) {
- duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, dest, arg1);
- } else {
- DUK_ASSERT(DUK__ISCONST(comp_ctx, arg1));
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, dest, arg1);
- }
- }
-
- /* Note: special DUK__EMIT_FLAG_B_IS_TARGETSOURCE
- * used to indicate that B is both a source and a
- * target register. When shuffled, it needs to be
- * both input and output shuffled.
- */
- DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
- duk__emit_extraop_b_c(comp_ctx,
- x->op | DUK__EMIT_FLAG_B_IS_TARGET |
- DUK__EMIT_FLAG_B_IS_TARGETSOURCE,
- (duk_regconst_t) dest,
- (duk_regconst_t) arg2);
-
- } else {
- DUK_ASSERT(DUK__ISREG(comp_ctx, dest));
- duk__emit_a_b_c(comp_ctx, x->op, (duk_regconst_t) dest, arg1, arg2);
- }
-
- x->t = DUK_IVAL_PLAIN;
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) dest;
- return;
- }
- case DUK_IVAL_PROP: {
- /* XXX: very similar to DUK_IVAL_ARITH - merge? */
- duk_regconst_t arg1;
- duk_regconst_t arg2;
- duk_reg_t dest;
-
- /* Need a short reg/const, does not have to be a mutable temp. */
- arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
- arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
-
- /* Pick a destination register. If either base value or key
- * happens to be a temp value, reuse it as the destination.
- *
- * XXX: The temp must be a "mutable" one, i.e. such that no
- * other expression is using it anymore. Here this should be
- * the case because the value of a property access expression
- * is neither the base nor the key, but the lookup result.
- */
-
- if (forced_reg >= 0) {
- dest = forced_reg;
- } else if (DUK__ISTEMP(comp_ctx, arg1)) {
- dest = (duk_reg_t) arg1;
- } else if (DUK__ISTEMP(comp_ctx, arg2)) {
- dest = (duk_reg_t) arg2;
- } else {
- dest = DUK__ALLOCTEMP(comp_ctx);
- }
-
- duk__emit_a_b_c(comp_ctx, DUK_OP_GETPROP, (duk_regconst_t) dest, arg1, arg2);
-
- x->t = DUK_IVAL_PLAIN;
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) dest;
- return;
- }
- case DUK_IVAL_VAR: {
- /* x1 must be a string */
- duk_reg_t dest;
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
-
- duk_dup(ctx, x->x1.valstack_idx);
- if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- x->t = DUK_IVAL_PLAIN;
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) reg_varbind;
- } else {
- dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
- duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, (duk_regconst_t) dest, rc_varname);
- x->t = DUK_IVAL_PLAIN;
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = (duk_regconst_t) dest;
- }
- return;
- }
- case DUK_IVAL_NONE:
- default: {
- break;
- }
- }
-
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- return;
-}
-
-/* evaluate to plain value, no forced register (temp/bound reg both ok) */
-DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
-}
-
-/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
-DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- duk_reg_t temp;
-
- /* If duk__ivalue_toplain_raw() allocates a temp, forget it and
- * restore next temp state.
- */
- temp = DUK__GETTEMP(comp_ctx);
- duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
- DUK__SETTEMP(comp_ctx, temp);
-}
-
-/* Coerce an duk_ivalue to a register or constant; result register may
- * be a temp or a bound register.
- *
- * The duk_ivalue argument ('x') is converted into a regconst as a
- * side effect.
- */
-DUK_LOCAL
-duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
- duk_ivalue *x,
- duk_reg_t forced_reg,
- duk_small_uint_t flags) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_regconst_t reg;
- DUK_UNREF(thr);
- DUK_UNREF(ctx);
-
- DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
- "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
- (long) x->t, (long) x->op,
- (long) x->x1.t, (long) x->x1.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
- (long) x->x2.t, (long) x->x2.regconst,
- (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
- (long) forced_reg,
- (unsigned long) flags,
- (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
- (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
- (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
-
- /* first coerce to a plain value */
- duk__ivalue_toplain_raw(comp_ctx, x, forced_reg);
- DUK_ASSERT(x->t == DUK_IVAL_PLAIN);
-
- /* then to a register */
- reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
- x->x1.t = DUK_ISPEC_REGCONST;
- x->x1.regconst = reg;
-
- return reg;
-}
-
-DUK_LOCAL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
-}
-
-#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
-}
-#endif
-
-DUK_LOCAL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg) {
- DUK_ASSERT(forced_reg >= 0);
- (void) duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
-}
-
-DUK_LOCAL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
-}
-
-DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
- return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
-}
-
-/* The issues below can be solved with better flags */
-
-/* XXX: many operations actually want toforcedtemp() -- brand new temp? */
-/* XXX: need a toplain_ignore() which will only coerce a value to a temp
- * register if it might have a side effect. Side-effect free values do not
- * need to be coerced.
- */
-
-/*
- * Identifier handling
- */
-
-DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_hstring *h_varname;
- duk_reg_t ret;
-
- DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /*
- * Special name handling
- */
-
- h_varname = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_varname != NULL);
-
- if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
- DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
- comp_ctx->curr_func.id_access_arguments = 1;
- }
-
- /*
- * Inside one or more 'with' statements fall back to slow path always.
- * (See e.g. test-stmt-with.js.)
- */
-
- if (comp_ctx->curr_func.with_depth > 0) {
- DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
- goto slow_path;
- }
-
- /*
- * Any catch bindings ("catch (e)") also affect identifier binding.
- *
- * Currently, the varmap is modified for the duration of the catch
- * clause to ensure any identifier accesses with the catch variable
- * name will use slow path.
- */
-
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- if (duk_is_number(ctx, -1)) {
- ret = duk_to_int(ctx, -1);
- duk_pop(ctx);
- } else {
- duk_pop(ctx);
- goto slow_path;
- }
-
- DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret));
- return ret;
-
- slow_path:
- DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path"));
-
- comp_ctx->curr_func.id_access_slow = 1;
- return (duk_reg_t) -1;
-}
-
-/* Lookup an identifier name in the current varmap, indicating whether the
- * identifier is register-bound and if not, allocating a constant for the
- * identifier name. Returns 1 if register-bound, 0 otherwise. Caller can
- * also check (out_reg_varbind >= 0) to check whether or not identifier is
- * register bound. The caller must NOT use out_rc_varname at all unless
- * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
- * is unsigned and doesn't have a "unused" / none value.
- */
-DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- /* [ ... varname ] */
-
- duk_dup_top(ctx);
- reg_varbind = duk__lookup_active_register_binding(comp_ctx);
-
- if (reg_varbind >= 0) {
- *out_reg_varbind = reg_varbind;
- *out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
- duk_pop(ctx);
- return 1;
- } else {
- rc_varname = duk__getconst(comp_ctx);
- *out_reg_varbind = -1;
- *out_rc_varname = rc_varname;
- return 0;
- }
-}
-
-/*
- * Label handling
- *
- * Labels are initially added with flags prohibiting both break and continue.
- * When the statement type is finally uncovered (after potentially multiple
- * labels), all the labels are updated to allow/prohibit break and continue.
- */
-
-DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_size_t n;
- duk_size_t new_size;
- duk_uint8_t *p;
- duk_labelinfo *li_start, *li;
-
- /* Duplicate (shadowing) labels are not allowed, except for the empty
- * labels (which are used as default labels for switch and iteration
- * statements).
- *
- * We could also allow shadowing of non-empty pending labels without any
- * other issues than breaking the required label shadowing requirements
- * of the E5 specification, see Section 12.12.
- */
-
- p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
- li_start = (duk_labelinfo *) (void *) p;
- li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
- n = (duk_size_t) (li - li_start);
-
- while (li > li_start) {
- li--;
-
- if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL);
- }
- }
-
- duk_push_hstring(ctx, h_label);
- DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */
- (void) duk_put_prop_index(ctx, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
-
- new_size = (n + 1) * sizeof(duk_labelinfo);
- duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
- /* XXX: spare handling, slow now */
-
- /* relookup after possible realloc */
- p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
- li_start = (duk_labelinfo *) (void *) p;
- DUK_UNREF(li_start); /* silence scan-build warning */
- li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
- li--;
-
- /* Labels can be used for iteration statements but also for other statements,
- * in particular a label can be used for a block statement. All cases of a
- * named label accept a 'break' so that flag is set here. Iteration statements
- * also allow 'continue', so that flag is updated when we figure out the
- * statement type.
- */
-
- li->flags = DUK_LABEL_FLAG_ALLOW_BREAK;
- li->label_id = label_id;
- li->h_label = h_label;
- li->catch_depth = comp_ctx->curr_func.catch_depth; /* catch depth from current func */
- li->pc_label = pc_label;
-
- DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld",
- (unsigned long) li->flags, (long) li->label_id, (duk_heaphdr *) li->h_label,
- (long) li->catch_depth, (long) li->pc_label));
-}
-
-/* Update all labels with matching label_id. */
-DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags) {
- duk_uint8_t *p;
- duk_labelinfo *li_start, *li;
-
- p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx->thr->heap, comp_ctx->curr_func.h_labelinfos);
- li_start = (duk_labelinfo *) (void *) p;
- li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
-
- /* Match labels starting from latest; once label_id no longer matches, we can
- * safely exit without checking the rest of the labels (only the topmost labels
- * are ever updated).
- */
- while (li > li_start) {
- li--;
-
- if (li->label_id != label_id) {
- break;
- }
-
- DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld",
- (void *) li, (long) label_id, (long) flags));
-
- li->flags = flags;
- }
-}
-
-/* Lookup active label information. Break/continue distinction is necessary to handle switch
- * statement related labels correctly: a switch will only catch a 'break', not a 'continue'.
- *
- * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled
- * iteration and switch statements) can. A break will match the closest unlabelled or labelled
- * statement. A continue will match the closest unlabelled or labelled iteration statement. It is
- * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot
- * be duplicated, the continue cannot match any valid label outside the switch.
- *
- * A side effect of these rules is that a LABEL statement related to a switch should never actually
- * catch a continue abrupt completion at run-time. Hence an INVALID opcode can be placed in the
- * continue slot of the switch's LABEL statement.
- */
-
-/* XXX: awkward, especially the bunch of separate output values -> output struct? */
-DUK_LOCAL void duk__lookup_active_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_bool_t is_break, duk_int_t *out_label_id, duk_int_t *out_label_catch_depth, duk_int_t *out_label_pc, duk_bool_t *out_is_closest) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_uint8_t *p;
- duk_labelinfo *li_start, *li_end, *li;
- duk_bool_t match = 0;
-
- DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
- (duk_heaphdr *) h_label, (long) is_break));
-
- DUK_UNREF(ctx);
-
- p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
- li_start = (duk_labelinfo *) (void *) p;
- li_end = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
- li = li_end;
-
- /* Match labels starting from latest label because there can be duplicate empty
- * labels in the label set.
- */
- while (li > li_start) {
- li--;
-
- if (li->h_label != h_label) {
- DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O",
- (long) (li - li_start),
- (duk_heaphdr *) li->h_label,
- (duk_heaphdr *) h_label));
- continue;
- }
-
- DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)",
- (long) (li - li_start), (duk_heaphdr *) h_label));
-
- /* currently all labels accept a break, so no explicit check for it now */
- DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK);
-
- if (is_break) {
- /* break matches always */
- match = 1;
- break;
- } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) {
- /* iteration statements allow continue */
- match = 1;
- break;
- } else {
- /* continue matched this label -- we can only continue if this is the empty
- * label, for which duplication is allowed, and thus there is hope of
- * finding a match deeper in the label stack.
- */
- if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
- } else {
- DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not "
- "allow a continue -> continue lookup deeper in label stack"));
- }
- }
- }
- /* XXX: match flag is awkward, rework */
- if (!match) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
- }
-
- DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld",
- (duk_heaphdr *) h_label, (long) li->label_id,
- (long) li->catch_depth, (long) li->pc_label));
-
- *out_label_id = li->label_id;
- *out_label_catch_depth = li->catch_depth;
- *out_label_pc = li->pc_label;
- *out_is_closest = (li == li_end - 1);
-}
-
-DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_size_t new_size;
-
- /* XXX: duk_set_length */
- new_size = sizeof(duk_labelinfo) * (duk_size_t) len;
- duk_push_int(ctx, len);
- duk_put_prop_stridx(ctx, comp_ctx->curr_func.labelnames_idx, DUK_STRIDX_LENGTH);
- duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
-}
-
-/*
- * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
- *
- * - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal)
- * - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator)
- * - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token
- */
-
-/* object literal key tracking flags */
-#define DUK__OBJ_LIT_KEY_PLAIN (1 << 0) /* key encountered as a plain property */
-#define DUK__OBJ_LIT_KEY_GET (1 << 1) /* key encountered as a getter */
-#define DUK__OBJ_LIT_KEY_SET (1 << 2) /* key encountered as a setter */
-
-DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_hthread *thr = comp_ctx->thr;
- duk_reg_t reg_obj; /* result reg */
- duk_reg_t reg_temp; /* temp reg */
- duk_reg_t temp_start; /* temp reg value for start of loop */
- duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */
- duk_small_uint_t num_values; /* number of values in current MPUTARR set */
- duk_uarridx_t curr_idx; /* current (next) array index */
- duk_uarridx_t start_idx; /* start array index of current MPUTARR set */
- duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */
- duk_bool_t require_comma; /* next loop requires a comma */
-
- /* DUK_TOK_LBRACKET already eaten, current token is right after that */
- DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
-
- max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */
-
- reg_obj = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_NEWARR | DUK__EMIT_FLAG_B_IS_TARGET,
- reg_obj,
- 0); /* XXX: patch initial size afterwards? */
- temp_start = DUK__GETTEMP(comp_ctx);
-
- /*
- * Emit initializers in sets of maximum max_init_values.
- * Corner cases such as single value initializers do not have
- * special handling now.
- *
- * Elided elements must not be emitted as 'undefined' values,
- * because such values would be enumerable (which is incorrect).
- * Also note that trailing elisions must be reflected in the
- * length of the final array but cause no elements to be actually
- * inserted.
- */
-
- curr_idx = 0;
- init_idx = 0; /* tracks maximum initialized index + 1 */
- start_idx = 0;
- require_comma = 0;
-
- for (;;) {
- num_values = 0;
- DUK__SETTEMP(comp_ctx, temp_start);
-
- if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
- break;
- }
-
- for (;;) {
- if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
- /* the outer loop will recheck and exit */
- break;
- }
-
- /* comma check */
- if (require_comma) {
- if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
- /* comma after a value, expected */
- duk__advance(comp_ctx);
- require_comma = 0;
- continue;
- } else {
- goto syntax_error;
- }
- } else {
- if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
- /* elision - flush */
- curr_idx++;
- duk__advance(comp_ctx);
- /* if num_values > 0, MPUTARR emitted by outer loop after break */
- break;
- }
- }
- /* else an array initializer element */
-
- /* initial index */
- if (num_values == 0) {
- start_idx = curr_idx;
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_load_int32(comp_ctx, reg_temp, (duk_int32_t) start_idx);
- }
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
- DUK__SETTEMP(comp_ctx, reg_temp);
- duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
- DUK__SETTEMP(comp_ctx, reg_temp + 1);
-
- num_values++;
- curr_idx++;
- require_comma = 1;
-
- if (num_values >= max_init_values) {
- /* MPUTARR emitted by outer loop */
- break;
- }
- }
-
- if (num_values > 0) {
- /* - A is a source register (it's not a write target, but used
- * to identify the target object) but can be shuffled.
- * - B cannot be shuffled normally because it identifies a range
- * of registers, the emitter has special handling for this
- * (the "no shuffle" flag must not be set).
- * - C is a non-register number and cannot be shuffled, but
- * never needs to be.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_MPUTARR |
- DUK__EMIT_FLAG_NO_SHUFFLE_C |
- DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_obj,
- (duk_regconst_t) temp_start,
- (duk_regconst_t) num_values);
- init_idx = start_idx + num_values;
-
- /* num_values and temp_start reset at top of outer loop */
- }
- }
-
- DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
- duk__advance(comp_ctx);
-
- DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld",
- (long) curr_idx, (long) init_idx));
-
- /* trailing elisions? */
- if (curr_idx > init_idx) {
- /* yes, must set array length explicitly */
- DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length"));
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_SETALEN,
- (duk_regconst_t) reg_obj,
- (duk_regconst_t) reg_temp);
- }
-
- DUK__SETTEMP(comp_ctx, temp_start);
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_obj;
- return;
-
- syntax_error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL);
-}
-
-/* duplicate/invalid key checks; returns 1 if syntax error */
-DUK_LOCAL duk_bool_t duk__nud_object_literal_key_check(duk_compiler_ctx *comp_ctx, duk_small_uint_t new_key_flags) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_t key_flags;
-
- /* [ ... key_obj key ] */
-
- DUK_ASSERT(duk_is_string(ctx, -1));
-
- /*
- * 'key_obj' tracks keys encountered so far by associating an
- * integer with flags with already encountered keys. The checks
- * below implement E5 Section 11.1.5, step 4 for production:
- *
- * PropertyNameAndValueList: PropertyNameAndValueList , PropertyAssignment
- */
-
- duk_dup(ctx, -1); /* [ ... key_obj key key ] */
- duk_get_prop(ctx, -3); /* [ ... key_obj key val ] */
- key_flags = duk_to_int(ctx, -1);
- duk_pop(ctx); /* [ ... key_obj key ] */
-
- if (new_key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
- if ((key_flags & DUK__OBJ_LIT_KEY_PLAIN) && comp_ctx->curr_func.is_strict) {
- /* step 4.a */
- DUK_DDD(DUK_DDDPRINT("duplicate key: plain key appears twice in strict mode"));
- return 1;
- }
- if (key_flags & (DUK__OBJ_LIT_KEY_GET | DUK__OBJ_LIT_KEY_SET)) {
- /* step 4.c */
- DUK_DDD(DUK_DDDPRINT("duplicate key: plain key encountered after setter/getter"));
- return 1;
- }
- } else {
- if (key_flags & DUK__OBJ_LIT_KEY_PLAIN) {
- /* step 4.b */
- DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered after plain key"));
- return 1;
- }
- if (key_flags & new_key_flags) {
- /* step 4.d */
- DUK_DDD(DUK_DDDPRINT("duplicate key: getter/setter encountered twice"));
- return 1;
- }
- }
-
- new_key_flags |= key_flags;
- DUK_DDD(DUK_DDDPRINT("setting/updating key %!T flags: 0x%08lx -> 0x%08lx",
- (duk_tval *) duk_get_tval(ctx, -1),
- (unsigned long) key_flags,
- (unsigned long) new_key_flags));
- duk_dup(ctx, -1);
- duk_push_int(ctx, new_key_flags); /* [ ... key_obj key key flags ] */
- duk_put_prop(ctx, -4); /* [ ... key_obj key ] */
-
- return 0;
-}
-
-DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_reg_t reg_obj; /* result reg */
- duk_reg_t reg_key; /* temp reg for key literal */
- duk_reg_t reg_temp; /* temp reg */
- duk_reg_t temp_start; /* temp reg value for start of loop */
- duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */
- duk_small_uint_t num_pairs; /* number of pairs in current MPUTOBJ set */
- duk_bool_t first; /* first value: comma must not precede the value */
- duk_bool_t is_set, is_get; /* temps */
-
- DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
-
- max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */
-
- reg_obj = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_NEWOBJ | DUK__EMIT_FLAG_B_IS_TARGET,
- reg_obj,
- 0); /* XXX: patch initial size afterwards? */
- temp_start = DUK__GETTEMP(comp_ctx);
-
- /* temp object for tracking / detecting duplicate keys */
- duk_push_object(ctx);
-
- /*
- * Emit initializers in sets of maximum max_init_pairs keys.
- * Setter/getter is handled separately and terminates the
- * current set of initializer values. Corner cases such as
- * single value initializers do not have special handling now.
- */
-
- first = 1;
- for (;;) {
- num_pairs = 0;
- DUK__SETTEMP(comp_ctx, temp_start);
-
- if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
- break;
- }
-
- for (;;) {
- /*
- * Three possible element formats:
- * 1) PropertyName : AssignmentExpression
- * 2) get PropertyName () { FunctionBody }
- * 3) set PropertyName ( PropertySetParameterList ) { FunctionBody }
- *
- * PropertyName can be IdentifierName (includes reserved words), a string
- * literal, or a number literal. Note that IdentifierName allows 'get' and
- * 'set' too, so we need to look ahead to the next token to distinguish:
- *
- * { get : 1 }
- *
- * and
- *
- * { get foo() { return 1 } }
- * { get get() { return 1 } } // 'get' as getter propertyname
- *
- * Finally, a trailing comma is allowed.
- *
- * Key name is coerced to string at compile time (and ends up as a
- * a string constant) even for numeric keys (e.g. "{1:'foo'}").
- * These could be emitted using e.g. LDINT, but that seems hardly
- * worth the effort and would increase code size.
- */
-
- DUK_DDD(DUK_DDDPRINT("object literal inner loop, curr_token->t = %ld",
- (long) comp_ctx->curr_token.t));
-
- if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
- /* the outer loop will recheck and exit */
- break;
- }
- if (num_pairs >= max_init_pairs) {
- /* MPUTOBJ emitted by outer loop */
- break;
- }
-
- if (first) {
- first = 0;
- } else {
- if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
- goto syntax_error;
- }
- duk__advance(comp_ctx);
- if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
- /* trailing comma followed by rcurly */
- break;
- }
- }
-
- /* advance to get one step of lookup */
- duk__advance(comp_ctx);
-
- /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
- * currently treats them always like ordinary identifiers (DUK_TOK_GET
- * and DUK_TOK_SET are unused). They need to be detected based on the
- * identifier string content.
- */
-
- is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
- comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
- is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
- comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
- if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
- /* getter/setter */
- duk_int_t fnum;
-
- if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
- comp_ctx->curr_token.t_nores == DUK_TOK_STRING) {
- /* same handling for identifiers and strings */
- DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
- duk_push_hstring(ctx, comp_ctx->curr_token.str1);
- } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
- duk_push_number(ctx, comp_ctx->curr_token.num);
- duk_to_string(ctx, -1);
- } else {
- goto syntax_error;
- }
-
- DUK_ASSERT(duk_is_string(ctx, -1));
- if (duk__nud_object_literal_key_check(comp_ctx,
- (is_get ? DUK__OBJ_LIT_KEY_GET : DUK__OBJ_LIT_KEY_SET))) {
- goto syntax_error;
- }
- reg_key = duk__getconst(comp_ctx);
-
- if (num_pairs > 0) {
- /* - A is a source register (it's not a write target, but used
- * to identify the target object) but can be shuffled.
- * - B cannot be shuffled normally because it identifies a range
- * of registers, the emitter has special handling for this
- * (the "no shuffle" flag must not be set).
- * - C is a non-register number and cannot be shuffled, but
- * never needs to be.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_MPUTOBJ |
- DUK__EMIT_FLAG_NO_SHUFFLE_C |
- DUK__EMIT_FLAG_A_IS_SOURCE,
- reg_obj,
- temp_start,
- num_pairs);
- num_pairs = 0;
- DUK__SETTEMP(comp_ctx, temp_start);
- }
-
- /* curr_token = get/set name */
- fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 1 /*is_setget*/);
-
- DUK_ASSERT(DUK__GETTEMP(comp_ctx) == temp_start);
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_LDCONST,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_key);
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_CLOSURE,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) fnum);
-
- /* Slot C is used in a non-standard fashion (range of regs),
- * emitter code has special handling for it (must not set the
- * "no shuffle" flag).
- */
- duk__emit_extraop_b_c(comp_ctx,
- (is_get ? DUK_EXTRAOP_INITGET : DUK_EXTRAOP_INITSET),
- reg_obj,
- temp_start); /* temp_start+0 = key, temp_start+1 = closure */
-
- DUK__SETTEMP(comp_ctx, temp_start);
- } else {
- /* normal key/value */
- if (comp_ctx->prev_token.t_nores == DUK_TOK_IDENTIFIER ||
- comp_ctx->prev_token.t_nores == DUK_TOK_STRING) {
- /* same handling for identifiers and strings */
- DUK_ASSERT(comp_ctx->prev_token.str1 != NULL);
- duk_push_hstring(ctx, comp_ctx->prev_token.str1);
- } else if (comp_ctx->prev_token.t == DUK_TOK_NUMBER) {
- duk_push_number(ctx, comp_ctx->prev_token.num);
- duk_to_string(ctx, -1);
- } else {
- goto syntax_error;
- }
-
- DUK_ASSERT(duk_is_string(ctx, -1));
- if (duk__nud_object_literal_key_check(comp_ctx, DUK__OBJ_LIT_KEY_PLAIN)) {
- goto syntax_error;
- }
- reg_key = duk__getconst(comp_ctx);
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_LDCONST,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_key);
- duk__advance_expect(comp_ctx, DUK_TOK_COLON);
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
- DUK__SETTEMP(comp_ctx, reg_temp);
- duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
- DUK__SETTEMP(comp_ctx, reg_temp + 1);
-
- num_pairs++;
- }
- }
-
- if (num_pairs > 0) {
- /* See MPUTOBJ comments above. */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_MPUTOBJ |
- DUK__EMIT_FLAG_NO_SHUFFLE_C |
- DUK__EMIT_FLAG_A_IS_SOURCE,
- reg_obj,
- temp_start,
- num_pairs);
-
- /* num_pairs and temp_start reset at top of outer loop */
- }
- }
-
- DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
- duk__advance(comp_ctx);
-
- DUK__SETTEMP(comp_ctx, temp_start);
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_obj;
-
- DUK_DDD(DUK_DDDPRINT("final tracking object: %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_pop(ctx);
- return;
-
- syntax_error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL);
-}
-
-/* Parse argument list. Arguments are written to temps starting from
- * "next temp". Returns number of arguments parsed. Expects left paren
- * to be already eaten, and eats the right paren before returning.
- */
-DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_int_t nargs = 0;
- duk_reg_t reg_temp;
-
- /* Note: expect that caller has already eaten the left paren */
-
- DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld",
- (long) comp_ctx->prev_token.t, (long) comp_ctx->curr_token.t));
-
- for (;;) {
- if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
- break;
- }
- if (nargs > 0) {
- duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
- }
-
- /* We want the argument expression value to go to "next temp"
- * without additional moves. That should almost always be the
- * case, but we double check after expression parsing.
- *
- * This is not the cleanest possible approach.
- */
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx); /* bump up "allocated" reg count, just in case */
- DUK__SETTEMP(comp_ctx, reg_temp);
-
- /* binding power must be high enough to NOT allow comma expressions directly */
- duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp); /* always allow 'in', coerce to 'tr' just in case */
-
- DUK__SETTEMP(comp_ctx, reg_temp + 1);
- nargs++;
-
- DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs, (long) reg_temp));
- }
-
- /* eat the right paren */
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
-
- DUK_DDD(DUK_DDDPRINT("end parsing arguments"));
-
- return nargs;
-}
-
-DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
- /* empty expressions can be detected conveniently with nud/led counts */
- return (comp_ctx->curr_func.nud_count == 0) &&
- (comp_ctx->curr_func.led_count == 0);
-}
-
-DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_token *tk;
- duk_reg_t temp_at_entry;
- duk_small_int_t tok;
- duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
-
- /*
- * ctx->prev_token token to process with duk__expr_nud()
- * ctx->curr_token updated by caller
- *
- * Note: the token in the switch below has already been eaten.
- */
-
- temp_at_entry = DUK__GETTEMP(comp_ctx);
-
- comp_ctx->curr_func.nud_count++;
-
- tk = &comp_ctx->prev_token;
- tok = tk->t;
- res->t = DUK_IVAL_NONE;
-
- DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
- (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
-
- switch (tok) {
-
- /* PRIMARY EXPRESSIONS */
-
- case DUK_TOK_THIS: {
- duk_reg_t reg_temp;
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LDTHIS,
- (duk_regconst_t) reg_temp);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- return;
- }
- case DUK_TOK_IDENTIFIER: {
- res->t = DUK_IVAL_VAR;
- res->x1.t = DUK_ISPEC_VALUE;
- duk_push_hstring(ctx, tk->str1);
- duk_replace(ctx, res->x1.valstack_idx);
- return;
- }
- case DUK_TOK_NULL: {
- duk_push_null(ctx);
- goto plain_value;
- }
- case DUK_TOK_TRUE: {
- duk_push_true(ctx);
- goto plain_value;
- }
- case DUK_TOK_FALSE: {
- duk_push_false(ctx);
- goto plain_value;
- }
- case DUK_TOK_NUMBER: {
- duk_push_number(ctx, tk->num);
- goto plain_value;
- }
- case DUK_TOK_STRING: {
- DUK_ASSERT(tk->str1 != NULL);
- duk_push_hstring(ctx, tk->str1);
- goto plain_value;
- }
- case DUK_TOK_REGEXP: {
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_reg_t reg_temp;
- duk_regconst_t rc_re_bytecode; /* const */
- duk_regconst_t rc_re_source; /* const */
-
- DUK_ASSERT(tk->str1 != NULL);
- DUK_ASSERT(tk->str2 != NULL);
-
- DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O",
- (duk_heaphdr *) tk->str1,
- (duk_heaphdr *) tk->str2));
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk_push_hstring(ctx, tk->str1);
- duk_push_hstring(ctx, tk->str2);
-
- /* [ ... pattern flags ] */
-
- duk_regexp_compile(thr);
-
- /* [ ... escaped_source bytecode ] */
-
- rc_re_bytecode = duk__getconst(comp_ctx);
- rc_re_source = duk__getconst(comp_ctx);
-
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_REGEXP,
- (duk_regconst_t) reg_temp /*a*/,
- rc_re_bytecode /*b*/,
- rc_re_source /*c*/);
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- return;
-#else /* DUK_USE_REGEXP_SUPPORT */
- goto syntax_error;
-#endif /* DUK_USE_REGEXP_SUPPORT */
- }
- case DUK_TOK_LBRACKET: {
- DUK_DDD(DUK_DDDPRINT("parsing array literal"));
- duk__nud_array_literal(comp_ctx, res);
- return;
- }
- case DUK_TOK_LCURLY: {
- DUK_DDD(DUK_DDDPRINT("parsing object literal"));
- duk__nud_object_literal(comp_ctx, res);
- return;
- }
- case DUK_TOK_LPAREN: {
- duk_bool_t prev_allow_in;
-
- comp_ctx->curr_func.paren_level++;
- prev_allow_in = comp_ctx->curr_func.allow_in;
- comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */
-
- duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */
-
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
- comp_ctx->curr_func.allow_in = prev_allow_in;
- comp_ctx->curr_func.paren_level--;
- return;
- }
-
- /* MEMBER/NEW/CALL EXPRESSIONS */
-
- case DUK_TOK_NEW: {
- /*
- * Parsing an expression starting with 'new' is tricky because
- * there are multiple possible productions deriving from
- * LeftHandSideExpression which begin with 'new'.
- *
- * We currently resort to one-token lookahead to distinguish the
- * cases. Hopefully this is correct. The binding power must be
- * such that parsing ends at an LPAREN (CallExpression) but not at
- * a PERIOD or LBRACKET (MemberExpression).
- *
- * See doc/compiler.rst for discussion on the parsing approach,
- * and testcases/test-dev-new.js for a bunch of documented tests.
- */
-
- duk_reg_t reg_target;
- duk_int_t nargs;
-
- DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
-
- reg_target = DUK__ALLOCTEMP(comp_ctx);
- duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
- DUK__SETTEMP(comp_ctx, reg_target + 1);
-
- if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
- /* 'new' MemberExpression Arguments */
- DUK_DDD(DUK_DDDPRINT("new expression has argument list"));
- duk__advance(comp_ctx);
- nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp", reg_target + 1 */
- /* right paren eaten */
- } else {
- /* 'new' MemberExpression */
- DUK_DDD(DUK_DDDPRINT("new expression has no argument list"));
- nargs = 0;
- }
-
- /* Opcode slot C is used in a non-standard way, so shuffling
- * is not allowed.
- */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_NEW | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
- 0 /*unused*/,
- reg_target /*target*/,
- nargs /*num_args*/);
-
- DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_target;
- return;
- }
-
- /* FUNCTION EXPRESSIONS */
-
- case DUK_TOK_FUNCTION: {
- /* Function expression. Note that any statement beginning with 'function'
- * is handled by the statement parser as a function declaration, or a
- * non-standard function expression/statement (or a SyntaxError). We only
- * handle actual function expressions (occurring inside an expression) here.
- *
- * O(depth^2) parse count for inner functions is handled by recording a
- * lexer offset on the first compilation pass, so that the function can
- * be efficiently skipped on the second pass. This is encapsulated into
- * duk__parse_func_like_fnum().
- */
-
- duk_reg_t reg_temp;
- duk_int_t fnum;
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
-
- /* curr_token follows 'function' */
- fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*is_decl*/, 0 /*is_setget*/);
- DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum));
-
- duk__emit_a_bc(comp_ctx,
- DUK_OP_CLOSURE,
- (duk_regconst_t) reg_temp /*a*/,
- (duk_regconst_t) fnum /*bc*/);
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- return;
- }
-
- /* UNARY EXPRESSIONS */
-
- case DUK_TOK_DELETE: {
- /* Delete semantics are a bit tricky. The description in E5 specification
- * is kind of confusing, because it distinguishes between resolvability of
- * a reference (which is only known at runtime) seemingly at compile time
- * (= SyntaxError throwing).
- */
- duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- if (res->t == DUK_IVAL_VAR) {
- /* not allowed in strict mode, regardless of whether resolves;
- * in non-strict mode DELVAR handles both non-resolving and
- * resolving cases (the specification description is a bit confusing).
- */
-
- duk_reg_t reg_temp;
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- if (comp_ctx->curr_func.is_strict) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER);
- }
-
- DUK__SETTEMP(comp_ctx, temp_at_entry);
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
-
- duk_dup(ctx, res->x1.valstack_idx);
- if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- /* register bound variables are non-configurable -> always false */
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LDFALSE,
- (duk_regconst_t) reg_temp);
- } else {
- duk_dup(ctx, res->x1.valstack_idx);
- rc_varname = duk__getconst(comp_ctx);
- duk__emit_a_b(comp_ctx,
- DUK_OP_DELVAR,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) rc_varname);
- }
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- } else if (res->t == DUK_IVAL_PROP) {
- duk_reg_t reg_temp;
- duk_reg_t reg_obj;
- duk_regconst_t rc_key;
-
- DUK__SETTEMP(comp_ctx, temp_at_entry);
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
- rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_DELPROP,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_obj,
- rc_key);
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- } else {
- /* non-Reference deletion is always 'true', even in strict mode */
- duk_push_true(ctx);
- goto plain_value;
- }
- return;
- }
- case DUK_TOK_VOID: {
- duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- duk_push_undefined(ctx);
- goto plain_value;
- }
- case DUK_TOK_TYPEOF: {
- /* 'typeof' must handle unresolvable references without throwing
- * a ReferenceError (E5 Section 11.4.3). Register mapped values
- * will never be unresolvable so special handling is only required
- * when an identifier is a "slow path" one.
- */
- duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
-
- if (res->t == DUK_IVAL_VAR) {
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
- duk_reg_t reg_temp;
-
- duk_dup(ctx, res->x1.valstack_idx);
- if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
- "at compile time, need to use special run-time handling"));
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_TYPEOFID | DUK__EMIT_FLAG_B_IS_TARGET,
- reg_temp,
- rc_varname);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- return;
- }
- }
-
- args = (DUK_EXTRAOP_TYPEOF << 8) + 0;
- goto unary_extraop;
- }
- case DUK_TOK_INCREMENT: {
- args = (DUK_OP_PREINCR << 8) + 0;
- goto preincdec;
- }
- case DUK_TOK_DECREMENT: {
- args = (DUK_OP_PREDECR << 8) + 0;
- goto preincdec;
- }
- case DUK_TOK_ADD: {
- /* unary plus */
- duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
- duk_is_number(ctx, res->x1.valstack_idx)) {
- /* unary plus of a number is identity */
- ;
- return;
- }
- args = (DUK_EXTRAOP_UNP << 8) + 0;
- goto unary_extraop;
- }
- case DUK_TOK_SUB: {
- /* unary minus */
- duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
- duk_is_number(ctx, res->x1.valstack_idx)) {
- /* this optimization is important to handle negative literals
- * (which are not directly provided by the lexical grammar)
- */
- duk_tval *tv_num;
- duk_double_union du;
-
- tv_num = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
- DUK_ASSERT(tv_num != NULL);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
- du.d = DUK_TVAL_GET_NUMBER(tv_num);
- du.d = -du.d;
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
- DUK_TVAL_SET_NUMBER(tv_num, du.d);
- return;
- }
- args = (DUK_EXTRAOP_UNM << 8) + 0;
- goto unary_extraop;
- }
- case DUK_TOK_BNOT: {
- duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- args = (DUK_EXTRAOP_BNOT << 8) + 0;
- goto unary_extraop;
- }
- case DUK_TOK_LNOT: {
- duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) {
- /* Very minimal inlining to handle common idioms '!0' and '!1',
- * and also boolean arguments like '!false' and '!true'.
- */
- duk_tval *tv_val;
-
- tv_val = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
- DUK_ASSERT(tv_val != NULL);
- if (DUK_TVAL_IS_NUMBER(tv_val)) {
- duk_double_t d;
- d = DUK_TVAL_GET_NUMBER(tv_val);
- if (d == 0.0) {
- /* Matches both +0 and -0 on purpose. */
- DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true"));
- DUK_TVAL_SET_BOOLEAN_TRUE(tv_val);
- return;
- } else if (d == 1.0) {
- DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false"));
- DUK_TVAL_SET_BOOLEAN_FALSE(tv_val);
- return;
- }
- } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
- duk_small_int_t v;
- v = DUK_TVAL_GET_BOOLEAN(tv_val);
- DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v));
- DUK_ASSERT(v == 0 || v == 1);
- DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01);
- return;
- }
- }
- args = (DUK_EXTRAOP_LNOT << 8) + 0;
- goto unary_extraop;
- }
-
- } /* end switch */
-
- DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
- return;
-
- unary_extraop:
- {
- /* Note: must coerce to a (writable) temp register, so that e.g. "!x" where x
- * is a reg-mapped variable works correctly (does not mutate the variable register).
- */
-
- duk_reg_t reg_temp;
- reg_temp = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
- duk__emit_extraop_bc(comp_ctx,
- (args >> 8),
- (duk_regconst_t) reg_temp);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- return;
- }
-
- preincdec:
- {
- /* preincrement and predecrement */
- duk_reg_t reg_res;
- duk_small_uint_t args_op = args >> 8;
-
- /* Specific assumptions for opcode numbering. */
- DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV);
- DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV);
- DUK_ASSERT(DUK_OP_PREINCR + 8 == DUK_OP_PREINCP);
- DUK_ASSERT(DUK_OP_PREDECR + 8 == DUK_OP_PREDECP);
-
- reg_res = DUK__ALLOCTEMP(comp_ctx);
-
- duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
- if (res->t == DUK_IVAL_VAR) {
- duk_hstring *h_varname;
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- h_varname = duk_get_hstring(ctx, res->x1.valstack_idx);
- DUK_ASSERT(h_varname != NULL);
-
- if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
- goto syntax_error;
- }
-
- duk_dup(ctx, res->x1.valstack_idx);
- if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- duk__emit_a_bc(comp_ctx,
- args_op, /* e.g. DUK_OP_PREINCR */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_varbind);
- } else {
- duk__emit_a_bc(comp_ctx,
- args_op + 4, /* e.g. DUK_OP_PREINCV */
- (duk_regconst_t) reg_res,
- rc_varname);
- }
-
- DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
- (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
- } else if (res->t == DUK_IVAL_PROP) {
- duk_reg_t reg_obj; /* allocate to reg only (not const) */
- duk_regconst_t rc_key;
- reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
- rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
- duk__emit_a_b_c(comp_ctx,
- args_op + 8, /* e.g. DUK_OP_PREINCP */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_obj,
- rc_key);
- } else {
- /* Technically return value is not needed because INVLHS will
- * unconditially throw a ReferenceError. Coercion is necessary
- * for proper semantics (consider ToNumber() called for an object).
- * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
- */
-
- duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_UNP,
- reg_res); /* for side effects, result ignored */
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_INVLHS);
- }
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_res;
- DUK__SETTEMP(comp_ctx, reg_res + 1);
- return;
- }
-
- plain_value:
- {
- /* Stack top contains plain value */
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_VALUE;
- duk_replace(ctx, res->x1.valstack_idx);
- return;
- }
-
- syntax_error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
-}
-
-/* XXX: add flag to indicate whether caller cares about return value; this
- * affects e.g. handling of assignment expressions. This change needs API
- * changes elsewhere too.
- */
-DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_token *tk;
- duk_small_int_t tok;
- duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
-
- /*
- * ctx->prev_token token to process with duk__expr_led()
- * ctx->curr_token updated by caller
- */
-
- comp_ctx->curr_func.led_count++;
-
- /* The token in the switch has already been eaten here */
- tk = &comp_ctx->prev_token;
- tok = tk->t;
-
- DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
- (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
-
- /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
-
- switch (tok) {
-
- /* PRIMARY EXPRESSIONS */
-
- case DUK_TOK_PERIOD: {
- /* Property access expressions are critical for correct LHS ordering,
- * see comments in duk__expr()!
- *
- * A conservative approach would be to use duk__ivalue_totempconst()
- * for 'left'. However, allowing a reg-bound variable seems safe here
- * and is nice because "foo.bar" is a common expression. If the ivalue
- * is used in an expression a GETPROP will occur before any changes to
- * the base value can occur. If the ivalue is used as an assignment
- * LHS, the assignment code will ensure the base value is safe from
- * RHS mutation.
- */
-
- /* XXX: This now coerces an identifier into a GETVAR to a temp, which
- * causes an extra LDREG in call setup. It's sufficient to coerce to a
- * unary ivalue?
- */
- duk__ivalue_toplain(comp_ctx, left);
-
- /* NB: must accept reserved words as property name */
- if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
- }
-
- res->t = DUK_IVAL_PROP;
- duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
- DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
- duk_push_hstring(ctx, comp_ctx->curr_token.str1);
- duk_replace(ctx, res->x2.valstack_idx);
- res->x2.t = DUK_ISPEC_VALUE;
-
- /* special RegExp literal handling after IdentifierName */
- comp_ctx->curr_func.reject_regexp_in_adv = 1;
-
- duk__advance(comp_ctx);
- return;
- }
- case DUK_TOK_LBRACKET: {
- /* Property access expressions are critical for correct LHS ordering,
- * see comments in duk__expr()!
- */
-
- /* XXX: optimize temp reg use */
- /* XXX: similar coercion issue as in DUK_TOK_PERIOD */
- /* XXX: coerce to regs? it might be better for enumeration use, where the
- * same PROP ivalue is used multiple times. Or perhaps coerce PROP further
- * there?
- */
- /* XXX: for simple cases like x['y'] an unnecessary LDREG is
- * emitted for the base value; could avoid it if we knew that
- * the key expression is safe (e.g. just a single literal).
- */
-
- /* The 'left' value must not be a register bound variable
- * because it may be mutated during the rest of the expression
- * and E5.1 Section 11.2.1 specifies the order of evaluation
- * so that the base value is evaluated first.
- * See: test-bug-nested-prop-mutate.js.
- */
- duk__ivalue_totempconst(comp_ctx, left);
- duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */
- duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
-
- res->t = DUK_IVAL_PROP;
- duk__copy_ispec(comp_ctx, &res->x1, &res->x2); /* res.x1 -> res.x2 */
- duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
- return;
- }
- case DUK_TOK_LPAREN: {
- /* function call */
- duk_reg_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
- duk_int_t nargs;
- duk_small_uint_t call_flags = 0;
-
- /*
- * XXX: attempt to get the call result to "next temp" whenever
- * possible to avoid unnecessary register shuffles.
- *
- * XXX: CSPROP (and CSREG) can overwrite the call target register, and save one temp,
- * if the call target is a temporary register and at the top of the temp reg "stack".
- */
-
- /*
- * Setup call: target and 'this' binding. Three cases:
- *
- * 1. Identifier base (e.g. "foo()")
- * 2. Property base (e.g. "foo.bar()")
- * 3. Register base (e.g. "foo()()"; i.e. when a return value is a function)
- */
-
- if (left->t == DUK_IVAL_VAR) {
- duk_hstring *h_varname;
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
-
- h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
- DUK_ASSERT(h_varname != NULL);
- if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
- /* Potential direct eval call detected, flag the CALL
- * so that a run-time "direct eval" check is made and
- * special behavior may be triggered. Note that this
- * does not prevent 'eval' from being register bound.
- */
- DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
- "-> enabling EVALCALL flag, marking function "
- "as may_direct_eval"));
- call_flags |= DUK_BC_CALL_FLAG_EVALCALL;
-
- comp_ctx->curr_func.may_direct_eval = 1;
- }
-
- duk_dup(ctx, left->x1.valstack_idx);
- if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- duk__emit_a_b(comp_ctx,
- DUK_OP_CSREG,
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) reg_varbind);
- } else {
- duk__emit_a_b(comp_ctx,
- DUK_OP_CSVAR,
- (duk_regconst_t) (reg_cs + 0),
- rc_varname);
- }
- } else if (left->t == DUK_IVAL_PROP) {
- DUK_DDD(DUK_DDDPRINT("function call with property base"));
-
- duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 0); /* base */
- duk__ispec_toforcedreg(comp_ctx, &left->x2, reg_cs + 1); /* key */
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_CSPROP,
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) (reg_cs + 1)); /* in-place setup */
- } else {
- DUK_DDD(DUK_DDDPRINT("function call with register base"));
-
- duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
- duk__emit_a_b(comp_ctx,
- DUK_OP_CSREG,
- (duk_regconst_t) (reg_cs + 0),
- (duk_regconst_t) (reg_cs + 0)); /* in-place setup */
- }
-
- DUK__SETTEMP(comp_ctx, reg_cs + 2);
- nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */
-
- /* Tailcalls are handled by back-patching the TAILCALL flag to the
- * already emitted instruction later (in return statement parser).
- * Since A and C have a special meaning here, they cannot be "shuffled".
- */
-
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_CALL | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C,
- (duk_regconst_t) call_flags /*flags*/,
- (duk_regconst_t) reg_cs /*basereg*/,
- (duk_regconst_t) nargs /*numargs*/);
- DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_cs;
- return;
- }
-
- /* POSTFIX EXPRESSION */
-
- case DUK_TOK_INCREMENT: {
- args = (DUK_OP_POSTINCR << 8) + 0;
- goto postincdec;
- }
- case DUK_TOK_DECREMENT: {
- args = (DUK_OP_POSTDECR << 8) + 0;
- goto postincdec;
- }
-
- /* MULTIPLICATIVE EXPRESSION */
-
- case DUK_TOK_MUL: {
- args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
- goto binary;
- }
- case DUK_TOK_DIV: {
- args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
- goto binary;
- }
- case DUK_TOK_MOD: {
- args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* UnaryExpression */
- goto binary;
- }
-
- /* ADDITIVE EXPRESSION */
-
- case DUK_TOK_ADD: {
- args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
- goto binary;
- }
- case DUK_TOK_SUB: {
- args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
- goto binary;
- }
-
- /* SHIFT EXPRESSION */
-
- case DUK_TOK_ALSHIFT: {
- /* << */
- args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT;
- goto binary;
- }
- case DUK_TOK_ARSHIFT: {
- /* >> */
- args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT;
- goto binary;
- }
- case DUK_TOK_RSHIFT: {
- /* >>> */
- args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT;
- goto binary;
- }
-
- /* RELATIONAL EXPRESSION */
-
- case DUK_TOK_LT: {
- /* < */
- args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL;
- goto binary;
- }
- case DUK_TOK_GT: {
- args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL;
- goto binary;
- }
- case DUK_TOK_LE: {
- args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL;
- goto binary;
- }
- case DUK_TOK_GE: {
- args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL;
- goto binary;
- }
- case DUK_TOK_INSTANCEOF: {
- args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_INSTOF << 8) + DUK__BP_RELATIONAL;
- goto binary;
- }
- case DUK_TOK_IN: {
- args = (1 << 16 /*is_extra*/) + (DUK_EXTRAOP_IN << 8) + DUK__BP_RELATIONAL;
- goto binary;
- }
-
- /* EQUALITY EXPRESSION */
-
- case DUK_TOK_EQ: {
- args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY;
- goto binary;
- }
- case DUK_TOK_NEQ: {
- args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY;
- goto binary;
- }
- case DUK_TOK_SEQ: {
- args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY;
- goto binary;
- }
- case DUK_TOK_SNEQ: {
- args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY;
- goto binary;
- }
-
- /* BITWISE EXPRESSIONS */
-
- case DUK_TOK_BAND: {
- args = (DUK_OP_BAND << 8) + DUK__BP_BAND;
- goto binary;
- }
- case DUK_TOK_BXOR: {
- args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR;
- goto binary;
- }
- case DUK_TOK_BOR: {
- args = (DUK_OP_BOR << 8) + DUK__BP_BOR;
- goto binary;
- }
-
- /* LOGICAL EXPRESSIONS */
-
- case DUK_TOK_LAND: {
- /* syntactically left-associative but parsed as right-associative */
- args = (1 << 8) + DUK__BP_LAND - 1;
- goto binary_logical;
- }
- case DUK_TOK_LOR: {
- /* syntactically left-associative but parsed as right-associative */
- args = (0 << 8) + DUK__BP_LOR - 1;
- goto binary_logical;
- }
-
- /* CONDITIONAL EXPRESSION */
-
- case DUK_TOK_QUESTION: {
- /* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
- * but only if it really is a temp. Nothing fancy here now.
- */
- duk_reg_t reg_temp;
- duk_int_t pc_jump1;
- duk_int_t pc_jump2;
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
- duk__emit_if_true_skip(comp_ctx, reg_temp);
- pc_jump1 = duk__emit_jump_empty(comp_ctx); /* jump to false */
- duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
- duk__advance_expect(comp_ctx, DUK_TOK_COLON);
- pc_jump2 = duk__emit_jump_empty(comp_ctx); /* jump to end */
- duk__patch_jump_here(comp_ctx, pc_jump1);
- duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
- duk__patch_jump_here(comp_ctx, pc_jump2);
-
- DUK__SETTEMP(comp_ctx, reg_temp + 1);
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- return;
- }
-
- /* ASSIGNMENT EXPRESSION */
-
- case DUK_TOK_EQUALSIGN: {
- /*
- * Assignments are right associative, allows e.g.
- * a = 5;
- * a += b = 9; // same as a += (b = 9)
- * -> expression value 14, a = 14, b = 9
- *
- * Right associativiness is reflected in the BP for recursion,
- * "-1" ensures assignment operations are allowed.
- *
- * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
- */
- args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1; /* DUK_OP_NONE marks a 'plain' assignment */
- goto assign;
- }
- case DUK_TOK_ADD_EQ: {
- /* right associative */
- args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_SUB_EQ: {
- /* right associative */
- args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_MUL_EQ: {
- /* right associative */
- args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_DIV_EQ: {
- /* right associative */
- args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_MOD_EQ: {
- /* right associative */
- args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_ALSHIFT_EQ: {
- /* right associative */
- args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_ARSHIFT_EQ: {
- /* right associative */
- args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_RSHIFT_EQ: {
- /* right associative */
- args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_BAND_EQ: {
- /* right associative */
- args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_BOR_EQ: {
- /* right associative */
- args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
- case DUK_TOK_BXOR_EQ: {
- /* right associative */
- args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1;
- goto assign;
- }
-
- /* COMMA */
-
- case DUK_TOK_COMMA: {
- /* right associative */
-
- duk__ivalue_toplain_ignore(comp_ctx, left); /* need side effects, not value */
- duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/);
-
- /* return 'res' (of right part) as our result */
- return;
- }
-
- default: {
- break;
- }
- }
-
- DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok));
- DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
- return;
-
-#if 0
- /* XXX: shared handling for 'duk__expr_lhs'? */
- if (comp_ctx->curr_func.paren_level == 0 && XXX) {
- comp_ctx->curr_func.duk__expr_lhs = 0;
- }
-#endif
-
- binary:
- /*
- * Shared handling of binary operations
- *
- * args = (is_extraop << 16) + (opcode << 8) + rbp
- */
- {
- duk__ivalue_toplain(comp_ctx, left);
- duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/);
-
- /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */
- DUK_ASSERT(left->t == DUK_IVAL_PLAIN);
- DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
-
- res->t = (args >> 16) ? DUK_IVAL_ARITH_EXTRAOP : DUK_IVAL_ARITH;
- res->op = (args >> 8) & 0xff;
-
- res->x2.t = res->x1.t;
- res->x2.regconst = res->x1.regconst;
- duk_copy(ctx, res->x1.valstack_idx, res->x2.valstack_idx);
-
- res->x1.t = left->x1.t;
- res->x1.regconst = left->x1.regconst;
- duk_copy(ctx, left->x1.valstack_idx, res->x1.valstack_idx);
-
- DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
- (long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst));
- return;
- }
-
- binary_logical:
- /*
- * Shared handling for logical AND and logical OR.
- *
- * args = (truthval << 8) + rbp
- *
- * Truthval determines when to skip right-hand-side.
- * For logical AND truthval=1, for logical OR truthval=0.
- *
- * See doc/compiler.rst for discussion on compiling logical
- * AND and OR expressions. The approach here is very simplistic,
- * generating extra jumps and multiple evaluations of truth values,
- * but generates code on-the-fly with only local back-patching.
- *
- * Both logical AND and OR are syntactically left-associated.
- * However, logical ANDs are compiled as right associative
- * expressions, i.e. "A && B && C" as "A && (B && C)", to allow
- * skip jumps to skip over the entire tail. Similarly for logical OR.
- */
-
- {
- duk_reg_t reg_temp;
- duk_int_t pc_jump;
- duk_small_uint_t args_truthval = args >> 8;
- duk_small_uint_t args_rbp = args & 0xff;
-
- /* XXX: unoptimal use of temps, resetting */
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
-
- duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
- duk__emit_a_b(comp_ctx,
- DUK_OP_IF | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) args_truthval,
- (duk_regconst_t) reg_temp); /* skip jump conditionally */
- pc_jump = duk__emit_jump_empty(comp_ctx);
- duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
- duk__patch_jump_here(comp_ctx, pc_jump);
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_temp;
- return;
- }
-
- assign:
- /*
- * Shared assignment expression handling
- *
- * args = (opcode << 8) + rbp
- *
- * If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic.
- * Syntactically valid left-hand-side forms which are not accepted as
- * left-hand-side values (e.g. as in "f() = 1") must NOT cause a
- * SyntaxError, but rather a run-time ReferenceError.
- *
- * Assignment expression value is conceptually the LHS/RHS value
- * copied into a fresh temporary so that it won't change even if
- * LHS/RHS values change (e.g. when they're identifiers). Doing this
- * concretely produces inefficient bytecode, so we try to avoid the
- * extra temporary for some known-to-be-safe cases. Currently the
- * only safe case we detect is a "top level assignment", for example
- * "x = y + z;", where the assignment expression value is ignored.
- * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
- */
-
- {
- duk_small_uint_t args_op = args >> 8;
- duk_small_uint_t args_rbp = args & 0xff;
- duk_bool_t toplevel_assign;
-
- /* XXX: here we need to know if 'left' is left-hand-side compatible.
- * That information is no longer available from current expr parsing
- * state; it would need to be carried into the 'left' ivalue or by
- * some other means.
- */
-
- /* A top-level assignment is e.g. "x = y;". For these it's safe
- * to use the RHS as-is as the expression value, even if the RHS
- * is a reg-bound identifier. The RHS ('res') is right associative
- * so it has consumed all other assignment level operations; the
- * only relevant lower binding power construct is comma operator
- * which will ignore the expression value provided here.
- */
- toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */
- comp_ctx->curr_func.led_count == 1); /* one operator (= assign) */
- DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld",
- (long) comp_ctx->curr_func.nud_count,
- (long) comp_ctx->curr_func.led_count,
- (long) toplevel_assign));
-
- if (left->t == DUK_IVAL_VAR) {
- duk_hstring *h_varname;
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
-
- /* Keep the RHS as an unresolved ivalue for now, so it
- * can be a plain value or a unary/binary operation here.
- * We resolve it before finishing but doing it later allows
- * better bytecode in some cases.
- */
- duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
-
- h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
- DUK_ASSERT(h_varname != NULL);
- if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
- /* E5 Section 11.13.1 (and others for other assignments), step 4 */
- goto syntax_error_lvalue;
- }
- duk_dup(ctx, left->x1.valstack_idx);
- (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
-
- if (args_op == DUK_OP_NONE) {
- if (toplevel_assign) {
- /* Any 'res' will do. */
- DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
- } else {
- /* 'res' must be a plain ivalue, and not register-bound variable. */
- DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
- if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST &&
- (res->x1.regconst & DUK__CONST_MARKER) == 0 &&
- !DUK__ISTEMP(comp_ctx, res->x1.regconst))) {
- duk__ivalue_totempconst(comp_ctx, res);
- }
- }
- } else {
- duk__ivalue_toregconst(comp_ctx, res);
- DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
-
- if (reg_varbind >= 0) {
- duk_reg_t reg_res;
-
- if (toplevel_assign) {
- /* 'reg_varbind' is the operation result and can also
- * become the expression value for top level assignments
- * such as: "var x; x += y;".
- */
- reg_res = reg_varbind;
- } else {
- /* Not safe to use 'reg_varbind' as assignment expression
- * value, so go through a temp.
- */
- reg_res = DUK__ALLOCTEMP(comp_ctx);
- }
-
- duk__emit_a_b_c(comp_ctx,
- args_op,
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_varbind,
- res->x1.regconst);
- res->x1.regconst = (duk_regconst_t) reg_res;
- } else {
- /* When LHS is not register bound, always go through a
- * temporary. No optimization for top level assignment.
- */
- duk_reg_t reg_temp;
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
-
- duk__emit_a_bc(comp_ctx,
- DUK_OP_GETVAR,
- (duk_regconst_t) reg_temp,
- rc_varname);
- duk__emit_a_b_c(comp_ctx,
- args_op,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_temp,
- res->x1.regconst);
- res->x1.regconst = (duk_regconst_t) reg_temp;
- }
-
- DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
- }
-
- /* At this point 'res' holds the potential expression value.
- * It can be basically any ivalue here, including a reg-bound
- * identifier (if code above deems it safe) or a unary/binary
- * operation. Operations must be resolved to a side effect free
- * plain value, and the side effects must happen exactly once.
- */
-
- if (reg_varbind >= 0) {
- if (res->t != DUK_IVAL_PLAIN) {
- /* Resolve 'res' directly into the LHS binding, and use
- * that as the expression value if safe. If not safe,
- * resolve to a temp/const and copy to LHS.
- */
- if (toplevel_assign) {
- duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind);
- } else {
- duk__ivalue_totempconst(comp_ctx, res);
- duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
- duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
- }
- } else {
- /* Use 'res' as the expression value (it's side effect
- * free and may be a plain value, a register, or a
- * constant) and write it to the LHS binding too.
- */
- duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
- duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
- }
- } else {
- /* Only a reg fits into 'A' so coerce 'res' into a register
- * for PUTVAR.
- *
- * XXX: here the current A/B/C split is suboptimal: we could
- * just use 9 bits for reg_res (and support constants) and 17
- * instead of 18 bits for the varname const index.
- */
-
- duk__ivalue_toreg(comp_ctx, res);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- res->x1.regconst,
- rc_varname);
- }
-
- /* 'res' contains expression value */
- } else if (left->t == DUK_IVAL_PROP) {
- /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
- duk_reg_t reg_obj;
- duk_regconst_t rc_key;
- duk_regconst_t rc_res;
- duk_reg_t reg_temp;
-
- /* Property access expressions ('a[b]') are critical to correct
- * LHS evaluation ordering, see test-dev-assign-eval-order*.js.
- * We must make sure that the LHS target slot (base object and
- * key) don't change during RHS evaluation. The only concrete
- * problem is a register reference to a variable-bound register
- * (i.e., non-temp). Require temp regs for both key and base.
- *
- * Don't allow a constant for the object (even for a number
- * etc), as it goes into the 'A' field of the opcode.
- */
-
- reg_obj = duk__ispec_toregconst_raw(comp_ctx,
- &left->x1,
- -1 /*forced_reg*/,
- DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
-
- rc_key = duk__ispec_toregconst_raw(comp_ctx,
- &left->x2,
- -1 /*forced_reg*/,
- DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
-
- /* Evaluate RHS only when LHS is safe. */
- duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
- DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
-
- if (args_op == DUK_OP_NONE) {
- rc_res = res->x1.regconst;
- } else {
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_GETPROP,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_obj,
- rc_key);
- duk__emit_a_b_c(comp_ctx,
- args_op,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) reg_temp,
- res->x1.regconst);
- rc_res = (duk_regconst_t) reg_temp;
- }
-
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_obj,
- rc_key,
- rc_res);
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = rc_res;
- } else {
- /* No support for lvalues returned from new or function call expressions.
- * However, these must NOT cause compile-time SyntaxErrors, but run-time
- * ReferenceErrors. Both left and right sides of the assignment must be
- * evaluated before throwing a ReferenceError. For instance:
- *
- * f() = g();
- *
- * must result in f() being evaluated, then g() being evaluated, and
- * finally, a ReferenceError being thrown. See E5 Section 11.13.1.
- */
-
- duk_regconst_t rc_res;
-
- /* first evaluate LHS fully to ensure all side effects are out */
- duk__ivalue_toplain_ignore(comp_ctx, left);
-
- /* then evaluate RHS fully (its value becomes the expression value too) */
- rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
-
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_INVLHS);
-
- /* XXX: this value is irrelevant because of INVLHS? */
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = rc_res;
- }
-
- return;
- }
-
- postincdec:
- {
- /*
- * Post-increment/decrement will return the original value as its
- * result value. However, even that value will be coerced using
- * ToNumber() which is quite awkward. Specific bytecode opcodes
- * are used to handle these semantics.
- *
- * Note that post increment/decrement has a "no LineTerminator here"
- * restriction. This is handled by duk__expr_lbp(), which forcibly terminates
- * the previous expression if a LineTerminator occurs before '++'/'--'.
- */
-
- duk_reg_t reg_res;
- duk_small_uint_t args_op = args >> 8;
-
- /* Specific assumptions for opcode numbering. */
- DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV);
- DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV);
- DUK_ASSERT(DUK_OP_POSTINCR + 8 == DUK_OP_POSTINCP);
- DUK_ASSERT(DUK_OP_POSTDECR + 8 == DUK_OP_POSTDECP);
-
- reg_res = DUK__ALLOCTEMP(comp_ctx);
-
- if (left->t == DUK_IVAL_VAR) {
- duk_hstring *h_varname;
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- h_varname = duk_get_hstring(ctx, left->x1.valstack_idx);
- DUK_ASSERT(h_varname != NULL);
-
- if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
- goto syntax_error;
- }
-
- duk_dup(ctx, left->x1.valstack_idx);
- if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- duk__emit_a_bc(comp_ctx,
- args_op, /* e.g. DUK_OP_POSTINCR */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_varbind);
- } else {
- duk__emit_a_bc(comp_ctx,
- args_op + 4, /* e.g. DUK_OP_POSTINCV */
- (duk_regconst_t) reg_res,
- rc_varname);
- }
-
- DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
- (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
- } else if (left->t == DUK_IVAL_PROP) {
- duk_reg_t reg_obj; /* allocate to reg only (not const) */
- duk_regconst_t rc_key;
-
- reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
- rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
- duk__emit_a_b_c(comp_ctx,
- args_op + 8, /* e.g. DUK_OP_POSTINCP */
- (duk_regconst_t) reg_res,
- (duk_regconst_t) reg_obj,
- rc_key);
- } else {
- /* Technically return value is not needed because INVLHS will
- * unconditially throw a ReferenceError. Coercion is necessary
- * for proper semantics (consider ToNumber() called for an object).
- * Use DUK_EXTRAOP_UNP with a dummy register to get ToNumber().
- */
- duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_UNP,
- reg_res); /* for side effects, result ignored */
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_INVLHS);
- }
-
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_REGCONST;
- res->x1.regconst = (duk_regconst_t) reg_res;
- DUK__SETTEMP(comp_ctx, reg_res + 1);
- return;
- }
-
- syntax_error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
- return;
-
- syntax_error_lvalue:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE);
- return;
-}
-
-DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
- duk_small_int_t tok = comp_ctx->curr_token.t;
-
- DUK_ASSERT(tok >= DUK_TOK_MINVAL && tok <= DUK_TOK_MAXVAL);
- DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
-
- /* XXX: integrate support for this into led() instead?
- * Similar issue as post-increment/post-decrement.
- */
-
- /* prevent duk__expr_led() by using a binding power less than anything valid */
- if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) {
- return 0;
- }
-
- if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) &&
- (comp_ctx->curr_token.lineterm)) {
- /* '++' or '--' in a post-increment/decrement position,
- * and a LineTerminator occurs between the operator and
- * the preceding expression. Force the previous expr
- * to terminate, in effect treating e.g. "a,b\n++" as
- * "a,b;++" (= SyntaxError).
- */
- return 0;
- }
-
- return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]); /* format is bit packed */
-}
-
-/*
- * Expression parsing.
- *
- * Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the
- * first token of the expression. Upon exit, 'curr_tok' will be the first
- * token not part of the expression (e.g. semicolon terminating an expression
- * statement).
- */
-
-#define DUK__EXPR_RBP_MASK 0xff
-#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */
-#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */
-#define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */
-
-/* main expression parser function */
-DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */
- duk_ivalue *tmp = &tmp_alloc;
- duk_small_uint_t rbp;
-
- DUK__RECURSION_INCREASE(comp_ctx, thr);
-
- duk_require_stack(ctx, DUK__PARSE_EXPR_SLOTS);
-
- /* filter out flags from exprtop rbp_flags here to save space */
- rbp = rbp_flags & DUK__EXPR_RBP_MASK;
-
- DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld",
- (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in,
- (long) comp_ctx->curr_func.paren_level));
-
- DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc));
- tmp->x1.valstack_idx = duk_get_top(ctx);
- tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
-
- /* XXX: where to release temp regs in intermediate expressions?
- * e.g. 1+2+3 -> don't inflate temp register count when parsing this.
- * that particular expression temp regs can be forced here.
- */
-
- /* XXX: increase ctx->expr_tokens here for every consumed token
- * (this would be a nice statistic)?
- */
-
- if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
- /* XXX: possibly incorrect handling of empty expression */
- DUK_DDD(DUK_DDDPRINT("empty expression"));
- if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
- }
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_VALUE;
- duk_push_undefined(ctx);
- duk_replace(ctx, res->x1.valstack_idx);
- goto cleanup;
- }
-
- duk__advance(comp_ctx);
- duk__expr_nud(comp_ctx, res); /* reuse 'res' as 'left' */
- while (rbp < duk__expr_lbp(comp_ctx)) {
- duk__advance(comp_ctx);
- duk__expr_led(comp_ctx, res, tmp);
- duk__copy_ivalue(comp_ctx, tmp, res); /* tmp -> res */
- }
-
- cleanup:
- /* final result is already in 'res' */
-
- duk_pop_2(ctx);
-
- DUK__RECURSION_DECREASE(comp_ctx, thr);
-}
-
-DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk_hthread *thr = comp_ctx->thr;
-
- /* Note: these variables must reside in 'curr_func' instead of the global
- * context: when parsing function expressions, expression parsing is nested.
- */
- comp_ctx->curr_func.nud_count = 0;
- comp_ctx->curr_func.led_count = 0;
- comp_ctx->curr_func.paren_level = 0;
- comp_ctx->curr_func.expr_lhs = 1;
- comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1);
-
- duk__expr(comp_ctx, res, rbp_flags);
-
- if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
- }
-}
-
-/* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
- * and result conversions.
- *
- * Each helper needs at least 2-3 calls to make it worth while to wrap.
- */
-
-#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__expr(comp_ctx, res, rbp_flags);
- return duk__ivalue_toreg(comp_ctx, res);
-}
-#endif
-
-#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__expr(comp_ctx, res, rbp_flags);
- return duk__ivalue_totemp(comp_ctx, res);
-}
-#endif
-
-DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
- DUK_ASSERT(forced_reg >= 0);
- duk__expr(comp_ctx, res, rbp_flags);
- duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
-}
-
-DUK_LOCAL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__expr(comp_ctx, res, rbp_flags);
- return duk__ivalue_toregconst(comp_ctx, res);
-}
-
-#if 0 /* unused */
-DUK_LOCAL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__expr(comp_ctx, res, rbp_flags);
- return duk__ivalue_totempconst(comp_ctx, res);
-}
-#endif
-
-DUK_LOCAL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__expr(comp_ctx, res, rbp_flags);
- duk__ivalue_toplain(comp_ctx, res);
-}
-
-DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__expr(comp_ctx, res, rbp_flags);
- duk__ivalue_toplain_ignore(comp_ctx, res);
-}
-
-DUK_LOCAL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__exprtop(comp_ctx, res, rbp_flags);
- return duk__ivalue_toreg(comp_ctx, res);
-}
-
-#if 0 /* unused */
-DUK_LOCAL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__exprtop(comp_ctx, res, rbp_flags);
- return duk__ivalue_totemp(comp_ctx, res);
-}
-#endif
-
-DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
- DUK_ASSERT(forced_reg >= 0);
- duk__exprtop(comp_ctx, res, rbp_flags);
- duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
-}
-
-DUK_LOCAL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
- duk__exprtop(comp_ctx, res, rbp_flags);
- return duk__ivalue_toregconst(comp_ctx, res);
-}
-
-#if 0 /* unused */
-DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
- duk__exprtop(comp_ctx, res, rbp_flags);
- duk__ivalue_toplain_ignore(comp_ctx, res);
-}
-#endif
-
-/*
- * Parse an individual source element (top level statement) or a statement.
- *
- * Handles labeled statements automatically (peeling away labels before
- * parsing an expression that follows the label(s)).
- *
- * Upon entry, 'curr_tok' contains the first token of the statement (parsed
- * in "allow regexp literal" mode). Upon exit, 'curr_tok' contains the first
- * token following the statement (if the statement has a terminator, this is
- * the token after the terminator).
- */
-
-#ifdef DUK__HAS_VAL
-#undef DUK__HAS_VAL
-#endif
-#ifdef DUK__HAS_TERM
-#undef DUK__HAS_TERM
-#endif
-#ifdef DUK__ALLOW_AUTO_SEMI_ALWAYS
-#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
-#endif
-#ifdef DUK__STILL_PROLOGUE
-#undef DUK__STILL_PROLOGUE
-#endif
-#ifdef DUK__IS_TERMINAL
-#undef DUK__IS_TERMINAL
-#endif
-
-#define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */
-#define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */
-#define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */
-#define DUK__STILL_PROLOGUE (1 << 3) /* statement does not terminate directive prologue */
-#define DUK__IS_TERMINAL (1 << 4) /* statement is guaranteed to be terminal (control doesn't flow to next statement) */
-
-/* Parse a single variable declaration (e.g. "i" or "i=10"). A leading 'var'
- * has already been eaten. These is no return value in 'res', it is used only
- * as a temporary.
- *
- * When called from 'for-in' statement parser, the initializer expression must
- * not allow the 'in' token. The caller supply additional expression parsing
- * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'.
- *
- * Finally, out_rc_varname and out_reg_varbind are updated to reflect where
- * the identifier is bound:
- *
- * If register bound: out_reg_varbind >= 0, out_rc_varname == 0 (ignore)
- * If not register bound: out_reg_varbind < 0, out_rc_varname >= 0
- *
- * These allow the caller to use the variable for further assignment, e.g.
- * as is done in 'for-in' parsing.
- */
-
-DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_hstring *h_varname;
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- /* assume 'var' has been eaten */
-
- /* Note: Identifier rejects reserved words */
- if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
- goto syntax_error;
- }
- h_varname = comp_ctx->curr_token.str1;
-
- DUK_ASSERT(h_varname != NULL);
-
- /* strict mode restrictions (E5 Section 12.2.1) */
- if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
- goto syntax_error;
- }
-
- /* register declarations in first pass */
- if (comp_ctx->curr_func.in_scanning) {
- duk_uarridx_t n;
- DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
- (duk_heaphdr *) h_varname));
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
- duk_push_hstring(ctx, h_varname);
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
- duk_push_int(ctx, DUK_DECL_TYPE_VAR + (0 << 8));
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
- }
-
- duk_push_hstring(ctx, h_varname); /* push before advancing to keep reachable */
-
- /* register binding lookup is based on varmap (even in first pass) */
- duk_dup_top(ctx);
- (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
-
- duk__advance(comp_ctx); /* eat identifier */
-
- if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) {
- duk__advance(comp_ctx);
-
- DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
- (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
-
- duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/); /* AssignmentExpression */
-
- if (reg_varbind >= 0) {
- duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
- } else {
- duk_reg_t reg_val;
- reg_val = duk__ivalue_toreg(comp_ctx, res);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_val,
- rc_varname);
- }
- } else {
- if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) {
- /* Used for minimal 'const': initializer required. */
- goto syntax_error;
- }
- }
-
- duk_pop(ctx); /* pop varname */
-
- *out_rc_varname = rc_varname;
- *out_reg_varbind = reg_varbind;
-
- return;
-
- syntax_error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION);
-}
-
-DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) {
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- duk__advance(comp_ctx); /* eat 'var' */
-
- for (;;) {
- /* rc_varname and reg_varbind are ignored here */
- duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, &reg_varbind, &rc_varname);
-
- if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
- break;
- }
- duk__advance(comp_ctx);
- }
-}
-
-DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
- duk_reg_t temp_reset; /* knock back "next temp" to this whenever possible */
- duk_reg_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
-
- DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
-
- /* Two temporaries are preallocated here for variants 3 and 4 which need
- * registers which are never clobbered by expressions in the loop
- * (concretely: for the enumerator object and the next enumerated value).
- * Variants 1 and 2 "release" these temps.
- */
-
- reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2);
-
- temp_reset = DUK__GETTEMP(comp_ctx);
-
- /*
- * For/for-in main variants are:
- *
- * 1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement
- * 2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement
- * 3. for (LeftHandSideExpression in Expression) Statement
- * 4. for (var VariableDeclarationNoIn in Expression) Statement
- *
- * Parsing these without arbitrary lookahead or backtracking is relatively
- * tricky but we manage to do so for now.
- *
- * See doc/compiler.rst for a detailed discussion of control flow
- * issues, evaluation order issues, etc.
- */
-
- duk__advance(comp_ctx); /* eat 'for' */
- duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
-
- DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx)));
-
- /* a label site has been emitted by duk__parse_stmt() automatically
- * (it will also emit the ENDLABEL).
- */
-
- if (comp_ctx->curr_token.t == DUK_TOK_VAR) {
- /*
- * Variant 2 or 4
- */
-
- duk_reg_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
- duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */
-
- duk__advance(comp_ctx); /* eat 'var' */
- duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
- DUK__SETTEMP(comp_ctx, temp_reset);
-
- if (comp_ctx->curr_token.t == DUK_TOK_IN) {
- /*
- * Variant 4
- */
-
- DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement"));
- pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here */
- if (reg_varbind >= 0) {
- duk__emit_a_bc(comp_ctx,
- DUK_OP_LDREG,
- (duk_regconst_t) reg_varbind,
- (duk_regconst_t) (reg_temps + 0));
- } else {
- duk__emit_a_bc(comp_ctx,
- DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_temps + 0),
- rc_varname);
- }
- goto parse_3_or_4;
- } else {
- /*
- * Variant 2
- */
-
- DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement"));
- for (;;) {
- /* more initializers */
- if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
- break;
- }
- DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer"));
-
- duk__advance(comp_ctx); /* eat comma */
- duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
- }
- goto parse_1_or_2;
- }
- } else {
- /*
- * Variant 1 or 3
- */
-
- pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here (variant 3) */
-
- /* Note that duk__exprtop() here can clobber any reg above current temp_next,
- * so any loop variables (e.g. enumerator) must be "preallocated".
- */
-
- /* don't coerce yet to a plain value (variant 3 needs special handling) */
- duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression */
- if (comp_ctx->curr_token.t == DUK_TOK_IN) {
- /*
- * Variant 3
- */
-
- /* XXX: need to determine LHS type, and check that it is LHS compatible */
- DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement"));
- if (duk__expr_is_empty(comp_ctx)) {
- goto syntax_error; /* LeftHandSideExpression does not allow empty expression */
- }
-
- if (res->t == DUK_IVAL_VAR) {
- duk_reg_t reg_varbind;
- duk_regconst_t rc_varname;
-
- duk_dup(ctx, res->x1.valstack_idx);
- if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
- duk__emit_a_bc(comp_ctx,
- DUK_OP_LDREG,
- (duk_regconst_t) reg_varbind,
- (duk_regconst_t) (reg_temps + 0));
- } else {
- duk__emit_a_bc(comp_ctx,
- DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_temps + 0),
- rc_varname);
- }
- } else if (res->t == DUK_IVAL_PROP) {
- /* Don't allow a constant for the object (even for a number etc), as
- * it goes into the 'A' field of the opcode.
- */
- duk_reg_t reg_obj;
- duk_regconst_t rc_key;
- reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
- rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) reg_obj,
- rc_key,
- (duk_regconst_t) (reg_temps + 0));
- } else {
- duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_INVLHS);
- }
- goto parse_3_or_4;
- } else {
- /*
- * Variant 1
- */
-
- DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement"));
- duk__ivalue_toplain_ignore(comp_ctx, res);
- goto parse_1_or_2;
- }
- }
-
- parse_1_or_2:
- /*
- * Parse variant 1 or 2. The first part expression (which differs
- * in the variants) has already been parsed and its code emitted.
- *
- * reg_temps + 0: unused
- * reg_temps + 1: unused
- */
- {
- duk_regconst_t rc_cond;
- duk_int_t pc_l1, pc_l2, pc_l3, pc_l4;
- duk_int_t pc_jumpto_l3, pc_jumpto_l4;
- duk_bool_t expr_c_empty;
-
- DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2"));
-
- /* "release" preallocated temps since we won't need them */
- temp_reset = reg_temps + 0;
- DUK__SETTEMP(comp_ctx, temp_reset);
-
- duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
-
- pc_l1 = duk__get_current_pc(comp_ctx);
- duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
- if (duk__expr_is_empty(comp_ctx)) {
- /* no need to coerce */
- pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
- pc_jumpto_l4 = -1; /* omitted */
- } else {
- rc_cond = duk__ivalue_toregconst(comp_ctx, res);
- duk__emit_if_false_skip(comp_ctx, rc_cond);
- pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
- pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); /* to exit */
- }
- DUK__SETTEMP(comp_ctx, temp_reset);
-
- duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
-
- pc_l2 = duk__get_current_pc(comp_ctx);
- duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
- if (duk__expr_is_empty(comp_ctx)) {
- /* no need to coerce */
- expr_c_empty = 1;
- /* JUMP L1 omitted */
- } else {
- duk__ivalue_toplain_ignore(comp_ctx, res);
- expr_c_empty = 0;
- duk__emit_jump(comp_ctx, pc_l1);
- }
- DUK__SETTEMP(comp_ctx, temp_reset);
-
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
-
- pc_l3 = duk__get_current_pc(comp_ctx);
- duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
- if (expr_c_empty) {
- duk__emit_jump(comp_ctx, pc_l1);
- } else {
- duk__emit_jump(comp_ctx, pc_l2);
- }
- /* temp reset is not necessary after duk__parse_stmt(), which already does it */
-
- pc_l4 = duk__get_current_pc(comp_ctx);
-
- DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, "
- "break: %ld->%ld, continue: %ld->%ld",
- (long) pc_jumpto_l3, (long) pc_l3, (long) pc_jumpto_l4, (long) pc_l4,
- (long) (pc_label_site + 1), (long) pc_l4, (long) (pc_label_site + 2), (long) pc_l2));
-
- duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
- duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
- duk__patch_jump(comp_ctx,
- pc_label_site + 1,
- pc_l4); /* break jump */
- duk__patch_jump(comp_ctx,
- pc_label_site + 2,
- expr_c_empty ? pc_l1 : pc_l2); /* continue jump */
- }
- goto finished;
-
- parse_3_or_4:
- /*
- * Parse variant 3 or 4.
- *
- * For variant 3 (e.g. "for (A in C) D;") the code for A (except the
- * final property/variable write) has already been emitted. The first
- * instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted
- * there to satisfy control flow needs.
- *
- * For variant 4, if the variable declaration had an initializer
- * (e.g. "for (var A = B in C) D;") the code for the assignment
- * (B) has already been emitted.
- *
- * Variables set before entering here:
- *
- * pc_v34_lhs: insert a "JUMP L2" here (see doc/compiler.rst example).
- * reg_temps + 0: iteration target value (written to LHS)
- * reg_temps + 1: enumerator object
- */
- {
- duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
- duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
- duk_reg_t reg_target;
-
- DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
-
- DUK__SETTEMP(comp_ctx, temp_reset);
-
- /* First we need to insert a jump in the middle of previously
- * emitted code to get the control flow right. No jumps can
- * cross the position where the jump is inserted. See doc/compiler.rst
- * for discussion on the intricacies of control flow and side effects
- * for variants 3 and 4.
- */
-
- duk__insert_jump_entry(comp_ctx, pc_v34_lhs);
- pc_jumpto_l2 = pc_v34_lhs; /* inserted jump */
- pc_l1 = pc_v34_lhs + 1; /* +1, right after inserted jump */
-
- /* The code for writing reg_temps + 0 to the left hand side has already
- * been emitted.
- */
-
- pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* -> loop body */
-
- duk__advance(comp_ctx); /* eat 'in' */
-
- /* Parse enumeration target and initialize enumerator. For 'null' and 'undefined',
- * INITENUM will creates a 'null' enumerator which works like an empty enumerator
- * (E5 Section 12.6.4, step 3). Note that INITENUM requires the value to be in a
- * register (constant not allowed).
- */
-
- pc_l2 = duk__get_current_pc(comp_ctx);
- reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
- (duk_regconst_t) (reg_temps + 1),
- (duk_regconst_t) reg_target);
- pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
- DUK__SETTEMP(comp_ctx, temp_reset);
-
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
-
- pc_l3 = duk__get_current_pc(comp_ctx);
- duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
- /* temp reset is not necessary after duk__parse_stmt(), which already does it */
-
- /* NEXTENUM needs a jump slot right after the main opcode.
- * We need the code emitter to reserve the slot: if there's
- * target shuffling, the target shuffle opcodes must happen
- * after the jump slot (for NEXTENUM the shuffle opcodes are
- * not needed if the enum is finished).
- */
- pc_l4 = duk__get_current_pc(comp_ctx);
- duk__emit_extraop_b_c(comp_ctx,
- DUK_EXTRAOP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
- (duk_regconst_t) (reg_temps + 0),
- (duk_regconst_t) (reg_temps + 1));
- pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */
- duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */
-
- pc_l5 = duk__get_current_pc(comp_ctx);
-
- /* XXX: since the enumerator may be a memory expensive object,
- * perhaps clear it explicitly here? If so, break jump must
- * go through this clearing operation.
- */
-
- DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, "
- "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, "
- "break: %ld->%ld, continue: %ld->%ld",
- (long) pc_jumpto_l2, (long) pc_l2, (long) pc_jumpto_l3, (long) pc_l3,
- (long) pc_jumpto_l4, (long) pc_l4, (long) pc_jumpto_l5, (long) pc_l5,
- (long) (pc_label_site + 1), (long) pc_l5, (long) (pc_label_site + 2), (long) pc_l4));
-
- duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2);
- duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
- duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
- duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5);
- duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5); /* break jump */
- duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4); /* continue jump */
- }
- goto finished;
-
- finished:
- DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement"));
- return;
-
- syntax_error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR);
-}
-
-DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
- duk_hthread *thr = comp_ctx->thr;
- duk_reg_t temp_at_loop;
- duk_regconst_t rc_switch; /* reg/const for switch value */
- duk_regconst_t rc_case; /* reg/const for case value */
- duk_reg_t reg_temp; /* general temp register */
- duk_int_t pc_prevcase = -1;
- duk_int_t pc_prevstmt = -1;
- duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */
-
- /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
-
- /*
- * Switch is pretty complicated because of several conflicting concerns:
- *
- * - Want to generate code without an intermediate representation,
- * i.e., in one go
- *
- * - Case selectors are expressions, not values, and may thus e.g. throw
- * exceptions (which causes evaluation order concerns)
- *
- * - Evaluation semantics of case selectors and default clause need to be
- * carefully implemented to provide correct behavior even with case value
- * side effects
- *
- * - Fall through case and default clauses; avoiding dead JUMPs if case
- * ends with an unconditional jump (a break or a continue)
- *
- * - The same case value may occur multiple times, but evaluation rules
- * only process the first match before switching to a "propagation" mode
- * where case values are no longer evaluated
- *
- * See E5 Section 12.11. Also see doc/compiler.rst for compilation
- * discussion.
- */
-
- duk__advance(comp_ctx);
- duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
- rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
- duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
-
- DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch));
-
- temp_at_loop = DUK__GETTEMP(comp_ctx);
-
- for (;;) {
- duk_int_t num_stmts;
- duk_small_int_t tok;
-
- /* sufficient for keeping temp reg numbers in check */
- DUK__SETTEMP(comp_ctx, temp_at_loop);
-
- if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
- break;
- }
-
- /*
- * Parse a case or default clause.
- */
-
- if (comp_ctx->curr_token.t == DUK_TOK_CASE) {
- /*
- * Case clause.
- *
- * Note: cannot use reg_case as a temp register (for SEQ target)
- * because it may be a constant.
- */
-
- duk__patch_jump_here(comp_ctx, pc_prevcase); /* chain jumps for case
- * evaluation and checking
- */
-
- duk__advance(comp_ctx);
- rc_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
- duk__advance_expect(comp_ctx, DUK_TOK_COLON);
-
- reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_SEQ,
- (duk_regconst_t) reg_temp,
- rc_switch,
- rc_case);
- duk__emit_if_true_skip(comp_ctx, (duk_regconst_t) reg_temp);
-
- /* jump to next case clause */
- pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */
-
- /* statements go here (if any) on next loop */
- } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) {
- /*
- * Default clause.
- */
-
- if (pc_default >= 0) {
- goto syntax_error;
- }
- duk__advance(comp_ctx);
- duk__advance_expect(comp_ctx, DUK_TOK_COLON);
-
- /* Fix for https://github.com/svaarala/duktape/issues/155:
- * If 'default' is first clause (detected by pc_prevcase < 0)
- * we need to ensure we stay in the matching chain.
- */
- if (pc_prevcase < 0) {
- DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump"));
- pc_prevcase = duk__emit_jump_empty(comp_ctx);
- }
-
- /* default clause matches next statement list (if any) */
- pc_default = -2;
- } else {
- /* Code is not accepted before the first case/default clause */
- goto syntax_error;
- }
-
- /*
- * Parse code after the clause. Possible terminators are
- * 'case', 'default', and '}'.
- *
- * Note that there may be no code at all, not even an empty statement,
- * between case clauses. This must be handled just like an empty statement
- * (omitting seemingly pointless JUMPs), to avoid situations like
- * test-bug-case-fallthrough.js.
- */
-
- num_stmts = 0;
- if (pc_default == -2) {
- pc_default = duk__get_current_pc(comp_ctx);
- }
-
- /* Note: this is correct even for default clause statements:
- * they participate in 'fall-through' behavior even if the
- * default clause is in the middle.
- */
- duk__patch_jump_here(comp_ctx, pc_prevstmt); /* chain jumps for 'fall-through'
- * after a case matches.
- */
-
- for (;;) {
- tok = comp_ctx->curr_token.t;
- if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT ||
- tok == DUK_TOK_RCURLY) {
- break;
- }
- num_stmts++;
- duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
- }
-
- /* fall-through jump to next code of next case (backpatched) */
- pc_prevstmt = duk__emit_jump_empty(comp_ctx);
-
- /* XXX: would be nice to omit this jump when the jump is not
- * reachable, at least in the obvious cases (such as the case
- * ending with a 'break'.
- *
- * Perhaps duk__parse_stmt() could provide some info on whether
- * the statement is a "dead end"?
- *
- * If implemented, just set pc_prevstmt to -1 when not needed.
- */
- }
-
- DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
- duk__advance(comp_ctx);
-
- /* default case control flow patchup; note that if pc_prevcase < 0
- * (i.e. no case clauses), control enters default case automatically.
- */
- if (pc_default >= 0) {
- /* default case exists: go there if no case matches */
- duk__patch_jump(comp_ctx, pc_prevcase, pc_default);
- } else {
- /* default case does not exist, or no statements present
- * after default case: finish case evaluation
- */
- duk__patch_jump_here(comp_ctx, pc_prevcase);
- }
-
- /* fall-through control flow patchup; note that pc_prevstmt may be
- * < 0 (i.e. no case clauses), in which case this is a no-op.
- */
- duk__patch_jump_here(comp_ctx, pc_prevstmt);
-
- /* continue jump not patched, an INVALID opcode remains there */
- duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
-
- /* Note: 'fast' breaks will jump to pc_label_site + 1, which will
- * then jump here. The double jump will be eliminated by a
- * peephole pass, resulting in an optimal jump here. The label
- * site jumps will remain in bytecode and will waste code size.
- */
-
- return;
-
- syntax_error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH);
-}
-
-DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_reg_t temp_reset;
- duk_regconst_t rc_cond;
- duk_int_t pc_jump_false;
-
- DUK_DDD(DUK_DDDPRINT("begin parsing if statement"));
-
- temp_reset = DUK__GETTEMP(comp_ctx);
-
- duk__advance(comp_ctx); /* eat 'if' */
- duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
-
- rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
- duk__emit_if_true_skip(comp_ctx, rc_cond);
- pc_jump_false = duk__emit_jump_empty(comp_ctx); /* jump to end or else part */
- DUK__SETTEMP(comp_ctx, temp_reset);
-
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
-
- duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
-
- /* The 'else' ambiguity is resolved by 'else' binding to the innermost
- * construct, so greedy matching is correct here.
- */
-
- if (comp_ctx->curr_token.t == DUK_TOK_ELSE) {
- duk_int_t pc_jump_end;
-
- DUK_DDD(DUK_DDDPRINT("if has else part"));
-
- duk__advance(comp_ctx);
-
- pc_jump_end = duk__emit_jump_empty(comp_ctx); /* jump from true part to end */
- duk__patch_jump_here(comp_ctx, pc_jump_false);
-
- duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
-
- duk__patch_jump_here(comp_ctx, pc_jump_end);
- } else {
- DUK_DDD(DUK_DDDPRINT("if does not have else part"));
-
- duk__patch_jump_here(comp_ctx, pc_jump_false);
- }
-
- DUK_DDD(DUK_DDDPRINT("end parsing if statement"));
-}
-
-DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
- duk_regconst_t rc_cond;
- duk_int_t pc_start;
-
- DUK_DDD(DUK_DDDPRINT("begin parsing do statement"));
-
- duk__advance(comp_ctx); /* eat 'do' */
-
- pc_start = duk__get_current_pc(comp_ctx);
- duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
- duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
-
- duk__advance_expect(comp_ctx, DUK_TOK_WHILE);
- duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
-
- rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
- duk__emit_if_false_skip(comp_ctx, rc_cond);
- duk__emit_jump(comp_ctx, pc_start);
- /* no need to reset temps, as we're finished emitting code */
-
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
-
- duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
-
- DUK_DDD(DUK_DDDPRINT("end parsing do statement"));
-}
-
-DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
- duk_reg_t temp_reset;
- duk_regconst_t rc_cond;
- duk_int_t pc_start;
- duk_int_t pc_jump_false;
-
- DUK_DDD(DUK_DDDPRINT("begin parsing while statement"));
-
- temp_reset = DUK__GETTEMP(comp_ctx);
-
- duk__advance(comp_ctx); /* eat 'while' */
-
- duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
-
- pc_start = duk__get_current_pc(comp_ctx);
- duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
-
- rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
- duk__emit_if_true_skip(comp_ctx, rc_cond);
- pc_jump_false = duk__emit_jump_empty(comp_ctx);
- DUK__SETTEMP(comp_ctx, temp_reset);
-
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
-
- duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
- duk__emit_jump(comp_ctx, pc_start);
-
- duk__patch_jump_here(comp_ctx, pc_jump_false);
- duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
-
- DUK_DDD(DUK_DDDPRINT("end parsing while statement"));
-}
-
-DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_hthread *thr = comp_ctx->thr;
- duk_bool_t is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK);
- duk_int_t label_id;
- duk_int_t label_catch_depth;
- duk_int_t label_pc; /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */
- duk_bool_t label_is_closest;
-
- DUK_UNREF(res);
-
- duk__advance(comp_ctx); /* eat 'break' or 'continue' */
-
- if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
- comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
- comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
- /* break/continue without label */
-
- duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
- } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) {
- /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */
- DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
- duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
- duk__advance(comp_ctx);
- } else {
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL);
- }
-
- /* Use a fast break/continue when possible. A fast break/continue is
- * just a jump to the LABEL break/continue jump slot, which then jumps
- * to an appropriate place (for break, going through ENDLABEL correctly).
- * The peephole optimizer will optimize the jump to a direct one.
- */
-
- if (label_catch_depth == comp_ctx->curr_func.catch_depth &&
- label_is_closest) {
- DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
- "label_catch_depth=%ld, catch_depth=%ld "
- "-> use fast variant (direct jump)",
- (long) is_break, (long) label_id, (long) label_is_closest,
- (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
-
- duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2));
- } else {
- DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
- "label_catch_depth=%ld, catch_depth=%ld "
- "-> use slow variant (longjmp)",
- (long) is_break, (long) label_id, (long) label_is_closest,
- (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
-
- duk__emit_extraop_bc(comp_ctx,
- is_break ? DUK_EXTRAOP_BREAK : DUK_EXTRAOP_CONTINUE,
- (duk_regconst_t) label_id);
- }
-}
-
-DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_hthread *thr = comp_ctx->thr;
- duk_regconst_t rc_val;
- duk_small_uint_t ret_flags;
-
- duk__advance(comp_ctx); /* eat 'return' */
-
- /* A 'return' statement is only allowed inside an actual function body,
- * not as part of eval or global code.
- */
- if (!comp_ctx->curr_func.is_function) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN);
- }
-
- ret_flags = 0;
-
- if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
- comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
- comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
- DUK_DDD(DUK_DDDPRINT("empty return value -> undefined"));
- rc_val = 0;
- } else {
- duk_int_t pc_before_expr;
- duk_int_t pc_after_expr;
-
- DUK_DDD(DUK_DDDPRINT("return with a value"));
-
- DUK_UNREF(pc_before_expr);
- DUK_UNREF(pc_after_expr);
-
- pc_before_expr = duk__get_current_pc(comp_ctx);
- rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
- pc_after_expr = duk__get_current_pc(comp_ctx);
-
- /* Tail call check: if last opcode emitted was CALL(I), and
- * the context allows it, change the CALL(I) to a tail call.
- * This doesn't guarantee that a tail call will be allowed at
- * runtime, so the RETURN must still be emitted. (Duktape
- * 0.10.0 avoided this and simulated a RETURN if a tail call
- * couldn't be used at runtime; but this didn't work
- * correctly with a thread yield/resume, see
- * test-bug-tailcall-thread-yield-resume.js for discussion.)
- *
- * In addition to the last opcode being CALL, we also need to
- * be sure that 'rc_val' is the result register of the CALL(I).
- * For instance, for the expression 'return 0, (function ()
- * { return 1; }), 2' the last opcode emitted is CALL (no
- * bytecode is emitted for '2') but 'rc_val' indicates
- * constant '2'. Similarly if '2' is replaced by a register
- * bound variable, no opcodes are emitted but tail call would
- * be incorrect.
- *
- * This is tricky and easy to get wrong. It would be best to
- * track enough expression metadata to check that 'rc_val' came
- * from that last CALL instruction. We don't have that metadata
- * now, so we check that 'rc_val' is a temporary register result
- * (not a constant or a register bound variable). There should
- * be no way currently for 'rc_val' to be a temporary for an
- * expression following the CALL instruction without emitting
- * some opcodes following the CALL. This proxy check is used
- * below.
- *
- * See: test-bug-comma-expr-gh131.js.
- *
- * The non-standard 'caller' property disables tail calls
- * because they pose some special cases which haven't been
- * fixed yet.
- */
-
-#if defined(DUK_USE_TAILCALL)
- if (comp_ctx->curr_func.catch_depth == 0 && /* no catchers */
- pc_after_expr > pc_before_expr) { /* at least one opcode emitted */
- duk_compiler_instr *instr;
- duk_small_uint_t op;
-
- instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
- DUK_ASSERT(instr != NULL);
-
- op = (duk_small_uint_t) DUK_DEC_OP(instr->ins);
- if ((op == DUK_OP_CALL || op == DUK_OP_CALLI) &&
- DUK__ISTEMP(comp_ctx, rc_val) /* see above */) {
- DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
- "catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
- "and last instruction is a CALL "
- "-> set TAILCALL flag"));
- /* Just flip the single bit. */
- instr->ins |= DUK_ENC_OP_A_B_C(0, DUK_BC_CALL_FLAG_TAILCALL, 0, 0);
- }
- }
-#endif /* DUK_USE_TAILCALL */
-
- ret_flags = DUK_BC_RETURN_FLAG_HAVE_RETVAL;
- }
-
- duk__emit_a_b(comp_ctx,
- DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) ret_flags /*flags*/,
- rc_val /*reg*/);
-}
-
-DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_reg_t reg_val;
-
- duk__advance(comp_ctx); /* eat 'throw' */
-
- /* Unlike break/continue, throw statement does not allow an empty value. */
-
- if (comp_ctx->curr_token.lineterm) {
- DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW);
- }
-
- reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_THROW,
- (duk_regconst_t) reg_val);
-}
-
-DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_reg_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
- duk_regconst_t rc_varname = 0;
- duk_small_uint_t trycatch_flags = 0;
- duk_int_t pc_ldconst = -1;
- duk_int_t pc_trycatch = -1;
- duk_int_t pc_catch = -1;
- duk_int_t pc_finally = -1;
-
- DUK_UNREF(res);
-
- /*
- * See the following documentation for discussion:
- *
- * doc/execution.rst: control flow details
- *
- * Try, catch, and finally "parts" are Blocks, not Statements, so
- * they must always be delimited by curly braces. This is unlike e.g.
- * the if statement, which accepts any Statement. This eliminates any
- * questions of matching parts of nested try statements. The Block
- * parsing is implemented inline here (instead of calling out).
- *
- * Finally part has a 'let scoped' variable, which requires a few kinks
- * here.
- */
-
- comp_ctx->curr_func.catch_depth++;
-
- duk__advance(comp_ctx); /* eat 'try' */
-
- reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
-
- /* The target for this LDCONST may need output shuffling, but we assume
- * that 'pc_ldconst' will be the LDCONST that we can patch later. This
- * should be the case because there's no input shuffling. (If there's
- * no catch clause, this LDCONST will be replaced with a NOP.)
- */
- pc_ldconst = duk__get_current_pc(comp_ctx);
- duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/);
-
- pc_trycatch = duk__get_current_pc(comp_ctx);
- duk__emit_invalid(comp_ctx); /* TRYCATCH, cannot emit now (not enough info) */
- duk__emit_invalid(comp_ctx); /* jump for 'catch' case */
- duk__emit_invalid(comp_ctx); /* jump for 'finally' case or end (if no finally) */
-
- /* try part */
- duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
- duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
- /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_ENDTRY);
-
- if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
- /*
- * The catch variable must be updated to reflect the new allocated
- * register for the duration of the catch clause. We need to store
- * and restore the original value for the varmap entry (if any).
- */
-
- /*
- * Note: currently register bindings must be fixed for the entire
- * function. So, even though the catch variable is in a register
- * we know, we must use an explicit environment record and slow path
- * accesses to read/write the catch binding to make closures created
- * within the catch clause work correctly. This restriction should
- * be fixable (at least in common cases) later.
- *
- * See: test-bug-catch-binding-2.js.
- *
- * XXX: improve to get fast path access to most catch clauses.
- */
-
- duk_hstring *h_var;
- duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */
-
- DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(ctx)));
-
- trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
-
- pc_catch = duk__get_current_pc(comp_ctx);
-
- duk__advance(comp_ctx);
- duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
-
- if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
- /* Identifier, i.e. don't allow reserved words */
- goto syntax_error;
- }
- h_var = comp_ctx->curr_token.str1;
- DUK_ASSERT(h_var != NULL);
-
- duk_push_hstring(ctx, h_var); /* keep in on valstack, use borrowed ref below */
-
- if (comp_ctx->curr_func.is_strict &&
- ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
- (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) {
- DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError"));
- goto syntax_error;
- }
-
- duk_dup_top(ctx);
- rc_varname = duk__getconst(comp_ctx);
- DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
- (unsigned long) rc_varname, (long) rc_varname));
-
- duk__advance(comp_ctx);
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
-
- duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
-
- DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
-
- duk_dup_top(ctx);
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- if (duk_is_undefined(ctx, -1)) {
- varmap_value = -2;
- } else if (duk_is_null(ctx, -1)) {
- varmap_value = -1;
- } else {
- DUK_ASSERT(duk_is_number(ctx, -1));
- varmap_value = duk_get_int(ctx, -1);
- DUK_ASSERT(varmap_value >= 0);
- }
- duk_pop(ctx);
-
-#if 0
- /* It'd be nice to do something like this - but it doesn't
- * work for closures created inside the catch clause.
- */
- duk_dup_top(ctx);
- duk_push_int(ctx, (duk_int_t) (reg_catch + 0));
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
-#endif
- duk_dup_top(ctx);
- duk_push_null(ctx);
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
-
- duk__emit_a_bc(comp_ctx,
- DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
- (duk_regconst_t) (reg_catch + 0) /*value*/,
- rc_varname /*varname*/);
-
- DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
-
- duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
- /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
-
- if (varmap_value == -2) {
- /* not present */
- duk_del_prop(ctx, comp_ctx->curr_func.varmap_idx);
- } else {
- if (varmap_value == -1) {
- duk_push_null(ctx);
- } else {
- DUK_ASSERT(varmap_value >= 0);
- duk_push_int(ctx, varmap_value);
- }
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
- }
- /* varname is popped by above code */
-
- DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
-
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_ENDCATCH);
-
- /*
- * XXX: for now, indicate that an expensive catch binding
- * declarative environment is always needed. If we don't
- * need it, we don't need the const_varname either.
- */
-
- trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
-
- DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(ctx)));
- }
-
- if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
- trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY;
-
- pc_finally = duk__get_current_pc(comp_ctx);
-
- duk__advance(comp_ctx);
-
- duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
- duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
- /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
- duk__emit_extraop_b(comp_ctx,
- DUK_EXTRAOP_ENDFIN,
- reg_catch); /* rethrow */
- }
-
- if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
- !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) {
- /* must have catch and/or finally */
- goto syntax_error;
- }
-
- /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch()
- * will replace the LDCONST with a NOP. For any actual constant (including
- * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname.
- */
-
- duk__patch_trycatch(comp_ctx,
- pc_ldconst,
- pc_trycatch,
- reg_catch,
- rc_varname,
- trycatch_flags);
-
- if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
- DUK_ASSERT(pc_catch >= 0);
- duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch);
- }
-
- if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
- DUK_ASSERT(pc_finally >= 0);
- duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally);
- } else {
- /* without finally, the second jump slot is used to jump to end of stmt */
- duk__patch_jump_here(comp_ctx, pc_trycatch + 2);
- }
-
- comp_ctx->curr_func.catch_depth--;
- return;
-
- syntax_error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY);
-}
-
-DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
- duk_int_t pc_trycatch;
- duk_int_t pc_finished;
- duk_reg_t reg_catch;
- duk_small_uint_t trycatch_flags;
-
- if (comp_ctx->curr_func.is_strict) {
- DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE);
- }
-
- comp_ctx->curr_func.catch_depth++;
-
- duk__advance(comp_ctx); /* eat 'with' */
-
- reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
-
- duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
- duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch);
- duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
-
- pc_trycatch = duk__get_current_pc(comp_ctx);
- trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING;
- duk__emit_a_bc(comp_ctx,
- DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) trycatch_flags /*a*/,
- (duk_regconst_t) reg_catch /*bc*/);
- duk__emit_invalid(comp_ctx); /* catch jump */
- duk__emit_invalid(comp_ctx); /* finished jump */
-
- duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
- duk__emit_extraop_only(comp_ctx,
- DUK_EXTRAOP_ENDTRY);
-
- pc_finished = duk__get_current_pc(comp_ctx);
-
- duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished);
-
- comp_ctx->curr_func.catch_depth--;
-}
-
-DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id) {
- /* if a site already exists, nop: max one label site per statement */
- if (label_id >= 0) {
- return label_id;
- }
-
- label_id = comp_ctx->curr_func.label_next++;
- DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id));
-
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LABEL,
- (duk_regconst_t) label_id);
- duk__emit_invalid(comp_ctx);
- duk__emit_invalid(comp_ctx);
-
- return label_id;
-}
-
-/* Parse a single statement.
- *
- * Creates a label site (with an empty label) automatically for iteration
- * statements. Also "peels off" any label statements for explicit labels.
- */
-DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */
- duk_reg_t temp_at_entry;
- duk_uarridx_t labels_len_at_entry;
- duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */
- duk_int_t stmt_id;
- duk_small_uint_t stmt_flags = 0;
- duk_int_t label_id = -1;
- duk_small_uint_t tok;
-
- DUK__RECURSION_INCREASE(comp_ctx, thr);
-
- temp_at_entry = DUK__GETTEMP(comp_ctx);
- pc_at_entry = duk__get_current_pc(comp_ctx);
- labels_len_at_entry = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.labelnames_idx);
- stmt_id = comp_ctx->curr_func.stmt_next++;
- dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
-
- DUK_UNREF(stmt_id);
-
- DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, "
- "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld",
- (long) stmt_id, (long) temp_at_entry, (long) labels_len_at_entry,
- (long) comp_ctx->curr_func.is_strict, (long) comp_ctx->curr_func.in_directive_prologue,
- (long) comp_ctx->curr_func.catch_depth));
-
- /* The directive prologue flag is cleared by default so that it is
- * unset for any recursive statement parsing. It is only "revived"
- * if a directive is detected. (We could also make directives only
- * allowed if 'allow_source_elem' was true.)
- */
- comp_ctx->curr_func.in_directive_prologue = 0;
-
- retry_parse:
-
- DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld",
- (long) stmt_id, (long) label_id, (long) allow_source_elem,
- (long) comp_ctx->curr_func.catch_depth));
-
- /*
- * Detect iteration statements; if encountered, establish an
- * empty label.
- */
-
- tok = comp_ctx->curr_token.t;
- if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE ||
- tok == DUK_TOK_SWITCH) {
- DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label"));
-
- label_id = duk__stmt_label_site(comp_ctx, label_id);
- duk__add_label(comp_ctx,
- DUK_HTHREAD_STRING_EMPTY_STRING(thr),
- pc_at_entry /*pc_label*/,
- label_id);
- }
-
- /*
- * Main switch for statement / source element type.
- */
-
- switch (comp_ctx->curr_token.t) {
- case DUK_TOK_FUNCTION: {
- /*
- * Function declaration, function expression, or (non-standard)
- * function statement.
- *
- * The E5 specification only allows function declarations at
- * the top level (in "source elements"). An ExpressionStatement
- * is explicitly not allowed to begin with a "function" keyword
- * (E5 Section 12.4). Hence any non-error semantics for such
- * non-top-level statements are non-standard. Duktape semantics
- * for function statements are modelled after V8, see
- * test-dev-func-decl-outside-top.js.
- */
-
-#if defined(DUK_USE_NONSTD_FUNC_STMT)
- /* Lenient: allow function declarations outside top level in
- * non-strict mode but reject them in strict mode.
- */
- if (allow_source_elem || !comp_ctx->curr_func.is_strict)
-#else /* DUK_USE_NONSTD_FUNC_STMT */
- /* Strict: never allow function declarations outside top level. */
- if (allow_source_elem)
-#endif /* DUK_USE_NONSTD_FUNC_STMT */
- {
- /* FunctionDeclaration: not strictly a statement but handled as such.
- *
- * O(depth^2) parse count for inner functions is handled by recording a
- * lexer offset on the first compilation pass, so that the function can
- * be efficiently skipped on the second pass. This is encapsulated into
- * duk__parse_func_like_fnum().
- */
-
- duk_int_t fnum;
-
- DUK_DDD(DUK_DDDPRINT("function declaration statement"));
-
- duk__advance(comp_ctx); /* eat 'function' */
- fnum = duk__parse_func_like_fnum(comp_ctx, 1 /*is_decl*/, 0 /*is_setget*/);
-
- if (comp_ctx->curr_func.in_scanning) {
- duk_uarridx_t n;
- duk_hstring *h_funcname;
-
- duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, fnum * 3);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME); /* -> [ ... func name ] */
- h_funcname = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_funcname != NULL);
-
- DUK_DDD(DUK_DDDPRINT("register function declaration %!O in pass 1, fnum %ld",
- (duk_heaphdr *) h_funcname, (long) fnum));
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
- duk_push_hstring(ctx, h_funcname);
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
- duk_push_int(ctx, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
- duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
-
- duk_pop_n(ctx, 2);
- }
-
- /* no statement value (unlike function expression) */
- stmt_flags = 0;
- break;
- } else {
- DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED);
- }
- break;
- }
- case DUK_TOK_LCURLY: {
- DUK_DDD(DUK_DDDPRINT("block statement"));
- duk__advance(comp_ctx);
- duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
- /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
- if (label_id >= 0) {
- duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
- }
- stmt_flags = 0;
- break;
- }
- case DUK_TOK_CONST: {
- DUK_DDD(DUK_DDDPRINT("constant declaration statement"));
- duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/);
- stmt_flags = DUK__HAS_TERM;
- break;
- }
- case DUK_TOK_VAR: {
- DUK_DDD(DUK_DDDPRINT("variable declaration statement"));
- duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/);
- stmt_flags = DUK__HAS_TERM;
- break;
- }
- case DUK_TOK_SEMICOLON: {
- /* empty statement with an explicit semicolon */
- DUK_DDD(DUK_DDDPRINT("empty statement"));
- stmt_flags = DUK__HAS_TERM;
- break;
- }
- case DUK_TOK_IF: {
- DUK_DDD(DUK_DDDPRINT("if statement"));
- duk__parse_if_stmt(comp_ctx, res);
- if (label_id >= 0) {
- duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
- }
- stmt_flags = 0;
- break;
- }
- case DUK_TOK_DO: {
- /*
- * Do-while statement is mostly trivial, but there is special
- * handling for automatic semicolon handling (triggered by the
- * DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at:
- *
- * https://bugs.ecmascript.org/show_bug.cgi?id=8
- *
- * See doc/compiler.rst for details.
- */
- DUK_DDD(DUK_DDDPRINT("do statement"));
- DUK_ASSERT(label_id >= 0);
- duk__update_label_flags(comp_ctx,
- label_id,
- DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
- duk__parse_do_stmt(comp_ctx, res, pc_at_entry);
- stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS; /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */
- break;
- }
- case DUK_TOK_WHILE: {
- DUK_DDD(DUK_DDDPRINT("while statement"));
- DUK_ASSERT(label_id >= 0);
- duk__update_label_flags(comp_ctx,
- label_id,
- DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
- duk__parse_while_stmt(comp_ctx, res, pc_at_entry);
- stmt_flags = 0;
- break;
- }
- case DUK_TOK_FOR: {
- /*
- * For/for-in statement is complicated to parse because
- * determining the statement type (three-part for vs. a
- * for-in) requires potential backtracking.
- *
- * See the helper for the messy stuff.
- */
- DUK_DDD(DUK_DDDPRINT("for/for-in statement"));
- DUK_ASSERT(label_id >= 0);
- duk__update_label_flags(comp_ctx,
- label_id,
- DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
- duk__parse_for_stmt(comp_ctx, res, pc_at_entry);
- stmt_flags = 0;
- break;
- }
- case DUK_TOK_CONTINUE:
- case DUK_TOK_BREAK: {
- DUK_DDD(DUK_DDDPRINT("break/continue statement"));
- duk__parse_break_or_continue_stmt(comp_ctx, res);
- stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
- break;
- }
- case DUK_TOK_RETURN: {
- DUK_DDD(DUK_DDDPRINT("return statement"));
- duk__parse_return_stmt(comp_ctx, res);
- stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
- break;
- }
- case DUK_TOK_WITH: {
- DUK_DDD(DUK_DDDPRINT("with statement"));
- comp_ctx->curr_func.with_depth++;
- duk__parse_with_stmt(comp_ctx, res);
- if (label_id >= 0) {
- duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
- }
- comp_ctx->curr_func.with_depth--;
- stmt_flags = 0;
- break;
- }
- case DUK_TOK_SWITCH: {
- /*
- * The switch statement is pretty messy to compile.
- * See the helper for details.
- */
- DUK_DDD(DUK_DDDPRINT("switch statement"));
- DUK_ASSERT(label_id >= 0);
- duk__update_label_flags(comp_ctx,
- label_id,
- DUK_LABEL_FLAG_ALLOW_BREAK); /* don't allow continue */
- duk__parse_switch_stmt(comp_ctx, res, pc_at_entry);
- stmt_flags = 0;
- break;
- }
- case DUK_TOK_THROW: {
- DUK_DDD(DUK_DDDPRINT("throw statement"));
- duk__parse_throw_stmt(comp_ctx, res);
- stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
- break;
- }
- case DUK_TOK_TRY: {
- DUK_DDD(DUK_DDDPRINT("try statement"));
- duk__parse_try_stmt(comp_ctx, res);
- stmt_flags = 0;
- break;
- }
- case DUK_TOK_DEBUGGER: {
- duk__advance(comp_ctx);
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode"));
- duk__emit_extraop_only(comp_ctx, DUK_EXTRAOP_DEBUGGER);
-#else
- DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
-#endif
- stmt_flags = DUK__HAS_TERM;
- break;
- }
- default: {
- /*
- * Else, must be one of:
- * - ExpressionStatement, possibly a directive (String)
- * - LabelledStatement (Identifier followed by ':')
- *
- * Expressions beginning with 'function' keyword are covered by a case
- * above (such expressions are not allowed in standard E5 anyway).
- * Also expressions starting with '{' are interpreted as block
- * statements. See E5 Section 12.4.
- *
- * Directive detection is tricky; see E5 Section 14.1 on directive
- * prologue. A directive is an expression statement with a single
- * string literal and an explicit or automatic semicolon. Escape
- * characters are significant and no parens etc are allowed:
- *
- * 'use strict'; // valid 'use strict' directive
- * 'use\u0020strict'; // valid directive, not a 'use strict' directive
- * ('use strict'); // not a valid directive
- *
- * The expression is determined to consist of a single string literal
- * based on duk__expr_nud() and duk__expr_led() call counts. The string literal
- * of a 'use strict' directive is determined to lack any escapes based
- * num_escapes count from the lexer. Note that other directives may be
- * allowed to contain escapes, so a directive with escapes does not
- * terminate a directive prologue.
- *
- * We rely on the fact that the expression parser will not emit any
- * code for a single token expression. However, it will generate an
- * intermediate value which we will then successfully ignore.
- *
- * A similar approach is used for labels.
- */
-
- duk_bool_t single_token;
-
- DUK_DDD(DUK_DDDPRINT("expression statement"));
- duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
-
- single_token = (comp_ctx->curr_func.nud_count == 1 && /* one token */
- comp_ctx->curr_func.led_count == 0); /* no operators */
-
- if (single_token &&
- comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
- comp_ctx->curr_token.t == DUK_TOK_COLON) {
- /*
- * Detected label
- */
-
- duk_hstring *h_lab;
-
- /* expected ival */
- DUK_ASSERT(res->t == DUK_IVAL_VAR);
- DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
- DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
- h_lab = comp_ctx->prev_token.str1;
- DUK_ASSERT(h_lab != NULL);
-
- DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'",
- (duk_heaphdr *) h_lab));
-
- duk__advance(comp_ctx); /* eat colon */
-
- label_id = duk__stmt_label_site(comp_ctx, label_id);
-
- duk__add_label(comp_ctx,
- h_lab,
- pc_at_entry /*pc_label*/,
- label_id);
-
- /* a statement following a label cannot be a source element
- * (a function declaration).
- */
- allow_source_elem = 0;
-
- DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing"));
- goto retry_parse;
- }
-
- stmt_flags = 0;
-
- if (dir_prol_at_entry && /* still in prologue */
- single_token && /* single string token */
- comp_ctx->prev_token.t == DUK_TOK_STRING) {
- /*
- * Detected a directive
- */
- duk_hstring *h_dir;
-
- /* expected ival */
- DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
- DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
- DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
- h_dir = comp_ctx->prev_token.str1;
- DUK_ASSERT(h_dir != NULL);
-
- DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir));
-
- stmt_flags |= DUK__STILL_PROLOGUE;
-
- /* Note: escaped characters differentiate directives */
-
- if (comp_ctx->prev_token.num_escapes > 0) {
- DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive "
- "but we ignore such directives"));
- } else {
- /*
- * The length comparisons are present to handle
- * strings like "use strict\u0000foo" as required.
- */
-
- if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 &&
- DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict", 10) == 0) {
-#if defined(DUK_USE_STRICT_DECL)
- DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld",
- (long) comp_ctx->curr_func.is_strict, (long) 1));
- comp_ctx->curr_func.is_strict = 1;
-#else
- DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring"));
-#endif
- } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 &&
- DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail", 14) == 0) {
- DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld",
- (long) comp_ctx->curr_func.is_notail, (long) 1));
- comp_ctx->curr_func.is_notail = 1;
- } else {
- DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
- "directive prologue", (duk_hobject *) h_dir));
- }
- }
- } else {
- DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
- "prologue terminated if still active"));
- }
-
- stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM;
- }
- } /* end switch (tok) */
-
- /*
- * Statement value handling.
- *
- * Global code and eval code has an implicit return value
- * which comes from the last statement with a value
- * (technically a non-"empty" continuation, which is
- * different from an empty statement).
- *
- * Since we don't know whether a later statement will
- * override the value of the current statement, we need
- * to coerce the statement value to a register allocated
- * for implicit return values. In other cases we need
- * to coerce the statement value to a plain value to get
- * any side effects out (consider e.g. "foo.bar;").
- */
-
- /* XXX: what about statements which leave a half-cooked value in 'res'
- * but have no stmt value? Any such statements?
- */
-
- if (stmt_flags & DUK__HAS_VAL) {
- duk_reg_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
- if (reg_stmt_value >= 0) {
- duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
- } else {
- duk__ivalue_toplain_ignore(comp_ctx, res);
- }
- } else {
- ;
- }
-
- /*
- * Statement terminator check, including automatic semicolon
- * handling. After this step, 'curr_tok' should be the first
- * token after a possible statement terminator.
- */
-
- if (stmt_flags & DUK__HAS_TERM) {
- if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) {
- DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement"));
- duk__advance(comp_ctx);
- } else {
- if (comp_ctx->curr_token.allow_auto_semi) {
- DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement"));
- } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) {
- /* XXX: make this lenience dependent on flags or strictness? */
- DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility "
- "even though no lineterm present before next token)"));
- } else {
- DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT);
- }
- }
- } else {
- DUK_DDD(DUK_DDDPRINT("statement has no terminator"));
- }
-
- /*
- * Directive prologue tracking.
- */
-
- if (stmt_flags & DUK__STILL_PROLOGUE) {
- DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue"));
- comp_ctx->curr_func.in_directive_prologue = 1;
- }
-
- /*
- * Cleanups (all statement parsing flows through here).
- *
- * Pop label site and reset labels. Reset 'next temp' to value at
- * entry to reuse temps.
- */
-
- if (label_id >= 0) {
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_ENDLABEL,
- (duk_regconst_t) label_id);
- }
-
- DUK__SETTEMP(comp_ctx, temp_at_entry);
-
- duk__reset_labels_to_length(comp_ctx, labels_len_at_entry);
-
- /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */
-
- DUK__RECURSION_DECREASE(comp_ctx, thr);
-}
-
-#undef DUK__HAS_VAL
-#undef DUK__HAS_TERM
-#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
-
-/*
- * Parse a statement list.
- *
- * Handles automatic semicolon insertion and implicit return value.
- *
- * Upon entry, 'curr_tok' should contain the first token of the first
- * statement (parsed in the "allow regexp literal" mode). Upon exit,
- * 'curr_tok' contains the token following the statement list terminator
- * (EOF or closing brace).
- */
-
-DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_ivalue res_alloc;
- duk_ivalue *res = &res_alloc;
-
- /* Setup state. Initial ivalue is 'undefined'. */
-
- duk_require_stack(ctx, DUK__PARSE_STATEMENTS_SLOTS);
-
- /* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
- * intermediate values suffice for parsing of each function. Nesting is needed
- * for nested functions (which may occur inside expressions).
- */
-
- DUK_MEMZERO(&res_alloc, sizeof(res_alloc));
- res->t = DUK_IVAL_PLAIN;
- res->x1.t = DUK_ISPEC_VALUE;
- res->x1.valstack_idx = duk_get_top(ctx);
- res->x2.valstack_idx = res->x1.valstack_idx + 1;
- duk_push_undefined(ctx);
- duk_push_undefined(ctx);
-
- /* Parse statements until a closing token (EOF or '}') is found. */
-
- for (;;) {
- /* Check whether statement list ends. */
-
- if (expect_eof) {
- if (comp_ctx->curr_token.t == DUK_TOK_EOF) {
- break;
- }
- } else {
- if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
- break;
- }
- }
-
- /* Check statement type based on the first token type.
- *
- * Note: expression parsing helpers expect 'curr_tok' to
- * contain the first token of the expression upon entry.
- */
-
- DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx->curr_token.t));
-
- duk__parse_stmt(comp_ctx, res, allow_source_elem);
- }
-
- duk__advance(comp_ctx);
-
- /* Tear down state. */
-
- duk_pop_2(ctx);
-}
-
-/*
- * Declaration binding instantiation conceptually happens when calling a
- * function; for us it essentially means that function prologue. The
- * conceptual process is described in E5 Section 10.5.
- *
- * We need to keep track of all encountered identifiers to (1) create an
- * identifier-to-register map ("varmap"); and (2) detect duplicate
- * declarations. Identifiers which are not bound to registers still need
- * to be tracked for detecting duplicates. Currently such identifiers
- * are put into the varmap with a 'null' value, which is later cleaned up.
- *
- * To support functions with a large number of variable and function
- * declarations, registers are not allocated beyond a certain limit;
- * after that limit, variables and functions need slow path access.
- * Arguments are currently always register bound, which imposes a hard
- * (and relatively small) argument count limit.
- *
- * Some bindings in E5 are not configurable (= deletable) and almost all
- * are mutable (writable). Exceptions are:
- *
- * - The 'arguments' binding, established only if no shadowing argument
- * or function declaration exists. We handle 'arguments' creation
- * and binding through an explicit slow path environment record.
- *
- * - The "name" binding for a named function expression. This is also
- * handled through an explicit slow path environment record.
- */
-
-/* XXX: add support for variables to not be register bound always, to
- * handle cases with a very large number of variables?
- */
-
-DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_hstring *h_name;
- duk_bool_t configurable_bindings;
- duk_uarridx_t num_args;
- duk_uarridx_t num_decls;
- duk_regconst_t rc_name;
- duk_small_uint_t declvar_flags;
- duk_uarridx_t i;
-#ifdef DUK_USE_ASSERTIONS
- duk_idx_t entry_top;
-#endif
-
-#ifdef DUK_USE_ASSERTIONS
- entry_top = duk_get_top(ctx);
-#endif
-
- /*
- * Preliminaries
- */
-
- configurable_bindings = comp_ctx->curr_func.is_eval;
- DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings));
-
- /* varmap is already in comp_ctx->curr_func.varmap_idx */
-
- /*
- * Function formal arguments, always bound to registers
- * (there's no support for shuffling them now).
- */
-
- num_args = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
- DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args));
- /* XXX: check num_args */
-
- for (i = 0; i < num_args; i++) {
- duk_get_prop_index(ctx, comp_ctx->curr_func.argnames_idx, i);
- h_name = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_name != NULL);
-
- if (comp_ctx->curr_func.is_strict) {
- if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
- DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
- goto error_argname;
- }
- duk_dup_top(ctx);
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
- DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
- goto error_argname;
- }
-
- /* Ensure argument name is not a reserved word in current
- * (final) strictness. Formal argument parsing may not
- * catch reserved names if strictness changes during
- * parsing.
- *
- * We only need to do this in strict mode because non-strict
- * keyword are always detected in formal argument parsing.
- */
-
- if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) {
- goto error_argname;
- }
- }
-
- /* overwrite any previous binding of the same name; the effect is
- * that last argument of a certain name wins.
- */
-
- /* only functions can have arguments */
- DUK_ASSERT(comp_ctx->curr_func.is_function);
- duk_push_uarridx(ctx, i); /* -> [ ... name index ] */
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
-
- /* no code needs to be emitted, the regs already have values */
- }
-
- /* use temp_next for tracking register allocations */
- DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_reg_t) num_args);
-
- /*
- * After arguments, allocate special registers (like shuffling temps)
- */
-
- if (out_stmt_value_reg) {
- *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
- }
- if (comp_ctx->curr_func.needs_shuffle) {
- duk_reg_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
- comp_ctx->curr_func.shuffle1 = shuffle_base;
- comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
- comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
- DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld",
- (long) comp_ctx->curr_func.shuffle1,
- (long) comp_ctx->curr_func.shuffle2,
- (long) comp_ctx->curr_func.shuffle3));
- }
- if (comp_ctx->curr_func.temp_next > 0x100) {
- DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld", (long) comp_ctx->curr_func.temp_next));
- goto error_outofregs;
- }
-
- /*
- * Function declarations
- */
-
- num_decls = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
- DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
- (long) num_decls,
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.decls_idx)));
- for (i = 0; i < num_decls; i += 2) {
- duk_int_t decl_type;
- duk_int_t fnum;
-
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
- decl_type = duk_to_int(ctx, -1);
- fnum = decl_type >> 8; /* XXX: macros */
- decl_type = decl_type & 0xff;
- duk_pop(ctx);
-
- if (decl_type != DUK_DECL_TYPE_FUNC) {
- continue;
- }
-
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
-
- /* XXX: spilling */
- if (comp_ctx->curr_func.is_function) {
- duk_reg_t reg_bind;
- duk_dup_top(ctx);
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
- /* shadowed; update value */
- duk_dup_top(ctx);
- duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
- reg_bind = duk_to_int(ctx, -1); /* [ ... name reg_bind ] */
- duk__emit_a_bc(comp_ctx,
- DUK_OP_CLOSURE,
- (duk_regconst_t) reg_bind,
- (duk_regconst_t) fnum);
- } else {
- /* function: always register bound */
- reg_bind = DUK__ALLOCTEMP(comp_ctx);
- duk__emit_a_bc(comp_ctx,
- DUK_OP_CLOSURE,
- (duk_regconst_t) reg_bind,
- (duk_regconst_t) fnum);
- duk_push_int(ctx, (duk_int_t) reg_bind);
- }
- } else {
- /* Function declaration for global/eval code is emitted even
- * for duplicates, because of E5 Section 10.5, step 5.e of
- * E5.1 (special behavior for variable bound to global object).
- *
- * DECLVAR will not re-declare a variable as such, but will
- * update the binding value.
- */
-
- duk_reg_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
- duk_dup_top(ctx);
- rc_name = duk__getconst(comp_ctx);
- duk_push_null(ctx);
-
- duk__emit_a_bc(comp_ctx,
- DUK_OP_CLOSURE,
- (duk_regconst_t) reg_temp,
- (duk_regconst_t) fnum);
-
- declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE |
- DUK_BC_DECLVAR_FLAG_FUNC_DECL;
-
- if (configurable_bindings) {
- declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
- }
-
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) declvar_flags /*flags*/,
- rc_name /*name*/,
- (duk_regconst_t) reg_temp /*value*/);
-
- DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */
- }
-
- DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
- }
-
- /*
- * 'arguments' binding is special; if a shadowing argument or
- * function declaration exists, an arguments object will
- * definitely not be needed, regardless of whether the identifier
- * 'arguments' is referenced inside the function body.
- */
-
- if (duk_has_prop_stridx(ctx, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
- DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
- "-> arguments object creation can be skipped"));
- comp_ctx->curr_func.is_arguments_shadowed = 1;
- }
-
- /*
- * Variable declarations.
- *
- * Unlike function declarations, variable declaration values don't get
- * assigned on entry. If a binding of the same name already exists, just
- * ignore it silently.
- */
-
- for (i = 0; i < num_decls; i += 2) {
- duk_int_t decl_type;
-
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
- decl_type = duk_to_int(ctx, -1);
- decl_type = decl_type & 0xff;
- duk_pop(ctx);
-
- if (decl_type != DUK_DECL_TYPE_VAR) {
- continue;
- }
-
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
-
- if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
- /* shadowed, ignore */
- } else {
- duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
- h_name = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_name != NULL);
-
- if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
- !comp_ctx->curr_func.is_arguments_shadowed) {
- /* E5 Section steps 7-8 */
- DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
- "but appears as a variable declaration -> treat as "
- "a no-op for variable declaration purposes"));
- duk_pop(ctx);
- continue;
- }
-
- /* XXX: spilling */
- if (comp_ctx->curr_func.is_function) {
- duk_reg_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
- /* no need to init reg, it will be undefined on entry */
- duk_push_int(ctx, (duk_int_t) reg_bind);
- } else {
- duk_dup_top(ctx);
- rc_name = duk__getconst(comp_ctx);
- duk_push_null(ctx);
-
- declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
- DUK_PROPDESC_FLAG_ENUMERABLE |
- DUK_BC_DECLVAR_FLAG_UNDEF_VALUE;
- if (configurable_bindings) {
- declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
- }
-
- duk__emit_a_b_c(comp_ctx,
- DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) declvar_flags /*flags*/,
- rc_name /*name*/,
- (duk_regconst_t) 0 /*value*/);
- }
-
- duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
- }
- }
-
- /*
- * Wrap up
- */
-
- DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
- (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx),
- (long) comp_ctx->curr_func.is_arguments_shadowed));
-
- DUK_ASSERT_TOP(ctx, entry_top);
- return;
-
- error_outofregs:
- DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT);
- DUK_UNREACHABLE();
- return;
-
- error_argname:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME);
- DUK_UNREACHABLE();
- return;
-}
-
-/*
- * Parse a function-body-like expression (FunctionBody or Program
- * in E5 grammar) using a two-pass parse. The productions appear
- * in the following contexts:
- *
- * - function expression
- * - function statement
- * - function declaration
- * - getter in object literal
- * - setter in object literal
- * - global code
- * - eval code
- * - Function constructor body
- *
- * This function only parses the statement list of the body; the argument
- * list and possible function name must be initialized by the caller.
- * For instance, for Function constructor, the argument names are originally
- * on the value stack. The parsing of statements ends either at an EOF or
- * a closing brace; this is controlled by an input flag.
- *
- * Note that there are many differences affecting parsing and even code
- * generation:
- *
- * - Global and eval code have an implicit return value generated
- * by the last statement; function code does not
- *
- * - Global code, eval code, and Function constructor body end in
- * an EOF, other bodies in a closing brace ('}')
- *
- * Upon entry, 'curr_tok' is ignored and the function will pull in the
- * first token on its own. Upon exit, 'curr_tok' is the terminating
- * token (EOF or closing brace).
- */
-
-DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token) {
- duk_compiler_func *func;
- duk_hthread *thr;
- duk_context *ctx;
- duk_reg_t reg_stmt_value = -1;
- duk_lexer_point lex_pt;
- duk_reg_t temp_first;
- duk_small_int_t compile_round = 1;
-
- DUK_ASSERT(comp_ctx != NULL);
-
- thr = comp_ctx->thr;
- ctx = (duk_context *) thr;
- DUK_ASSERT(thr != NULL);
-
- func = &comp_ctx->curr_func;
- DUK_ASSERT(func != NULL);
-
- DUK__RECURSION_INCREASE(comp_ctx, thr);
-
- duk_require_stack(ctx, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
-
- /*
- * Store lexer position for a later rewind
- */
-
- DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt);
-
- /*
- * Program code (global and eval code) has an implicit return value
- * from the last statement value (e.g. eval("1; 2+3;") returns 3).
- * This is not the case with functions. If implicit statement return
- * value is requested, all statements are coerced to a register
- * allocated here, and used in the implicit return statement below.
- */
-
- /* XXX: this is pointless here because pass 1 is throw-away */
- if (implicit_return_value) {
- reg_stmt_value = DUK__ALLOCTEMP(comp_ctx);
-
- /* If an implicit return value is needed by caller, it must be
- * initialized to 'undefined' because we don't know whether any
- * non-empty (where "empty" is a continuation type, and different
- * from an empty statement) statements will be executed.
- *
- * However, since 1st pass is a throwaway one, no need to emit
- * it here.
- */
-#if 0
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LDUNDEF,
- 0);
-#endif
- }
-
- /*
- * First pass.
- *
- * Gather variable/function declarations needed for second pass.
- * Code generated is dummy and discarded.
- */
-
- func->in_directive_prologue = 1;
- func->in_scanning = 1;
- func->may_direct_eval = 0;
- func->id_access_arguments = 0;
- func->id_access_slow = 0;
- func->reg_stmt_value = reg_stmt_value;
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- func->min_line = DUK_INT_MAX;
- func->max_line = 0;
-#endif
-
- /* duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp literal" mode with current strictness */
- if (expect_token >= 0) {
- /* Eating a left curly; regexp mode is allowed by left curly
- * based on duk__token_lbp[] automatically.
- */
- DUK_ASSERT(expect_token == DUK_TOK_LCURLY);
- duk__update_lineinfo_currtoken(comp_ctx);
- duk__advance_expect(comp_ctx, expect_token);
- } else {
- /* Need to set curr_token.t because lexing regexp mode depends on current
- * token type. Zero value causes "allow regexp" mode.
- */
- comp_ctx->curr_token.t = 0;
- duk__advance(comp_ctx);
- }
-
- DUK_DDD(DUK_DDDPRINT("begin 1st pass"));
- duk__parse_stmts(comp_ctx,
- 1, /* allow source elements */
- expect_eof); /* expect EOF instead of } */
- DUK_DDD(DUK_DDDPRINT("end 1st pass"));
-
- /*
- * Second (and possibly third) pass.
- *
- * Generate actual code. In most cases the need for shuffle
- * registers is detected during pass 1, but in some corner cases
- * we'll only detect it during pass 2 and a third pass is then
- * needed (see GH-115).
- */
-
- for (;;) {
- duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle;
- compile_round++;
-
- /*
- * Rewind lexer.
- *
- * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
- * literal" mode with current strictness.
- *
- * curr_token line number info should be initialized for pass 2 before
- * generating prologue, to ensure prologue bytecode gets nice line numbers.
- */
-
- DUK_DDD(DUK_DDDPRINT("rewind lexer"));
- DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
- comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
- comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
- duk__advance(comp_ctx);
-
- /*
- * Reset function state and perform register allocation, which creates
- * 'varmap' for second pass. Function prologue for variable declarations,
- * binding value initializations etc is emitted as a by-product.
- *
- * Strict mode restrictions for duplicate and invalid argument
- * names are checked here now that we know whether the function
- * is actually strict. See: test-dev-strict-mode-boundary.js.
- *
- * Inner functions are compiled during pass 1 and are not reset.
- */
-
- duk__reset_func_for_pass2(comp_ctx);
- func->in_directive_prologue = 1;
- func->in_scanning = 0;
-
- /* must be able to emit code, alloc consts, etc. */
-
- duk__init_varmap_and_prologue_for_pass2(comp_ctx,
- (implicit_return_value ? &reg_stmt_value : NULL));
- func->reg_stmt_value = reg_stmt_value;
-
- temp_first = DUK__GETTEMP(comp_ctx);
-
- func->temp_first = temp_first;
- func->temp_next = temp_first;
- func->stmt_next = 0;
- func->label_next = 0;
-
- /* XXX: init or assert catch depth etc -- all values */
- func->id_access_arguments = 0;
- func->id_access_slow = 0;
-
- /*
- * Check function name validity now that we know strictness.
- * This only applies to function declarations and expressions,
- * not setter/getter name.
- *
- * See: test-dev-strict-mode-boundary.js
- */
-
- if (func->is_function && !func->is_setget && func->h_name != NULL) {
- if (func->is_strict) {
- if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) {
- DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode"));
- goto error_funcname;
- }
- if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
- DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode"));
- goto error_funcname;
- }
- } else {
- if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) &&
- !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
- DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode"));
- goto error_funcname;
- }
- }
- }
-
- /*
- * Second pass parsing.
- */
-
- if (implicit_return_value) {
- /* Default implicit return value. */
- duk__emit_extraop_bc(comp_ctx,
- DUK_EXTRAOP_LDUNDEF,
- 0);
- }
-
- DUK_DDD(DUK_DDDPRINT("begin 2nd pass"));
- duk__parse_stmts(comp_ctx,
- 1, /* allow source elements */
- expect_eof); /* expect EOF instead of } */
- DUK_DDD(DUK_DDDPRINT("end 2nd pass"));
-
- duk__update_lineinfo_currtoken(comp_ctx);
-
- if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) {
- /* Shuffle decision not changed. */
- break;
- }
- if (compile_round >= 3) {
- /* Should never happen but avoid infinite loop just in case. */
- DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen"));
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- }
- DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round));
- }
-
- /*
- * Emit a final RETURN.
- *
- * It would be nice to avoid emitting an unnecessary "return" opcode
- * if the current PC is not reachable. However, this cannot be reliably
- * detected; even if the previous instruction is an unconditional jump,
- * there may be a previous jump which jumps to current PC (which is the
- * case for iteration and conditional statements, for instance).
- */
-
- /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts();
- * we could avoid the last RETURN if we could ensure there is no way to get here
- * (directly or via a jump)
- */
-
- DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);
- if (reg_stmt_value >= 0) {
- duk__emit_a_b(comp_ctx,
- DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) DUK_BC_RETURN_FLAG_HAVE_RETVAL /*flags*/,
- (duk_regconst_t) reg_stmt_value /*reg*/);
- } else {
- duk__emit_a_b(comp_ctx,
- DUK_OP_RETURN | DUK__EMIT_FLAG_NO_SHUFFLE_A,
- (duk_regconst_t) 0 /*flags*/,
- (duk_regconst_t) 0 /*reg(ignored)*/);
- }
-
- /*
- * Peephole optimize JUMP chains.
- */
-
- duk__peephole_optimize_bytecode(comp_ctx);
-
- /*
- * comp_ctx->curr_func is now ready to be converted into an actual
- * function template.
- */
-
- DUK__RECURSION_DECREASE(comp_ctx, thr);
- return;
-
- error_funcname:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME);
-}
-
-/*
- * Parse a function-like expression:
- *
- * - function expression
- * - function declaration
- * - function statement (non-standard)
- * - setter/getter
- *
- * Adds the function to comp_ctx->curr_func function table and returns the
- * function number.
- *
- * On entry, curr_token points to:
- *
- * - the token after 'function' for function expression/declaration/statement
- * - the token after 'set' or 'get' for setter/getter
- */
-
-/* Parse formals. */
-DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t first = 1;
- duk_uarridx_t n;
-
- for (;;) {
- if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
- break;
- }
-
- if (first) {
- /* no comma */
- first = 0;
- } else {
- duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
- }
-
- /* Note: when parsing a formal list in non-strict context, e.g.
- * "implements" is parsed as an identifier. When the function is
- * later detected to be strict, the argument list must be rechecked
- * against a larger set of reserved words (that of strict mode).
- * This is handled by duk__parse_func_body(). Here we recognize
- * whatever tokens are considered reserved in current strictness
- * (which is not always enough).
- */
-
- if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
- DUK_ERROR_SYNTAX(thr, "expected identifier");
- }
- DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
- DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
- DUK_DDD(DUK_DDDPRINT("formal argument: %!O",
- (duk_heaphdr *) comp_ctx->curr_token.str1));
-
- /* XXX: append primitive */
- duk_push_hstring(ctx, comp_ctx->curr_token.str1);
- n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
- duk_put_prop_index(ctx, comp_ctx->curr_func.argnames_idx, n);
-
- duk__advance(comp_ctx); /* eat identifier */
- }
-}
-
-/* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is
- * correctly set up. Assumes that curr_token is just after 'function' (or
- * 'set'/'get' etc).
- */
-DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
-
- DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
- DUK_ASSERT(comp_ctx->curr_func.is_function == 1);
- DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
- DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
- DUK_ASSERT(comp_ctx->curr_func.is_setget == is_setget);
- DUK_ASSERT(comp_ctx->curr_func.is_decl == is_decl);
-
- duk__update_lineinfo_currtoken(comp_ctx);
-
- /*
- * Function name (if any)
- *
- * We don't check for prohibited names here, because we don't
- * yet know whether the function will be strict. Function body
- * parsing handles this retroactively.
- *
- * For function expressions and declarations function name must
- * be an Identifer (excludes reserved words). For setter/getter
- * it is a PropertyName which allows reserved words and also
- * strings and numbers (e.g. "{ get 1() { ... } }").
- */
-
- if (is_setget) {
- /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
- if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER ||
- comp_ctx->curr_token.t == DUK_TOK_STRING) {
- duk_push_hstring(ctx, comp_ctx->curr_token.str1); /* keep in valstack */
- } else if (comp_ctx->curr_token.t == DUK_TOK_NUMBER) {
- duk_push_number(ctx, comp_ctx->curr_token.num);
- duk_to_string(ctx, -1);
- } else {
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
- }
- comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1); /* borrowed reference */
- DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
- duk__advance(comp_ctx);
- } else {
- /* Function name is an Identifier (not IdentifierName), but we get
- * the raw name (not recognizing keywords) here and perform the name
- * checks only after pass 1.
- */
- if (comp_ctx->curr_token.t_nores == DUK_TOK_IDENTIFIER) {
- duk_push_hstring(ctx, comp_ctx->curr_token.str1); /* keep in valstack */
- comp_ctx->curr_func.h_name = duk_get_hstring(ctx, -1); /* borrowed reference */
- DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
- duk__advance(comp_ctx);
- } else {
- /* valstack will be unbalanced, which is OK */
- DUK_ASSERT(!is_setget);
- if (is_decl) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED);
- }
- }
- }
-
- DUK_DDD(DUK_DDDPRINT("function name: %!O",
- (duk_heaphdr *) comp_ctx->curr_func.h_name));
-
- /*
- * Formal argument list
- *
- * We don't check for prohibited names or for duplicate argument
- * names here, becase we don't yet know whether the function will
- * be strict. Function body parsing handles this retroactively.
- */
-
- duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
-
- duk__parse_func_formals(comp_ctx);
-
- DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN);
- duk__advance(comp_ctx);
-
- /*
- * Parse function body
- */
-
- duk__parse_func_body(comp_ctx,
- 0, /* expect_eof */
- 0, /* implicit_return_value */
- DUK_TOK_LCURLY); /* expect_token */
-
- /*
- * Convert duk_compiler_func to a function template and add it
- * to the parent function table.
- */
-
- duk__convert_to_func_template(comp_ctx, is_setget /*force_no_namebind*/); /* -> [ ... func ] */
-}
-
-/* Parse an inner function, adding the function template to the current function's
- * function table. Return a function number to be used by the outer function.
- *
- * Avoiding O(depth^2) inner function parsing is handled here. On the first pass,
- * compile and register the function normally into the 'funcs' array, also recording
- * a lexer point (offset/line) to the closing brace of the function. On the second
- * pass, skip the function and return the same 'fnum' as on the first pass by using
- * a running counter.
- *
- * An unfortunate side effect of this is that when parsing the inner function, almost
- * nothing is known of the outer function, i.e. the inner function's scope. We don't
- * need that information at the moment, but it would allow some optimizations if it
- * were used.
- */
-DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_bool_t is_decl, duk_bool_t is_setget) {
- duk_hthread *thr = comp_ctx->thr;
- duk_context *ctx = (duk_context *) thr;
- duk_compiler_func old_func;
- duk_idx_t entry_top;
- duk_int_t fnum;
-
- /*
- * On second pass, skip the function.
- */
-
- if (!comp_ctx->curr_func.in_scanning) {
- duk_lexer_point lex_pt;
-
- fnum = comp_ctx->curr_func.fnum_next++;
- duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
- lex_pt.offset = duk_to_int(ctx, -1);
- duk_pop(ctx);
- duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
- lex_pt.line = duk_to_int(ctx, -1);
- duk_pop(ctx);
-
- DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
- (long) lex_pt.offset, (long) lex_pt.line));
-
- DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
- comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
- comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
- duk__advance(comp_ctx);
- duk__advance_expect(comp_ctx, DUK_TOK_RCURLY);
-
- return fnum;
- }
-
- /*
- * On first pass, perform actual parsing. Remember valstack top on entry
- * to restore it later, and switch to using a new function in comp_ctx.
- */
-
- entry_top = duk_get_top(ctx);
- DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
- (long) entry_top, (long) comp_ctx->curr_token.start_offset));
-
- DUK_MEMCPY(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func));
-
- DUK_MEMZERO(&comp_ctx->curr_func, sizeof(duk_compiler_func));
- duk__init_func_valstack_slots(comp_ctx);
- DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
-
- /* inherit initial strictness from parent */
- comp_ctx->curr_func.is_strict = old_func.is_strict;
-
- DUK_ASSERT(comp_ctx->curr_func.is_notail == 0);
- comp_ctx->curr_func.is_function = 1;
- DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
- DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
- comp_ctx->curr_func.is_setget = is_setget;
- comp_ctx->curr_func.is_decl = is_decl;
-
- /*
- * Parse inner function
- */
-
- duk__parse_func_like_raw(comp_ctx, is_decl, is_setget); /* pushes function template */
-
- /* prev_token.start_offset points to the closing brace here; when skipping
- * we're going to reparse the closing brace to ensure semicolon insertion
- * etc work as expected.
- */
- DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld",
- (long) comp_ctx->prev_token.start_offset, (long) comp_ctx->curr_token.start_offset));
- DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY);
-
- /* XXX: append primitive */
- DUK_ASSERT(duk_get_length(ctx, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
- fnum = old_func.fnum_next++;
-
- if (fnum > DUK__MAX_FUNCS) {
- DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT);
- }
-
- /* array writes autoincrement length */
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
- duk_push_size_t(ctx, comp_ctx->prev_token.start_offset);
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
- duk_push_int(ctx, comp_ctx->prev_token.start_line);
- (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
-
- /*
- * Cleanup: restore original function, restore valstack state.
- */
-
- DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
- duk_set_top(ctx, entry_top);
-
- DUK_ASSERT_TOP(ctx, entry_top);
-
- return fnum;
-}
-
-/*
- * Compile input string into an executable function template without
- * arguments.
- *
- * The string is parsed as the "Program" production of Ecmascript E5.
- * Compilation context can be either global code or eval code (see E5
- * Sections 14 and 15.1.2.1).
- *
- * Input stack: [ ... filename ]
- * Output stack: [ ... func_template ]
- */
-
-/* XXX: source code property */
-
-DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk_hstring *h_filename;
- duk__compiler_stkstate *comp_stk;
- duk_compiler_ctx *comp_ctx;
- duk_lexer_point *lex_pt;
- duk_compiler_func *func;
- duk_idx_t entry_top;
- duk_bool_t is_strict;
- duk_bool_t is_eval;
- duk_bool_t is_funcexpr;
- duk_small_uint_t flags;
-
- DUK_ASSERT(thr != NULL);
-
- /*
- * Arguments check
- */
-
- entry_top = duk_get_top(ctx);
- DUK_ASSERT(entry_top >= 2);
-
- comp_stk = (duk__compiler_stkstate *) duk_require_pointer(ctx, -1);
- comp_ctx = &comp_stk->comp_ctx_alloc;
- lex_pt = &comp_stk->lex_pt_alloc;
- DUK_ASSERT(comp_ctx != NULL);
- DUK_ASSERT(lex_pt != NULL);
-
- flags = comp_stk->flags;
- is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0);
- is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0);
- is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0);
-
- h_filename = duk_get_hstring(ctx, -2); /* may be undefined */
-
- /*
- * Init compiler and lexer contexts
- */
-
- func = &comp_ctx->curr_func;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- comp_ctx->thr = NULL;
- comp_ctx->h_filename = NULL;
- comp_ctx->prev_token.str1 = NULL;
- comp_ctx->prev_token.str2 = NULL;
- comp_ctx->curr_token.str1 = NULL;
- comp_ctx->curr_token.str2 = NULL;
-#endif
-
- duk_require_stack(ctx, DUK__COMPILE_ENTRY_SLOTS);
-
- duk_push_dynamic_buffer(ctx, 0); /* entry_top + 0 */
- duk_push_undefined(ctx); /* entry_top + 1 */
- duk_push_undefined(ctx); /* entry_top + 2 */
- duk_push_undefined(ctx); /* entry_top + 3 */
- duk_push_undefined(ctx); /* entry_top + 4 */
-
- comp_ctx->thr = thr;
- comp_ctx->h_filename = h_filename;
- comp_ctx->tok11_idx = entry_top + 1;
- comp_ctx->tok12_idx = entry_top + 2;
- comp_ctx->tok21_idx = entry_top + 3;
- comp_ctx->tok22_idx = entry_top + 4;
- comp_ctx->recursion_limit = DUK_USE_COMPILER_RECLIMIT;
-
- /* comp_ctx->lex has been pre-initialized by caller: it has been
- * zeroed and input/input_length has been set.
- */
- comp_ctx->lex.thr = thr;
- /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */
- comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
- comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
- comp_ctx->lex.buf_idx = entry_top + 0;
- comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, entry_top + 0);
- DUK_ASSERT(comp_ctx->lex.buf != NULL);
- DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf));
- comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
-
- lex_pt->offset = 0;
- lex_pt->line = 1;
- DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt); /* fills window */
- comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
-
- /*
- * Initialize function state for a zero-argument function
- */
-
- duk__init_func_valstack_slots(comp_ctx);
- DUK_ASSERT(func->num_formals == 0);
-
- if (is_funcexpr) {
- /* Name will be filled from function expression, not by caller.
- * This case is used by Function constructor and duk_compile()
- * API with the DUK_COMPILE_FUNCTION option.
- */
- DUK_ASSERT(func->h_name == NULL);
- } else {
- duk_push_hstring_stridx(ctx, (is_eval ? DUK_STRIDX_EVAL :
- DUK_STRIDX_GLOBAL));
- func->h_name = duk_get_hstring(ctx, -1);
- }
-
- /*
- * Parse a function body or a function-like expression, depending
- * on flags.
- */
-
- func->is_strict = is_strict;
- func->is_setget = 0;
- func->is_decl = 0;
-
- if (is_funcexpr) {
- func->is_function = 1;
- func->is_eval = 0;
- func->is_global = 0;
-
- duk__advance(comp_ctx); /* init 'curr_token' */
- duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION);
- (void) duk__parse_func_like_raw(comp_ctx,
- 0, /* is_decl */
- 0); /* is_setget */
- } else {
- func->is_function = 0;
- func->is_eval = is_eval;
- func->is_global = !is_eval;
-
- duk__parse_func_body(comp_ctx,
- 1, /* expect_eof */
- 1, /* implicit_return_value */
- -1); /* expect_token */
- }
-
- /*
- * Convert duk_compiler_func to a function template
- */
-
- duk__convert_to_func_template(comp_ctx, 0 /*force_no_namebind*/);
-
- /*
- * Wrapping duk_safe_call() will mangle the stack, just return stack top
- */
-
- /* [ ... filename (temps) func ] */
-
- return 1;
-}
-
-DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) {
- duk_context *ctx = (duk_context *) thr;
- duk__compiler_stkstate comp_stk;
- duk_compiler_ctx *prev_ctx;
- duk_ret_t safe_rc;
-
- /* XXX: this illustrates that a C catchpoint implemented using duk_safe_call()
- * is a bit heavy at the moment. The wrapper compiles to ~180 bytes on x64.
- * Alternatives would be nice.
- */
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(src_buffer != NULL);
-
- /* preinitialize lexer state partially */
- DUK_MEMZERO(&comp_stk, sizeof(comp_stk));
- comp_stk.flags = flags;
- DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex);
- comp_stk.comp_ctx_alloc.lex.input = src_buffer;
- comp_stk.comp_ctx_alloc.lex.input_length = src_length;
-
- duk_push_pointer(ctx, (void *) &comp_stk);
-
- /* [ ... filename &comp_stk ] */
-
- prev_ctx = thr->compile_ctx;
- thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */
- safe_rc = duk_safe_call(ctx, duk__js_compile_raw, 2 /*nargs*/, 1 /*nret*/);
- thr->compile_ctx = prev_ctx; /* must restore reliably before returning */
-
- if (safe_rc != DUK_EXEC_SUCCESS) {
- duk_throw(ctx);
- }
-
- /* [ ... template ] */
-}
-#line 1 "duk_js_executor.c"
-/*
- * Ecmascript bytecode executor.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Local declarations.
- */
-
-DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top);
-
-/*
- * Arithmetic, binary, and logical helpers.
- *
- * Note: there is no opcode for logical AND or logical OR; this is on
- * purpose, because the evalution order semantics for them make such
- * opcodes pretty pointless: short circuiting means they are most
- * comfortably implemented as jumps. However, a logical NOT opcode
- * is useful.
- *
- * Note: careful with duk_tval pointers here: they are potentially
- * invalidated by any DECREF and almost any API call. It's still
- * preferable to work without making a copy but that's not always
- * possible.
- */
-
-DUK_LOCAL duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) {
- /*
- * Ecmascript modulus ('%') does not match IEEE 754 "remainder"
- * operation (implemented by remainder() in C99) but does seem
- * to match ANSI C fmod().
- *
- * Compare E5 Section 11.5.3 and "man fmod".
- */
-
- return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
-}
-
-DUK_LOCAL void duk__vm_arith_add(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z) {
- /*
- * Addition operator is different from other arithmetic
- * operations in that it also provides string concatenation.
- * Hence it is implemented separately.
- *
- * There is a fast path for number addition. Other cases go
- * through potentially multiple coercions as described in the
- * E5 specification. It may be possible to reduce the number
- * of coercions, but this must be done carefully to preserve
- * the exact semantics.
- *
- * E5 Section 11.6.1.
- *
- * Custom types also have special behavior implemented here.
- */
-
- duk_context *ctx = (duk_context *) thr;
- duk_double_union du;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(tv_x != NULL); /* may be reg or const */
- DUK_ASSERT(tv_y != NULL); /* may be reg or const */
- DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
-
- /*
- * Fast paths
- */
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
- duk_int64_t v1, v2, v3;
- duk_int32_t v3_hi;
- duk_tval *tv_z;
-
- /* Input values are signed 48-bit so we can detect overflow
- * reliably from high bits or just a comparison.
- */
-
- v1 = DUK_TVAL_GET_FASTINT(tv_x);
- v2 = DUK_TVAL_GET_FASTINT(tv_y);
- v3 = v1 + v2;
- v3_hi = (duk_int32_t) (v3 >> 32);
- if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
- return;
- } else {
- /* overflow, fall through */
- ;
- }
- }
-#endif /* DUK_USE_FASTINT */
-
- if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
- duk_tval *tv_z;
-
- du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
-
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
- return;
- }
-
- /*
- * Slow path: potentially requires function calls for coercion
- */
-
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
- duk_to_primitive(ctx, -1, DUK_HINT_NONE);
-
- /* As a first approximation, buffer values are coerced to strings
- * for addition. This means that adding two buffers currently
- * results in a string.
- */
- if (duk_check_type_mask(ctx, -2, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER) ||
- duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_BUFFER)) {
- duk_to_string(ctx, -2);
- duk_to_string(ctx, -1);
- duk_concat(ctx, 2); /* [... s1 s2] -> [... s1+s2] */
- duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
- } else {
- duk_double_t d1, d2;
-
- d1 = duk_to_number(ctx, -2);
- d2 = duk_to_number(ctx, -1);
- DUK_ASSERT(duk_is_number(ctx, -2));
- DUK_ASSERT(duk_is_number(ctx, -1));
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
-
- du.d = d1 + d2;
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
-
- duk_pop_2(ctx);
- duk_push_number(ctx, du.d);
- duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
- }
-}
-
-DUK_LOCAL void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_idx_t idx_z, duk_small_uint_fast_t opcode) {
- /*
- * Arithmetic operations other than '+' have number-only semantics
- * and are implemented here. The separate switch-case here means a
- * "double dispatch" of the arithmetic opcode, but saves code space.
- *
- * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
- */
-
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_z;
- duk_double_t d1, d2;
- duk_double_union du;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(tv_x != NULL); /* may be reg or const */
- DUK_ASSERT(tv_y != NULL); /* may be reg or const */
- DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
- duk_int64_t v1, v2, v3;
- duk_int32_t v3_hi;
-
- v1 = DUK_TVAL_GET_FASTINT(tv_x);
- v2 = DUK_TVAL_GET_FASTINT(tv_y);
-
- switch (opcode) {
- case DUK_OP_SUB: {
- v3 = v1 - v2;
- break;
- }
- case DUK_OP_MUL: {
- /* Must ensure result is 64-bit (no overflow); a
- * simple and sufficient fast path is to allow only
- * 32-bit inputs. Avoid zero inputs to avoid
- * negative zero issues (-1 * 0 = -0, for instance).
- */
- if (v1 >= -0x80000000LL && v1 <= 0x7fffffffLL && v1 != 0 &&
- v2 >= -0x80000000LL && v2 <= 0x7fffffffLL && v2 != 0) {
- v3 = v1 * v2;
- } else {
- goto skip_fastint;
- }
- break;
- }
- case DUK_OP_DIV: {
- /* Don't allow a zero divisor. Fast path check by
- * "verifying" with multiplication. Also avoid zero
- * dividend to avoid negative zero issues (0 / -1 = -0
- * for instance).
- */
- if (v1 == 0 || v2 == 0) {
- goto skip_fastint;
- }
- v3 = v1 / v2;
- if (v3 * v2 != v1) {
- goto skip_fastint;
- }
- break;
- }
- case DUK_OP_MOD: {
- /* Don't allow a zero divisor. Restrict both v1 and
- * v2 to positive values to avoid compiler specific
- * behavior.
- */
- if (v1 < 1 || v2 < 1) {
- goto skip_fastint;
- }
- v3 = v1 % v2;
- DUK_ASSERT(v3 >= 0);
- DUK_ASSERT(v3 < v2);
- DUK_ASSERT(v1 - (v1 / v2) * v2 == v3);
- break;
- }
- default: {
- DUK_UNREACHABLE();
- goto skip_fastint;
- }
- }
-
- v3_hi = (duk_int32_t) (v3 >> 32);
- if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
- return;
- }
- /* fall through if overflow etc */
- }
- skip_fastint:
-#endif /* DUK_USE_FASTINT */
-
- if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
- /* fast path */
- d1 = DUK_TVAL_GET_NUMBER(tv_x);
- d2 = DUK_TVAL_GET_NUMBER(tv_y);
- } else {
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- d1 = duk_to_number(ctx, -2); /* side effects */
- d2 = duk_to_number(ctx, -1);
- DUK_ASSERT(duk_is_number(ctx, -2));
- DUK_ASSERT(duk_is_number(ctx, -1));
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
- duk_pop_2(ctx);
- }
-
- switch (opcode) {
- case DUK_OP_SUB: {
- du.d = d1 - d2;
- break;
- }
- case DUK_OP_MUL: {
- du.d = d1 * d2;
- break;
- }
- case DUK_OP_DIV: {
- du.d = d1 / d2;
- break;
- }
- case DUK_OP_MOD: {
- du.d = duk__compute_mod(d1, d2);
- break;
- }
- default: {
- DUK_UNREACHABLE();
- du.d = DUK_DOUBLE_NAN; /* should not happen */
- break;
- }
- }
-
- /* important to use normalized NaN with 8-byte tagged types */
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
-
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
-}
-
-DUK_LOCAL void duk__vm_bitwise_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_uint_fast_t idx_z, duk_small_uint_fast_t opcode) {
- /*
- * Binary bitwise operations use different coercions (ToInt32, ToUint32)
- * depending on the operation. We coerce the arguments first using
- * ToInt32(), and then cast to an 32-bit value if necessary. Note that
- * such casts must be correct even if there is no native 32-bit type
- * (e.g., duk_int32_t and duk_uint32_t are 64-bit).
- *
- * E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
- */
-
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_z;
- duk_int32_t i1, i2, i3;
- duk_uint32_t u1, u2, u3;
-#if defined(DUK_USE_FASTINT)
- duk_int64_t fi3;
-#else
- duk_double_t d3;
-#endif
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(tv_x != NULL); /* may be reg or const */
- DUK_ASSERT(tv_y != NULL); /* may be reg or const */
- DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
- i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
- i2 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_y);
- }
- else
-#endif /* DUK_USE_FASTINT */
- {
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- i1 = duk_to_int32(ctx, -2);
- i2 = duk_to_int32(ctx, -1);
- duk_pop_2(ctx);
- }
-
- switch (opcode) {
- case DUK_OP_BAND: {
- i3 = i1 & i2;
- break;
- }
- case DUK_OP_BOR: {
- i3 = i1 | i2;
- break;
- }
- case DUK_OP_BXOR: {
- i3 = i1 ^ i2;
- break;
- }
- case DUK_OP_BASL: {
- /* Signed shift, named "arithmetic" (asl) because the result
- * is signed, e.g. 4294967295 << 1 -> -2. Note that result
- * must be masked.
- */
-
- u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
- i3 = i1 << (u2 & 0x1f); /* E5 Section 11.7.1, steps 7 and 8 */
- i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */
- break;
- }
- case DUK_OP_BASR: {
- /* signed shift */
-
- u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
- i3 = i1 >> (u2 & 0x1f); /* E5 Section 11.7.2, steps 7 and 8 */
- break;
- }
- case DUK_OP_BLSR: {
- /* unsigned shift */
-
- u1 = ((duk_uint32_t) i1) & 0xffffffffUL;
- u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
-
- /* special result value handling */
- u3 = u1 >> (u2 & 0x1f); /* E5 Section 11.7.2, steps 7 and 8 */
-#if defined(DUK_USE_FASTINT)
- fi3 = (duk_int64_t) u3;
- goto fastint_result_set;
-#else
- d3 = (duk_double_t) u3;
- goto result_set;
-#endif
- }
- default: {
- DUK_UNREACHABLE();
- i3 = 0; /* should not happen */
- break;
- }
- }
-
-#if defined(DUK_USE_FASTINT)
- /* Result is always fastint compatible. */
- /* XXX: Set 32-bit result (but must then handle signed and
- * unsigned results separately).
- */
- fi3 = (duk_int64_t) i3;
-
- fastint_result_set:
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3); /* side effects */
-#else
- d3 = (duk_double_t) i3;
-
- result_set:
- DUK_ASSERT(!DUK_ISNAN(d3)); /* 'd3' is never NaN, so no need to normalize */
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */
-
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */
-#endif
-}
-
-/* In-place unary operation. */
-DUK_LOCAL void duk__vm_arith_unary_op(duk_hthread *thr, duk_tval *tv_x, duk_idx_t idx_x, duk_small_uint_fast_t opcode) {
- /*
- * Arithmetic operations other than '+' have number-only semantics
- * and are implemented here. The separate switch-case here means a
- * "double dispatch" of the arithmetic opcode, but saves code space.
- *
- * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
- */
-
- duk_context *ctx = (duk_context *) thr;
- duk_double_t d1;
- duk_double_union du;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(opcode == DUK_EXTRAOP_UNM || opcode == DUK_EXTRAOP_UNP);
- DUK_ASSERT(tv_x != NULL);
- DUK_ASSERT(idx_x >= 0);
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x)) {
- duk_int64_t v1, v2;
-
- v1 = DUK_TVAL_GET_FASTINT(tv_x);
- if (opcode == DUK_EXTRAOP_UNM) {
- /* The smallest fastint is no longer 48-bit when
- * negated. Positive zero becames negative zero
- * (cannot be represented) when negated.
- */
- if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) {
- v2 = -v1;
- DUK_TVAL_SET_FASTINT(tv_x, v2); /* no refcount changes */
- return;
- }
- } else {
- /* ToNumber() for a fastint is a no-op. */
- DUK_ASSERT(opcode == DUK_EXTRAOP_UNP);
- return;
- }
- /* fall through if overflow etc */
- }
-#endif /* DUK_USE_FASTINT */
-
- if (!DUK_TVAL_IS_NUMBER(tv_x)) {
- duk_to_number(ctx, idx_x); /* side effects, perform in-place */
- tv_x = DUK_GET_TVAL_POSIDX(ctx, idx_x);
- DUK_ASSERT(tv_x != NULL);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
- }
-
- d1 = DUK_TVAL_GET_NUMBER(tv_x);
- if (opcode == DUK_EXTRAOP_UNM) {
- du.d = -d1;
- } else {
- /* ToNumber() for a double is a no-op. */
- DUK_ASSERT(opcode == DUK_EXTRAOP_UNP);
- du.d = d1;
- }
- DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */
-
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
-
-#if defined(DUK_USE_FASTINT)
- /* Unary plus is used to force a fastint check, so must include
- * downgrade check.
- */
- DUK_TVAL_SET_NUMBER_CHKFAST(tv_x, du.d); /* no refcount changes */
-#else
- DUK_TVAL_SET_NUMBER(tv_x, du.d); /* no refcount changes */
-#endif
-}
-
-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
- */
-
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_z;
- duk_int32_t i1, i2;
-#if !defined(DUK_USE_FASTINT)
- duk_double_t d2;
-#endif
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(tv_x != NULL); /* may be reg or const */
- DUK_ASSERT_DISABLE(idx_z >= 0);
- DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x)) {
- i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
- }
- else
-#endif /* DUK_USE_FASTINT */
- {
- duk_push_tval(ctx, tv_x);
- i1 = duk_to_int32(ctx, -1);
- duk_pop(ctx);
- }
-
- i2 = ~i1;
-
-#if defined(DUK_USE_FASTINT)
- /* Result is always fastint compatible. */
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv_z, i2); /* side effects */
-#else
- d2 = (duk_double_t) i2;
-
- DUK_ASSERT(!DUK_ISNAN(d2)); /* 'val' is never NaN, so no need to normalize */
- DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2); /* always normalized */
-
- tv_z = thr->valstack_bottom + idx_z;
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d2); /* side effects */
-#endif
-}
-
-DUK_LOCAL void duk__vm_logical_not(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_z) {
- /*
- * E5 Section 11.4.9
- */
-
- duk_bool_t res;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(tv_x != NULL); /* may be reg or const */
- DUK_ASSERT(tv_z != NULL); /* reg */
-
- DUK_UNREF(thr); /* w/o refcounts */
-
- /* ToBoolean() does not require any operations with side effects so
- * we can do it efficiently. For footprint it would be better to use
- * duk_js_toboolean() and then push+replace to the result slot.
- */
- res = duk_js_toboolean(tv_x); /* does not modify tv_x */
- DUK_ASSERT(res == 0 || res == 1);
- res ^= 1;
- DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv_z, res); /* side effects */
-}
-
-/*
- * Longjmp and other control flow transfer for the bytecode executor.
- *
- * The longjmp handler can handle all longjmp types: error, yield, and
- * resume (pseudotypes are never actually thrown).
- *
- * Error policy for longjmp: should not ordinarily throw errors; if errors
- * occur (e.g. due to out-of-memory) they bubble outwards rather than being
- * handled recursively.
- */
-
-#define DUK__LONGJMP_RESTART 0 /* state updated, restart bytecode execution */
-#define DUK__LONGJMP_RETHROW 1 /* exit bytecode executor by rethrowing an error to caller */
-
-#define DUK__RETHAND_RESTART 0 /* state updated, restart bytecode execution */
-#define DUK__RETHAND_FINISHED 1 /* exit bytecode execution with return value */
-
-/* XXX: optimize reconfig valstack operations so that resize, clamp, and setting
- * top are combined into one pass.
- */
-
-/* Reconfigure value stack for return to an Ecmascript function at 'act_idx'. */
-DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr, duk_size_t act_idx) {
- duk_activation *act;
- duk_hcompiledfunction *h_func;
- duk_idx_t clamp_top;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
- DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
-
- /* Clamp so that values at 'clamp_top' and above are wiped and won't
- * retain reachable garbage. Then extend to 'nregs' because we're
- * returning to an Ecmascript function.
- */
-
- act = thr->callstack + act_idx;
- h_func = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
-
- thr->valstack_bottom = thr->valstack + act->idx_bottom;
- DUK_ASSERT(act->idx_retval >= act->idx_bottom);
- clamp_top = (duk_idx_t) (act->idx_retval - act->idx_bottom + 1); /* +1 = one retval */
- duk_set_top((duk_context *) thr, clamp_top);
- act = NULL;
-
- (void) duk_valstack_resize_raw((duk_context *) thr,
- (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- h_func->nregs + /* reg count */
- DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
-
- duk_set_top((duk_context *) thr, h_func->nregs);
-}
-
-DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_size_t act_idx, duk_size_t cat_idx) {
- duk_activation *act;
- duk_catcher *cat;
- duk_hcompiledfunction *h_func;
- duk_idx_t clamp_top;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
- DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
-
- act = thr->callstack + act_idx;
- cat = thr->catchstack + cat_idx;
- h_func = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
-
- thr->valstack_bottom = thr->valstack + act->idx_bottom;
- DUK_ASSERT(cat->idx_base >= act->idx_bottom);
- clamp_top = (duk_idx_t) (cat->idx_base - act->idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
- duk_set_top((duk_context *) thr, clamp_top);
- act = NULL;
- cat = NULL;
-
- (void) duk_valstack_resize_raw((duk_context *) thr,
- (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
- h_func->nregs + /* reg count */
- DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
- DUK_VSRESIZE_FLAG_SHRINK | /* flags */
- 0 /* no compact */ |
- DUK_VSRESIZE_FLAG_THROW);
-
- duk_set_top((duk_context *) thr, h_func->nregs);
-}
-
-/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type. */
-DUK_LOCAL void duk__set_catcher_regs(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
- duk_tval *tv1;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(tv_val_unstable != NULL);
-
- tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base;
- DUK_ASSERT(tv1 < thr->valstack_top);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
-
- tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base + 1;
- DUK_ASSERT(tv1 < thr->valstack_top);
-
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) lj_type); /* side effects */
-}
-
-DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
- duk_context *ctx;
- duk_activation *act;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(tv_val_unstable != NULL);
- ctx = (duk_context *) thr;
-
- duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
-
- duk_hthread_catchstack_unwind(thr, cat_idx + 1);
- duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
-
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
-
- duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
-
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
- act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */
- act = NULL;
-
- /*
- * If entering a 'catch' block which requires an automatic
- * catch variable binding, create the lexical environment.
- *
- * The binding is mutable (= writable) but not deletable.
- * Step 4 for the catch production in E5 Section 12.14;
- * no value is given for CreateMutableBinding 'D' argument,
- * which implies the binding is not deletable.
- */
-
- if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) {
- duk_hobject *new_env;
- duk_hobject *act_lex_env;
-
- DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding"));
-
- /* Note: 'act' is dangerous here because it may get invalidate at many
- * points, so we re-lookup it multiple times.
- */
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
-
- if (act->lex_env == NULL) {
- DUK_ASSERT(act->var_env == NULL);
- DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
-
- /* this may have side effects, so re-lookup act */
- duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack + thr->callstack_top - 1;
- }
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
- DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
- DUK_UNREF(act); /* unreferenced without assertions */
-
- act = thr->callstack + thr->callstack_top - 1;
- act_lex_env = act->lex_env;
- act = NULL; /* invalidated */
-
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- act_lex_env);
- new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
- DUK_ASSERT(new_env != NULL);
- DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
-
- /* Note: currently the catch binding is handled without a register
- * binding because we don't support dynamic register bindings (they
- * must be fixed for an entire function). So, there is no need to
- * record regbases etc.
- */
-
- DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL);
- duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname);
- duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base);
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
-
- act = thr->callstack + thr->callstack_top - 1;
- act->lex_env = new_env;
- DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */
-
- DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]);
-
- duk_pop(ctx);
-
- DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env));
- }
-
- DUK_CAT_CLEAR_CATCH_ENABLED(&thr->catchstack[cat_idx]);
-}
-
-DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
- duk_activation *act;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(tv_val_unstable != NULL);
-
- duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
-
- duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */
- duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
-
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
-
- duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
-
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
- act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */
- act = NULL;
-
- DUK_CAT_CLEAR_FINALLY_ENABLED(&thr->catchstack[cat_idx]);
-}
-
-DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_size_t cat_idx, duk_small_uint_t lj_type) {
- duk_activation *act;
-
- DUK_ASSERT(thr != NULL);
-
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
-
- DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(act)));
-
- /* +0 = break, +1 = continue */
- act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
- act = NULL; /* invalidated */
-
- duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */
- /* no need to unwind callstack */
-
- /* valstack should not need changes */
-#if defined(DUK_USE_ASSERTIONS)
- DUK_ASSERT(thr->callstack_top >= 1);
- act = thr->callstack + thr->callstack_top - 1;
- DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) ==
- (duk_size_t) ((duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act))->nregs);
-#endif
-}
-
-/* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and
- * when a RETURN opcode terminates a thread and yields to the resumer.
- */
-DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_size_t act_idx, duk_tval *tv_val_unstable) {
- duk_tval *tv1;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(resumer != NULL);
- DUK_ASSERT(tv_val_unstable != NULL);
- DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + act_idx) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + act_idx))); /* resume caller must be an ecmascript func */
-
- tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
-
- duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */
-
- /* no need to unwind catchstack */
- duk__reconfig_valstack_ecma_return(resumer, act_idx);
-
- /* caller must change active thread, and set thr->resumer to NULL */
-}
-
-DUK_LOCAL
-duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
- duk_hthread *entry_thread,
- duk_size_t entry_callstack_top) {
- duk_size_t entry_callstack_index;
- duk_small_uint_t retval = DUK__LONGJMP_RESTART;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(entry_thread != NULL);
- DUK_ASSERT(entry_callstack_top > 0); /* guarantees entry_callstack_top - 1 >= 0 */
-
- entry_callstack_index = entry_callstack_top - 1;
-
- /* 'thr' is the current thread, as no-one resumes except us and we
- * switch 'thr' in that case.
- */
- DUK_ASSERT(thr == thr->heap->curr_thread);
-
- /*
- * (Re)try handling the longjmp.
- *
- * A longjmp handler may convert the longjmp to a different type and
- * "virtually" rethrow by goto'ing to 'check_longjmp'. Before the goto,
- * the following must be updated:
- * - the heap 'lj' state
- * - 'thr' must reflect the "throwing" thread
- */
-
- check_longjmp:
-
- DUK_DD(DUK_DDPRINT("handling longjmp: type=%ld, value1=%!T, value2=%!T, iserror=%ld",
- (long) thr->heap->lj.type,
- (duk_tval *) &thr->heap->lj.value1,
- (duk_tval *) &thr->heap->lj.value2,
- (long) thr->heap->lj.iserror));
-
- switch (thr->heap->lj.type) {
-
- case DUK_LJ_TYPE_RESUME: {
- /*
- * Note: lj.value1 is 'value', lj.value2 is 'resumee'.
- * This differs from YIELD.
- */
-
- duk_tval *tv;
- duk_tval *tv2;
- duk_size_t act_idx;
- duk_hthread *resumee;
-
- /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
-
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */
- DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
-
- tv = &thr->heap->lj.value2; /* resumee */
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
- resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
-
- DUK_ASSERT(resumee != NULL);
- DUK_ASSERT(resumee->resumer == NULL);
- DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE ||
- resumee->state == DUK_HTHREAD_STATE_YIELDED); /* checked by Duktape.Thread.resume() */
- DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
- resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */
- DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
- (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield));
- DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
- (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 2)))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
- (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */
- DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
- resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */
- DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
- (resumee->valstack_top == resumee->valstack + 1 &&
- DUK_TVAL_IS_OBJECT(resumee->valstack_top - 1) &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(resumee->valstack_top - 1))));
-
- if (thr->heap->lj.iserror) {
- /*
- * Throw the error in the resumed thread's context; the
- * error value is pushed onto the resumee valstack.
- *
- * Note: the callstack of the target may empty in this case
- * too (i.e. the target thread has never been resumed). The
- * value stack will contain the initial function in that case,
- * which we simply ignore.
- */
-
- resumee->resumer = thr;
- resumee->state = DUK_HTHREAD_STATE_RUNNING;
- thr->state = DUK_HTHREAD_STATE_RESUMED;
- DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
- thr = resumee;
-
- thr->heap->lj.type = DUK_LJ_TYPE_THROW;
-
- /* thr->heap->lj.value1 is already the value to throw */
- /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */
-
- DUK_ASSERT(thr->heap->lj.iserror); /* already set */
-
- DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate"));
- goto check_longjmp;
- } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
- act_idx = resumee->callstack_top - 2; /* Ecmascript function */
- DUK_ASSERT_DISABLE(resumee->callstack[act_idx].idx_retval >= 0); /* unsigned */
-
- tv = resumee->valstack + resumee->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.yield() */
- DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
- tv2 = &thr->heap->lj.value1;
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */
-
- duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */
-
- /* no need to unwind catchstack */
-
- duk__reconfig_valstack_ecma_return(resumee, act_idx);
-
- resumee->resumer = thr;
- resumee->state = DUK_HTHREAD_STATE_RUNNING;
- thr->state = DUK_HTHREAD_STATE_RESUMED;
- DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
-#if 0
- thr = resumee; /* not needed, as we exit right away */
-#endif
- DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
- } else {
- duk_small_uint_t call_flags;
- duk_bool_t setup_rc;
-
- /* resumee: [... initial_func] (currently actually: [initial_func]) */
-
- duk_push_undefined((duk_context *) resumee);
- tv = &thr->heap->lj.value1;
- duk_push_tval((duk_context *) resumee, tv);
-
- /* resumee: [... initial_func undefined(= this) resume_value ] */
-
- call_flags = DUK_CALL_FLAG_IS_RESUME; /* is resume, not a tail call */
-
- setup_rc = duk_handle_ecma_call_setup(resumee,
- 1, /* num_stack_args */
- call_flags); /* call_flags */
- if (setup_rc == 0) {
- /* Shouldn't happen but check anyway. */
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- }
-
- resumee->resumer = thr;
- resumee->state = DUK_HTHREAD_STATE_RUNNING;
- thr->state = DUK_HTHREAD_STATE_RESUMED;
- DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
-#if 0
- thr = resumee; /* not needed, as we exit right away */
-#endif
- DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
- }
- DUK_UNREACHABLE();
- break; /* never here */
- }
-
- case DUK_LJ_TYPE_YIELD: {
- /*
- * Currently only allowed only if yielding thread has only
- * Ecmascript activations (except for the Duktape.Thread.yield()
- * call at the callstack top) and none of them constructor
- * calls.
- *
- * This excludes the 'entry' thread which will always have
- * a preventcount > 0.
- */
-
- duk_hthread *resumer;
-
- /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
-
- DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */
- DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
-
- resumer = thr->resumer;
-
- DUK_ASSERT(resumer != NULL);
- DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */
- DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume);
- DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
-
- if (thr->heap->lj.iserror) {
- thr->state = DUK_HTHREAD_STATE_YIELDED;
- thr->resumer = NULL;
- resumer->state = DUK_HTHREAD_STATE_RUNNING;
- DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
- thr = resumer;
-
- thr->heap->lj.type = DUK_LJ_TYPE_THROW;
- /* lj.value1 is already set */
- DUK_ASSERT(thr->heap->lj.iserror); /* already set */
-
- DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
- goto check_longjmp;
- } else {
- duk__handle_yield(thr, resumer, resumer->callstack_top - 2, &thr->heap->lj.value1);
-
- thr->state = DUK_HTHREAD_STATE_YIELDED;
- thr->resumer = NULL;
- resumer->state = DUK_HTHREAD_STATE_RUNNING;
- DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
-#if 0
- thr = resumer; /* not needed, as we exit right away */
-#endif
-
- DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
- }
- DUK_UNREACHABLE();
- break; /* never here */
- }
-
- case DUK_LJ_TYPE_THROW: {
- /*
- * Three possible outcomes:
- * * A try or finally catcher is found => resume there.
- * (or)
- * * The error propagates to the bytecode executor entry
- * level (and we're in the entry thread) => rethrow
- * with a new longjmp(), after restoring the previous
- * catchpoint.
- * * The error is not caught in the current thread, so
- * the thread finishes with an error. This works like
- * a yielded error, except that the thread is finished
- * and can no longer be resumed. (There is always a
- * resumer in this case.)
- *
- * Note: until we hit the entry level, there can only be
- * Ecmascript activations.
- */
-
- duk_catcher *cat;
- duk_hthread *resumer;
-
- cat = thr->catchstack + thr->catchstack_top - 1;
- while (cat >= thr->catchstack) {
- if (thr == entry_thread &&
- cat->callstack_index < entry_callstack_index) {
- /* entry level reached */
- break;
- }
-
- if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
-
- duk__handle_catch(thr,
- cat - thr->catchstack,
- &thr->heap->lj.value1,
- DUK_LJ_TYPE_THROW);
-
- DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
- }
-
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
- DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
-
- duk__handle_finally(thr,
- cat - thr->catchstack,
- &thr->heap->lj.value1,
- DUK_LJ_TYPE_THROW);
-
- DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
- retval = DUK__LONGJMP_RESTART;
- goto wipe_and_return;
- }
-
- cat--;
- }
-
- if (thr == entry_thread) {
- /* not caught by anything before entry level; rethrow and let the
- * final catcher unwind everything
- */
-#if 0
- duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
- duk_hthread_callstack_unwind(thr, entry_callstack_index + 1);
-
-#endif
- DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
- retval = DUK__LONGJMP_RETHROW;
- goto just_return;
- /* Note: MUST NOT wipe_and_return here, as heap->lj must remain intact */
- }
-
- DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp"));
-
- /* not caught by current thread, thread terminates (yield error to resumer);
- * note that this may cause a cascade if the resumer terminates with an uncaught
- * exception etc (this is OK, but needs careful testing)
- */
-
- DUK_ASSERT(thr->resumer != NULL);
- DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
-
- resumer = thr->resumer;
-
- /* reset longjmp */
-
- DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); /* already set */
- /* lj.value1 already set */
-
- duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
-
- thr->resumer = NULL;
- resumer->state = DUK_HTHREAD_STATE_RUNNING;
- DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
- thr = resumer;
- goto check_longjmp;
- }
-
- case DUK_LJ_TYPE_BREAK: /* pseudotypes, not used in actual longjmps */
- case DUK_LJ_TYPE_CONTINUE:
- case DUK_LJ_TYPE_RETURN:
- case DUK_LJ_TYPE_NORMAL:
- default: {
- /* should never happen, but be robust */
- DUK_D(DUK_DPRINT("caught unknown longjmp type %ld, treat as internal error", (long) thr->heap->lj.type));
- goto convert_to_internal_error;
- }
-
- } /* end switch */
-
- DUK_UNREACHABLE();
-
- wipe_and_return:
- /* this is not strictly necessary, but helps debugging */
- 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 */
-
- just_return:
- return retval;
-
- convert_to_internal_error:
- /* This could also be thrown internally (set the error, goto check_longjmp),
- * but it's better for internal errors to bubble outwards so that we won't
- * infinite loop in this catchpoint.
- */
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- DUK_UNREACHABLE();
- return retval;
-}
-
-/* Handle a BREAK/CONTINUE opcode. Avoid using longjmp() for BREAK/CONTINUE
- * handling because it has a measurable performance impact in ordinary
- * environments and an extreme impact in Emscripten (GH-342).
- */
-DUK_LOCAL void duk__handle_break_or_continue(duk_hthread *thr,
- duk_uint_t label_id,
- duk_small_uint_t lj_type) {
- duk_catcher *cat;
- duk_size_t orig_callstack_index;
-
- DUK_ASSERT(thr != NULL);
-
- /*
- * Find a matching label catcher or 'finally' catcher in
- * the same function.
- *
- * A label catcher must always exist and will match unless
- * a 'finally' captures the break/continue first. It is the
- * compiler's responsibility to ensure that labels are used
- * correctly.
- */
-
- /* Note: thr->catchstack_top may be 0, so that cat < thr->catchstack
- * initially. This is OK and intended.
- */
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_ASSERT(thr->callstack_top > 0);
- orig_callstack_index = thr->callstack_top - 1;
-
- DUK_DDD(DUK_DDDPRINT("handling break/continue with label=%ld, callstack index=%ld",
- (long) label_id, (long) cat->callstack_index));
-
- while (cat >= thr->catchstack) {
- if (cat->callstack_index != orig_callstack_index) {
- break;
- }
- DUK_DDD(DUK_DDDPRINT("considering catcher %ld: type=%ld label=%ld",
- (long) (cat - thr->catchstack),
- (long) DUK_CAT_GET_TYPE(cat),
- (long) DUK_CAT_GET_LABEL(cat)));
-
- if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
- DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- duk_size_t cat_idx;
- duk_tval tv_tmp;
-
- cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
-
- DUK_TVAL_SET_FASTINT_U32(&tv_tmp, (duk_uint32_t) label_id);
- duk__handle_finally(thr, cat_idx, &tv_tmp, lj_type);
-
- DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution"));
- return;
- }
- if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
- (duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) {
- duk_size_t cat_idx;
-
- cat_idx = (duk_size_t) (cat - thr->catchstack);
- duk__handle_label(thr, cat_idx, lj_type);
-
- DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution"));
- return;
- }
- cat--;
- }
-
- /* should never happen, but be robust */
- DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error"));
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- return;
-}
-
-/* Handle a RETURN opcode. Avoid using longjmp() for return handling because
- * it has a measurable performance impact in ordinary environments and an extreme
- * impact in Emscripten (GH-342). Return value is on value stack top.
- */
-DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
- duk_hthread *entry_thread,
- duk_size_t entry_callstack_top) {
- duk_tval *tv1;
- duk_tval *tv2;
- duk_hthread *resumer;
- duk_catcher *cat;
- duk_size_t new_cat_top;
- duk_size_t orig_callstack_index;
-
- /* We can directly access value stack here. */
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(entry_thread != NULL);
- DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
- tv1 = thr->valstack_top - 1;
- DUK_TVAL_CHKFAST_INPLACE(tv1); /* fastint downgrade check for return values */
-
- /*
- * Four possible outcomes:
- *
- * 1. A 'finally' in the same function catches the 'return'.
- * It may continue to propagate when 'finally' is finished,
- * or it may be neutralized by 'finally' (both handled by
- * ENDFIN).
- *
- * 2. The return happens at the entry level of the bytecode
- * executor, so return from the executor (in C stack).
- *
- * 3. There is a calling (Ecmascript) activation in the call
- * stack => return to it, in the same executor instance.
- *
- * 4. There is no calling activation, and the thread is
- * terminated. There is always a resumer in this case,
- * which gets the return value similarly to a 'yield'
- * (except that the current thread can no longer be
- * resumed).
- */
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack != NULL);
-
- /* XXX: does not work if thr->catchstack is NULL */
- /* XXX: does not work if thr->catchstack is allocated but lowest pointer */
-
- cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */
- DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */
- orig_callstack_index = thr->callstack_top - 1;
-
- while (cat >= thr->catchstack) {
- if (cat->callstack_index != orig_callstack_index) {
- break;
- }
- if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
- DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- duk_size_t cat_idx;
-
- cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
-
- DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
- duk__handle_finally(thr, cat_idx, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
-
- DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution"));
- return DUK__RETHAND_RESTART;
- }
- cat--;
- }
- /* If out of catchstack, cat = thr->catchstack - 1;
- * new_cat_top will be 0 in that case.
- */
- new_cat_top = (duk_size_t) ((cat + 1) - thr->catchstack);
- cat = NULL; /* avoid referencing, invalidated */
-
- DUK_DDD(DUK_DDDPRINT("no catcher in catch stack, return to calling activation / yield"));
-
- if (thr == entry_thread &&
- thr->callstack_top == entry_callstack_top) {
- /* Return to the bytecode executor caller which will unwind stacks.
- * 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;
- }
-
- if (thr->callstack_top >= 2) {
- /* There is a caller; it MUST be an Ecmascript caller (otherwise it would
- * match entry level check)
- */
-
- DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T",
- (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
- (duk_tval *) &thr->heap->lj.value1));
-
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */
-
- tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval;
- DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
- tv2 = thr->valstack_top - 1;
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
-
- DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T",
- (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
- (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval)));
-
- duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
- duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
- duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1);
-
- DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller"));
- return DUK__RETHAND_RESTART;
- }
-
- DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)"));
-
- DUK_ASSERT(thr->resumer != NULL);
- DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
- DUK_HOBJECT_IS_NATIVEFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
- ((duk_hnativefunction *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
- DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
- DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
- DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
-
- resumer = thr->resumer;
-
- /* Share yield longjmp handler. */
- DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
- duk__handle_yield(thr, resumer, resumer->callstack_top - 2, thr->valstack_top - 1);
-
- duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
- DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
-
- thr->resumer = NULL;
- resumer->state = DUK_HTHREAD_STATE_RUNNING;
- DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
-#if 0
- thr = resumer; /* not needed */
-#endif
-
- DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer"));
- return DUK__RETHAND_RESTART;
-}
-
-/*
- * Executor interrupt handling
- *
- * The handler is called whenever the interrupt countdown reaches zero
- * (or below). The handler must perform whatever checks are activated,
- * e.g. check for cumulative step count to impose an execution step
- * limit or check for breakpoints or other debugger interaction.
- *
- * When the actions are done, the handler must reinit the interrupt
- * init and counter values. The 'init' value must indicate how many
- * bytecode instructions are executed before the next interrupt. The
- * counter must interface with the bytecode executor loop. Concretely,
- * the new init value is normally one higher than the new counter value.
- * For instance, to execute exactly one bytecode instruction the init
- * value is set to 1 and the counter to 0. If an error is thrown by the
- * interrupt handler, the counters are set to the same value (e.g. both
- * to 0 to cause an interrupt when the next bytecode instruction is about
- * to be executed after error handling).
- *
- * Maintaining the init/counter value properly is important for accurate
- * behavior. For instance, executor step limit needs a cumulative step
- * count which is simply computed as a sum of 'init' values. This must
- * work accurately even when single stepping.
- */
-
-#if defined(DUK_USE_INTERRUPT_COUNTER)
-
-#define DUK__INT_NOACTION 0 /* no specific action, resume normal execution */
-#define DUK__INT_RESTART 1 /* must "goto restart_execution", e.g. breakpoints changed */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) {
- duk_context *ctx;
- duk_activation *act;
- duk_breakpoint *bp;
- duk_breakpoint **bp_active;
- duk_uint_fast32_t line = 0;
- duk_bool_t process_messages;
- duk_bool_t processed_messages = 0;
-
- DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */
-
- ctx = (duk_context *) thr;
- act = thr->callstack + thr->callstack_top - 1;
-
- /* It might seem that replacing 'thr->heap' with just 'heap' below
- * might be a good idea, but it increases code size slightly
- * (probably due to unnecessary spilling) at least on x64.
- */
-
- /*
- * Breakpoint and step state checks
- */
-
- if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
- (thr->heap->dbg_step_thread == thr &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
- line = duk_debug_curr_line(thr);
-
- if (act->prev_line != line) {
- /* Stepped? Step out is handled by callstack unwind. */
- if ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
- thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
- (thr->heap->dbg_step_thread == thr) &&
- (thr->heap->dbg_step_csindex == thr->callstack_top - 1) &&
- (line != thr->heap->dbg_step_startline)) {
- DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld",
- (long) line));
-
- DUK_HEAP_SET_PAUSED(thr->heap);
- }
-
- /* Check for breakpoints only on line transition.
- * Breakpoint is triggered when we enter the target
- * line from a different line, and the previous line
- * was within the same function.
- *
- * This condition is tricky: the condition used to be
- * that transition to -or across- the breakpoint line
- * triggered the breakpoint. This seems intuitively
- * better because it handles breakpoints on lines with
- * no emitted opcodes; but this leads to the issue
- * described in: https://github.com/svaarala/duktape/issues/263.
- */
- bp_active = thr->heap->dbg_breakpoints_active;
- for (;;) {
- bp = *bp_active++;
- if (bp == NULL) {
- break;
- }
-
- DUK_ASSERT(bp->filename != NULL);
- if (act->prev_line != bp->line && line == bp->line) {
- DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld",
- (duk_heaphdr *) bp->filename, (long) bp->line));
-
- DUK_HEAP_SET_PAUSED(thr->heap);
- }
- }
- } else {
- ;
- }
-
- act->prev_line = line;
- }
-
- /*
- * Rate limit check for sending status update or peeking into
- * the debug transport. Both can be expensive operations that
- * we don't want to do on every opcode.
- *
- * Making sure the interval remains reasonable on a wide variety
- * of targets and bytecode is difficult without a timestamp, so
- * we use a Date-provided timestamp for the rate limit check.
- * But since it's also expensive to get a timestamp, a bytecode
- * counter is used to rate limit getting timestamps.
- */
-
- process_messages = 0;
- if (thr->heap->dbg_state_dirty || thr->heap->dbg_paused || thr->heap->dbg_detaching) {
- /* Enter message processing loop for sending Status notifys and
- * to finish a pending detach.
- */
- process_messages = 1;
- }
-
- /* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */
- thr->heap->dbg_exec_counter += thr->interrupt_init;
- if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) {
- /* Overflow of the execution counter is fine and doesn't break
- * anything here.
- */
-
- duk_double_t now, diff_last;
-
- thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter;
- now = DUK_USE_DATE_GET_NOW(ctx);
-
- diff_last = now - thr->heap->dbg_last_time;
- if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) {
- /* Negative value checked so that a "time jump" works
- * reasonably.
- *
- * Same interval is now used for status sending and
- * peeking.
- */
-
- thr->heap->dbg_last_time = now;
- thr->heap->dbg_state_dirty = 1;
- process_messages = 1;
- }
- }
-
- /*
- * Process messages and send status if necessary.
- *
- * If we're paused, we'll block for new messages. If we're not
- * paused, we'll process anything we can peek but won't block
- * for more. Detach (and re-attach) handling is all localized
- * to duk_debug_process_messages() too.
- *
- * Debugger writes outside the message loop may cause debugger
- * detach1 phase to run, after which dbg_read_cb == NULL and
- * dbg_detaching != 0. The message loop will finish the detach
- * by running detach2 phase, so enter the message loop also when
- * detaching.
- */
-
- act = NULL; /* may be changed */
- if (process_messages) {
- DUK_ASSERT(thr->heap->dbg_processing == 0);
- processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
- DUK_ASSERT(thr->heap->dbg_processing == 0);
- }
-
- /* Continue checked execution if there are breakpoints or we're stepping.
- * Also use checked execution if paused flag is active - it shouldn't be
- * because the debug message loop shouldn't terminate if it was. Step out
- * is handled by callstack unwind and doesn't need checked execution.
- * Note that debugger may have detached due to error or explicit request
- * above, so we must recheck attach status.
- */
-
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */
- if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
- ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
- thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
- thr->heap->dbg_step_thread == thr &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1) ||
- thr->heap->dbg_paused) {
- *out_immediate = 1;
- }
-
- /* If we processed any debug messages breakpoints may have
- * changed; restart execution to re-check active breakpoints.
- */
- if (processed_messages) {
- DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints"));
- *out_interrupt_retval = DUK__INT_RESTART;
- }
- } else {
- DUK_D(DUK_DPRINT("debugger became detached, resume normal execution"));
- }
-}
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
-DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
- duk_int_t ctr;
- duk_activation *act;
- duk_hcompiledfunction *fun;
- duk_bool_t immediate = 0;
- duk_small_uint_t retval;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->heap != NULL);
- DUK_ASSERT(thr->callstack != NULL);
- DUK_ASSERT(thr->callstack_top > 0);
-
-#if defined(DUK_USE_DEBUG)
- thr->heap->inst_count_interrupt += thr->interrupt_init;
- DUK_DD(DUK_DDPRINT("execution interrupt, counter=%ld, init=%ld, "
- "instruction counts: executor=%ld, interrupt=%ld",
- (long) thr->interrupt_counter, (long) thr->interrupt_init,
- (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
-#endif
-
- retval = DUK__INT_NOACTION;
- ctr = DUK_HTHREAD_INTCTR_DEFAULT;
-
- /*
- * Avoid nested calls. Concretely this happens during debugging, e.g.
- * when we eval() an expression.
- *
- * Also don't interrupt if we're currently doing debug processing
- * (which can be initiated outside the bytecode executor) as this
- * may cause the debugger to be called recursively. Check required
- * for correct operation of throw intercept and other "exotic" halting
- * scenarios.
- */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap) || thr->heap->dbg_processing) {
-#else
- if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap)) {
-#endif
- DUK_DD(DUK_DDPRINT("nested executor interrupt, ignoring"));
-
- /* Set a high interrupt counter; the original executor
- * interrupt invocation will rewrite before exiting.
- */
- thr->interrupt_init = ctr;
- thr->interrupt_counter = ctr - 1;
- return DUK__INT_NOACTION;
- }
- DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap);
-
- act = thr->callstack + thr->callstack_top - 1;
-
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION((duk_hobject *) fun));
-
- DUK_UNREF(fun);
-
-#if defined(DUK_USE_EXEC_TIMEOUT_CHECK)
- /*
- * Execution timeout check
- */
-
- if (DUK_USE_EXEC_TIMEOUT_CHECK(thr->heap->heap_udata)) {
- /* Keep throwing an error whenever we get here. The unusual values
- * are set this way because no instruction is ever executed, we just
- * throw an error until all try/catch/finally and other catchpoints
- * have been exhausted. Duktape/C code gets control at each protected
- * call but whenever it enters back into Duktape the RangeError gets
- * raised. User exec timeout check must consistently indicate a timeout
- * until we've fully bubbled out of Duktape.
- */
- DUK_D(DUK_DPRINT("execution timeout, throwing a RangeError"));
- thr->interrupt_init = 0;
- thr->interrupt_counter = 0;
- DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
- DUK_ERROR_RANGE(thr, "execution timeout");
- }
-#endif /* DUK_USE_EXEC_TIMEOUT_CHECK */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (!thr->heap->dbg_processing &&
- (thr->heap->dbg_read_cb != NULL || thr->heap->dbg_detaching)) {
- /* Avoid recursive re-entry; enter when we're attached or
- * detaching (to finish off the pending detach).
- */
- duk__interrupt_handle_debugger(thr, &immediate, &retval);
- act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */
- DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
- }
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
- /*
- * Update the interrupt counter
- */
-
- if (immediate) {
- /* Cause an interrupt after executing one instruction. */
- ctr = 1;
- }
-
- /* The counter value is one less than the init value: init value should
- * indicate how many instructions are executed before interrupt. To
- * execute 1 instruction (after interrupt handler return), counter must
- * be 0.
- */
- DUK_ASSERT(ctr >= 1);
- thr->interrupt_init = ctr;
- thr->interrupt_counter = ctr - 1;
- DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
-
- return retval;
-}
-#endif /* DUK_USE_INTERRUPT_COUNTER */
-
-/*
- * Debugger handling for executor restart
- *
- * Check for breakpoints, stepping, etc, and figure out if we should execute
- * in checked or normal mode. Note that we can't do this when an activation
- * is created, because breakpoint status (and stepping status) may change
- * later, so we must recheck every time we're executing an activation.
- * This primitive should be side effect free to avoid changes during check.
- */
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
-DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompiledfunction *fun) {
- duk_heap *heap;
- duk_tval *tv_tmp;
- duk_hstring *filename;
- duk_small_uint_t bp_idx;
- duk_breakpoint **bp_active;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(act != NULL);
- DUK_ASSERT(fun != NULL);
-
- heap = thr->heap;
- bp_active = heap->dbg_breakpoints_active;
- act->flags &= ~DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
-
- tv_tmp = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) fun, DUK_HTHREAD_STRING_FILE_NAME(thr));
- if (tv_tmp && DUK_TVAL_IS_STRING(tv_tmp)) {
- filename = DUK_TVAL_GET_STRING(tv_tmp);
-
- /* Figure out all active breakpoints. A breakpoint is
- * considered active if the current function's fileName
- * matches the breakpoint's fileName, AND there is no
- * inner function that has matching line numbers
- * (otherwise a breakpoint would be triggered both
- * inside and outside of the inner function which would
- * be confusing). Example:
- *
- * function foo() {
- * print('foo');
- * function bar() { <-. breakpoints in these
- * print('bar'); | lines should not affect
- * } <-' foo() execution
- * bar();
- * }
- *
- * We need a few things that are only available when
- * debugger support is enabled: (1) a line range for
- * each function, and (2) access to the function
- * template to access the inner functions (and their
- * line ranges).
- *
- * It's important to have a narrow match for active
- * breakpoints so that we don't enter checked execution
- * when that's not necessary. For instance, if we're
- * running inside a certain function and there's
- * breakpoint outside in (after the call site), we
- * don't want to slow down execution of the function.
- */
-
- for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) {
- duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx;
- duk_hobject **funcs, **funcs_end;
- duk_hcompiledfunction *inner_fun;
- duk_bool_t bp_match;
-
- if (bp->filename == filename &&
- bp->line >= fun->start_line && bp->line <= fun->end_line) {
- bp_match = 1;
- DUK_DD(DUK_DDPRINT("breakpoint filename and line match: "
- "%s:%ld vs. %s (line %ld vs. %ld-%ld)",
- DUK_HSTRING_GET_DATA(bp->filename),
- (long) bp->line,
- DUK_HSTRING_GET_DATA(filename),
- (long) bp->line,
- (long) fun->start_line,
- (long) fun->end_line));
-
- funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, fun);
- funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, fun);
- while (funcs != funcs_end) {
- inner_fun = (duk_hcompiledfunction *) *funcs;
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) inner_fun));
- if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) {
- DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint"));
- bp_match = 0;
- break;
- }
- funcs++;
- }
-
- if (bp_match) {
- /* No need to check for size of bp_active list,
- * it's always larger than maximum number of
- * breakpoints.
- */
- act->flags |= DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
- *bp_active = heap->dbg_breakpoints + bp_idx;
- bp_active++;
- }
- }
- }
- }
-
- *bp_active = NULL; /* terminate */
-
- DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active)));
-
- /* Force pause if we were doing "step into" in another activation. */
- if (thr->heap->dbg_step_thread != NULL &&
- thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO &&
- (thr->heap->dbg_step_thread != thr ||
- thr->heap->dbg_step_csindex != thr->callstack_top - 1)) {
- DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED"));
- DUK_HEAP_SET_PAUSED(thr->heap);
- }
-
- /* Force interrupt right away if we're paused or in "checked mode".
- * Step out is handled by callstack unwind.
- */
- if (act->flags & (DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
- thr->heap->dbg_paused ||
- (thr->heap->dbg_step_type != DUK_STEP_TYPE_OUT &&
- thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
- /* We'll need to interrupt early so recompute the init
- * counter to reflect the number of bytecode instructions
- * executed so that step counts for e.g. debugger rate
- * limiting are accurate.
- */
- DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
- thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
- thr->interrupt_counter = 0;
- }
-}
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
-/*
- * Ecmascript bytecode executor.
- *
- * Resume execution for the current thread from its current activation.
- * Returns when execution would return from the entry level activation,
- * leaving a single return value on top of the stack. Function calls
- * and thread resumptions are handled internally. If an error occurs,
- * a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level
- * setjmp() jmpbuf.
- *
- * Ecmascript function calls and coroutine resumptions are handled
- * internally (by the outer executor function) without recursive C calls.
- * Other function calls are handled using duk_handle_call(), increasing
- * C recursion depth.
- *
- * Abrupt completions (= long control tranfers) are handled either
- * directly by reconfiguring relevant stacks and restarting execution,
- * or via a longjmp. Longjmp-free handling is preferable for performance
- * (especially Emscripten performance), and is used for: break, continue,
- * and return.
- *
- * For more detailed notes, see doc/execution.rst.
- *
- * Also see doc/code-issues.rst for discussion of setjmp(), longjmp(),
- * and volatile.
- */
-
-/* Presence of 'fun' is config based, there's a marginal performance
- * difference and the best option is architecture dependent.
- */
-#if defined(DUK_USE_EXEC_FUN_LOCAL)
-#define DUK__FUN() fun
-#else
-#define DUK__FUN() ((duk_hcompiledfunction *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1))
-#endif
-#define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
-
-/* Reg/const access macros: these are very footprint and performance sensitive
- * so modify with care.
- */
-#define DUK__REG(x) (*(thr->valstack_bottom + (x)))
-#define DUK__REGP(x) (thr->valstack_bottom + (x))
-#define DUK__CONST(x) (*(consts + (x)))
-#define DUK__CONSTP(x) (consts + (x))
-#if 0
-#define DUK__REGCONST(x) ((x) < DUK_BC_REGLIMIT ? DUK__REG((x)) : DUK__CONST((x) - DUK_BC_REGLIMIT))
-#define DUK__REGCONSTP(x) ((x) < DUK_BC_REGLIMIT ? DUK__REGP((x)) : DUK__CONSTP((x) - DUK_BC_REGLIMIT))
-#define DUK__REGCONST(x) *((((x) < DUK_BC_REGLIMIT ? thr->valstack_bottom : consts2) + (x)))
-#define DUK__REGCONSTP(x) (((x) < DUK_BC_REGLIMIT ? thr->valstack_bottom : consts2) + (x))
-#endif
-/* This macro works when a regconst field is 9 bits, [0,0x1ff]. Adding
- * DUK_LIKELY/DUK_UNLIKELY increases code footprint and doesn't seem to
- * improve performance on x64 (and actually harms performance in some tests).
- */
-#define DUK__RCISREG(x) (((x) & 0x100) == 0)
-#define DUK__REGCONST(x) (*((DUK__RCISREG((x)) ? thr->valstack_bottom : consts2) + (x)))
-#define DUK__REGCONSTP(x) ((DUK__RCISREG((x)) ? thr->valstack_bottom : consts2) + (x))
-
-#ifdef DUK_USE_VERBOSE_EXECUTOR_ERRORS
-#define DUK__INTERNAL_ERROR(msg) do { \
- DUK_ERROR_INTERNAL(thr, (msg)); \
- } while (0)
-#else
-#define DUK__INTERNAL_ERROR(msg) do { \
- goto internal_error; \
- } while (0)
-#endif
-
-#define DUK__SYNC_CURR_PC() do { \
- duk_activation *act; \
- act = thr->callstack + thr->callstack_top - 1; \
- act->curr_pc = curr_pc; \
- } while (0)
-#define DUK__SYNC_AND_NULL_CURR_PC() do { \
- duk_activation *act; \
- act = thr->callstack + thr->callstack_top - 1; \
- act->curr_pc = curr_pc; \
- 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,
- duk_jmpbuf *entry_jmpbuf_ptr) {
- 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;
-
- /* 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();
- }
-}
-
-/* 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;
- duk_jmpbuf *entry_jmpbuf_ptr;
- duk_jmpbuf our_jmpbuf;
- duk_heap *heap;
-
- DUK_ASSERT(exec_thr != NULL);
- DUK_ASSERT(exec_thr->heap != NULL);
- DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
- DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr);
- DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */
- DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1)));
-
- entry_thread = exec_thr;
- heap = entry_thread->heap;
- entry_callstack_top = entry_thread->callstack_top;
- entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
- entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
-
- /*
- * Note: we currently assume that the setjmp() catchpoint is
- * not re-entrant (longjmp() cannot be called more than once
- * for a single setjmp()).
- *
- * See doc/code-issues.rst for notes on variable assignment
- * before and after setjmp().
- */
-
- for (;;) {
- heap->lj.jmpbuf_ptr = &our_jmpbuf;
- DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
-
-#if defined(DUK_USE_CPP_EXCEPTIONS)
- try {
-#else
- DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf);
- if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
-#endif
- /* Execute bytecode until returned or longjmp(). */
- duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
-
- /* Successful return: restore jmpbuf and return to caller. */
- heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
-
- 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,
- entry_jmpbuf_ptr);
- }
-#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_FMT1(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_UNREF(exc);
- duk__handle_executor_error(heap,
- entry_thread,
- entry_callstack_top,
- entry_call_recursion_depth,
- entry_jmpbuf_ptr);
- }
- } catch (...) {
- DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
- try {
- DUK_ASSERT(heap->curr_thread != NULL);
- DUK_ERROR_API(heap->curr_thread, "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_UNREF(exc);
- duk__handle_executor_error(heap,
- entry_thread,
- entry_callstack_top,
- entry_call_recursion_depth,
- entry_jmpbuf_ptr);
- }
- }
-#endif
- }
-
- DUK_UNREACHABLE();
-}
-
-/* Inner executor, performance critical. */
-DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) {
- /* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
- * Critical for performance. It would be safest to make this volatile,
- * but that eliminates performance benefits; aliasing guarantees
- * should be enough though.
- */
- duk_instr_t *curr_pc; /* bytecode has a stable pointer */
-
- /* Hot variables for interpretation. Critical for performance,
- * but must add sparingly to minimize register shuffling.
- */
- duk_hthread *thr; /* stable */
- duk_tval *consts; /* stable */
- duk_tval *consts2; /* stable; precalculated for faster lookups */
- duk_uint_fast32_t ins;
- /* 'funcs' is quite rarely used, so no local for it */
-#if defined(DUK_USE_EXEC_FUN_LOCAL)
- duk_hcompiledfunction *fun;
-#else
- /* 'fun' is quite rarely used, so no local for it */
-#endif
-
-#ifdef DUK_USE_INTERRUPT_COUNTER
- duk_int_t int_ctr;
-#endif
-
-#ifdef DUK_USE_ASSERTIONS
- duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */
-#endif
-
- /*
- * Restart execution by reloading thread state.
- *
- * Note that 'thr' and any thread configuration may have changed,
- * so all local variables are suspect and we need to reinitialize.
- *
- * The number of local variables should be kept to a minimum: if
- * the variables are spilled, they will need to be loaded from
- * memory anyway.
- *
- * Any 'goto restart_execution;' code path in opcode dispatch must
- * ensure 'curr_pc' is synced back to act->curr_pc before the goto
- * takes place.
- *
- * The interpreter must be very careful with memory pointers, as
- * many pointers are not guaranteed to be 'stable' and may be
- * reallocated and relocated on-the-fly quite easily (e.g. by a
- * memory allocation or a property access).
- *
- * The following are assumed to have stable pointers:
- * - the current thread
- * - the current function
- * - the bytecode, constant table, inner function table of the
- * current function (as they are a part of the function allocation)
- *
- * The following are assumed to have semi-stable pointers:
- * - the current activation entry: stable as long as callstack
- * is not changed (reallocated by growing or shrinking), or
- * by any garbage collection invocation (through finalizers)
- * - Note in particular that ANY DECREF can invalidate the
- * activation pointer, so for the most part a fresh lookup
- * is required
- *
- * The following are not assumed to have stable pointers at all:
- * - the value stack (registers) of the current thread
- * - the catch stack of the current thread
- *
- * See execution.rst for discussion.
- */
-
- restart_execution:
-
- /* Lookup current thread; use the stable 'entry_thread' for this to
- * avoid clobber warnings. Any valid, reachable 'thr' value would be
- * fine for this, so using 'entry_thread' is just to silence warnings.
- */
- thr = entry_thread->heap->curr_thread;
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
-
- thr->ptr_curr_pc = &curr_pc;
-
- /* Relookup and initialize dispatch loop variables. Debugger check. */
- {
- duk_activation *act;
-#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- duk_hcompiledfunction *fun;
-#endif
-
- /* Assume interrupt init/counter are properly initialized here. */
- /* Assume that thr->valstack_bottom has been set-up before getting here. */
-
- act = thr->callstack + thr->callstack_top - 1;
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
- DUK_ASSERT(fun != NULL);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);
- consts = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, fun);
- DUK_ASSERT(consts != NULL);
- consts2 = consts - DUK_BC_REGLIMIT;
-
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) {
- duk__executor_recheck_debugger(thr, act, fun);
- act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */
- }
-#endif /* DUK_USE_DEBUGGER_SUPPORT */
-
-#ifdef DUK_USE_ASSERTIONS
- valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack);
-#endif
-
- /* Set up curr_pc for opcode dispatch. */
- curr_pc = act->curr_pc;
- }
-
- DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p,"
- "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, catchstack_top=%ld, "
- "preventcount=%ld",
- (void *) thr,
- (long) (thr->callstack_top - 1),
- (void *) DUK__FUN(),
- (void *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, DUK__FUN()),
- (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, DUK__FUN()),
- (long) (thr->callstack_top - 1),
- (long) (thr->valstack_bottom - thr->valstack),
- (long) (thr->valstack_top - thr->valstack),
- (long) thr->catchstack_top,
- (long) thr->callstack_preventcount));
-
- /* Dispatch loop. */
-
- for (;;) {
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs);
- DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base);
-
- /* Executor interrupt counter check, used to implement breakpoints,
- * debugging interface, execution timeouts, etc. The counter is heap
- * specific but is maintained in the current thread to make the check
- * as fast as possible. The counter is copied back to the heap struct
- * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro.
- */
-#if defined(DUK_USE_INTERRUPT_COUNTER)
- int_ctr = thr->interrupt_counter;
- if (DUK_LIKELY(int_ctr > 0)) {
- thr->interrupt_counter = int_ctr - 1;
- } else {
- /* Trigger at zero or below */
- duk_small_uint_t exec_int_ret;
-
- /* Write curr_pc back for the debugger. */
- DUK_ASSERT(thr->callstack_top > 0);
- {
- duk_activation *act;
- act = thr->callstack + thr->callstack_top - 1;
- act->curr_pc = (duk_instr_t *) curr_pc;
- }
-
- /* Force restart caused by a function return; must recheck
- * debugger breakpoints before checking line transitions,
- * see GH-303. Restart and then handle interrupt_counter
- * zero again.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (thr->heap->dbg_force_restart) {
- DUK_DD(DUK_DDPRINT("dbg_force_restart flag forced restart execution")); /* GH-303 */
- thr->heap->dbg_force_restart = 0;
- goto restart_execution;
- }
-#endif
-
- exec_int_ret = duk__executor_interrupt(thr);
- if (exec_int_ret == DUK__INT_RESTART) {
- /* curr_pc synced back above */
- goto restart_execution;
- }
- }
-#endif /* DUK_USE_INTERRUPT_COUNTER */
-#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
- /* For cross-checking during development: ensure dispatch count
- * matches cumulative interrupt counter init value sums.
- */
- thr->heap->inst_count_exec++;
-#endif
-
-#if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG)
- {
- duk_activation *act;
- act = thr->callstack + thr->callstack_top - 1;
- DUK_ASSERT(curr_pc >= DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, DUK__FUN()));
- DUK_ASSERT(curr_pc < DUK_HCOMPILEDFUNCTION_GET_CODE_END(thr->heap, DUK__FUN()));
- DUK_UNREF(act); /* if debugging disabled */
-
- DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I",
- (long) (curr_pc - DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, DUK__FUN())),
- (unsigned long) *curr_pc,
- (long) DUK_DEC_OP(*curr_pc),
- (long) (thr->valstack_top - thr->valstack),
- (long) (thr->valstack_end - thr->valstack),
- (long) (DUK__FUN() ? DUK__FUN()->nregs : -1),
- (duk_instr_t) *curr_pc));
- }
-#endif
-
-#if defined(DUK_USE_ASSERTIONS)
- /* Quite heavy assert: check valstack policy. Improper
- * shuffle instructions can write beyond valstack_top/end
- * so this check catches them in the act.
- */
- {
- duk_tval *tv;
- tv = thr->valstack_top;
- while (tv != thr->valstack_end) {
- DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
- tv++;
- }
- }
-#endif
-
- ins = *curr_pc++;
-
- /* Typing: use duk_small_(u)int_fast_t when decoding small
- * opcode fields (op, A, B, C) and duk_(u)int_fast_t when
- * decoding larger fields (e.g. BC which is 18 bits). Use
- * unsigned variant by default, signed when the value is used
- * in signed arithmetic. Using variable names such as 'a', 'b',
- * 'c', 'bc', etc makes it easier to spot typing mismatches.
- */
-
- /* XXX: the best typing needs to be validated by perf measurement:
- * e.g. using a small type which is the cast to a larger duk_idx_t
- * may be slower than declaring the variable as a duk_idx_t in the
- * first place.
- */
-
- /* XXX: use macros for the repetitive tval/refcount handling. */
-
- switch ((int) DUK_DEC_OP(ins)) {
- /* XXX: switch cast? */
-
- case DUK_OP_LDREG: {
- duk_small_uint_fast_t a;
- duk_uint_fast_t bc;
- duk_tval *tv1, *tv2;
-
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); tv2 = DUK__REGP(bc);
- DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
- break;
- }
-
- case DUK_OP_STREG: {
- duk_small_uint_fast_t a;
- duk_uint_fast_t bc;
- duk_tval *tv1, *tv2;
-
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); tv2 = DUK__REGP(bc);
- DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1); /* side effects */
- break;
- }
-
- case DUK_OP_LDCONST: {
- duk_small_uint_fast_t a;
- duk_uint_fast_t bc;
- duk_tval *tv1, *tv2;
-
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); tv2 = DUK__CONSTP(bc);
- DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
- break;
- }
-
- case DUK_OP_LDINT: {
- duk_small_uint_fast_t a;
- duk_int_fast_t bc;
- duk_tval *tv1;
-#if defined(DUK_USE_FASTINT)
- duk_int32_t val;
-#else
- duk_double_t val;
-#endif
-
-#if defined(DUK_USE_FASTINT)
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); val = (duk_int32_t) (bc - DUK_BC_LDINT_BIAS);
- DUK_TVAL_SET_FASTINT_I32_UPDREF(thr, tv1, val); /* side effects */
-#else
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- bc = DUK_DEC_BC(ins); val = (duk_double_t) (bc - DUK_BC_LDINT_BIAS);
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv1, val); /* side effects */
-#endif
- break;
- }
-
- case DUK_OP_LDINTX: {
- duk_small_uint_fast_t a;
- duk_tval *tv1;
- duk_double_t val;
-
- /* LDINTX is not necessarily in FASTINT range, so
- * no fast path for now.
- *
- * XXX: perhaps restrict LDINTX to fastint range, wider
- * range very rarely needed.
- */
-
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- val = DUK_TVAL_GET_NUMBER(tv1) * ((duk_double_t) (1L << DUK_BC_LDINTX_SHIFT)) +
- (duk_double_t) DUK_DEC_BC(ins);
-#if defined(DUK_USE_FASTINT)
- DUK_TVAL_SET_NUMBER_CHKFAST(tv1, val);
-#else
- DUK_TVAL_SET_NUMBER(tv1, val);
-#endif
- break;
- }
-
- case DUK_OP_MPUTOBJ:
- case DUK_OP_MPUTOBJI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a;
- duk_tval *tv1;
- duk_hobject *obj;
- duk_uint_fast_t idx;
- duk_small_uint_fast_t count;
-
- /* A -> register of target object
- * B -> first register of key/value pair list
- * C -> number of key/value pairs
- */
-
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
- obj = DUK_TVAL_GET_OBJECT(tv1);
-
- idx = (duk_uint_fast_t) DUK_DEC_B(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
- count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (DUK_UNLIKELY(idx + count * 2 > (duk_uint_fast_t) duk_get_top(ctx))) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
- }
-#endif
-
- duk_push_hobject(ctx, obj);
-
- while (count > 0) {
- /* XXX: faster initialization (direct access or better primitives) */
-
- duk_push_tval(ctx, DUK__REGP(idx));
- DUK_ASSERT(duk_is_string(ctx, -1));
- duk_push_tval(ctx, DUK__REGP(idx + 1)); /* -> [... obj key value] */
- duk_xdef_prop_wec(ctx, -3); /* -> [... obj] */
-
- count--;
- idx += 2;
- }
-
- duk_pop(ctx); /* [... obj] -> [...] */
- break;
- }
-
- case DUK_OP_MPUTARR:
- case DUK_OP_MPUTARRI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a;
- duk_tval *tv1;
- duk_hobject *obj;
- duk_uint_fast_t idx;
- duk_small_uint_fast_t count;
- duk_uint32_t arr_idx;
-
- /* A -> register of target object
- * B -> first register of value data (start_index, value1, value2, ..., valueN)
- * C -> number of key/value pairs (N)
- */
-
- a = DUK_DEC_A(ins); tv1 = DUK__REGP(a);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
- obj = DUK_TVAL_GET_OBJECT(tv1);
- DUK_ASSERT(obj != NULL);
-
- idx = (duk_uint_fast_t) DUK_DEC_B(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
- count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + count + 1 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("MPUTARR out of bounds");
- }
-#endif
-
- tv1 = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
- idx++;
-
- duk_push_hobject(ctx, obj);
-
- while (count > 0) {
- /* duk_xdef_prop() will define an own property without any array
- * special behaviors. We'll need to set the array length explicitly
- * in the end. For arrays with elisions, the compiler will emit an
- * explicit SETALEN which will update the length.
- */
-
- /* XXX: because we're dealing with 'own' properties of a fresh array,
- * the array initializer should just ensure that the array has a large
- * enough array part and write the values directly into array part,
- * and finally set 'length' manually in the end (as already happens now).
- */
-
- duk_push_tval(ctx, DUK__REGP(idx)); /* -> [... obj value] */
- duk_xdef_prop_index_wec(ctx, -2, arr_idx); /* -> [... obj] */
-
- /* XXX: could use at least one fewer loop counters */
- count--;
- idx++;
- arr_idx++;
- }
-
- /* XXX: E5.1 Section 11.1.4 coerces the final length through
- * ToUint32() which is odd but happens now as a side effect of
- * 'arr_idx' type.
- */
- duk_hobject_set_length(thr, obj, (duk_uint32_t) arr_idx);
-
- duk_pop(ctx); /* [... obj] -> [...] */
- break;
- }
-
- case DUK_OP_NEW:
- case DUK_OP_NEWI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_uint_fast_t idx;
- duk_small_uint_fast_t i;
-
- /* A -> unused (reserved for flags, for consistency with DUK_OP_CALL)
- * B -> target register and start reg: constructor, arg1, ..., argN
- * (for DUK_OP_NEWI, 'b' is indirect)
- * C -> num args (N)
- */
-
- /* duk_new() will call the constuctor using duk_handle_call().
- * A constructor call prevents a yield from inside the constructor,
- * even if the constructor is an Ecmascript function.
- */
-
- /* Don't need to sync curr_pc here; duk_new() will do that
- * when it augments the created error.
- */
-
- /* XXX: unnecessary copying of values? Just set 'top' to
- * b + c, and let the return handling fix up the stack frame?
- */
-
- idx = (duk_uint_fast_t) DUK_DEC_B(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_NEWI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + c + 1 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("NEW out of bounds");
- }
-#endif
-
- duk_require_stack(ctx, (duk_idx_t) c);
- duk_push_tval(ctx, DUK__REGP(idx));
- for (i = 0; i < c; i++) {
- duk_push_tval(ctx, DUK__REGP(idx + i + 1));
- }
- duk_new(ctx, (duk_idx_t) c); /* [... constructor arg1 ... argN] -> [retval] */
- DUK_DDD(DUK_DDDPRINT("NEW -> %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_replace(ctx, (duk_idx_t) idx);
-
- /* When debugger is enabled, we need to recheck the activation
- * status after returning. This is now handled by call handling
- * and heap->dbg_force_restart.
- */
- break;
- }
-
- case DUK_OP_REGEXP: {
-#ifdef DUK_USE_REGEXP_SUPPORT
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
-
- /* A -> target register
- * B -> bytecode (also contains flags)
- * C -> escaped source
- */
-
- duk_push_tval(ctx, DUK__REGCONSTP(c));
- duk_push_tval(ctx, DUK__REGCONSTP(b)); /* -> [ ... escaped_source bytecode ] */
- duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */
- DUK_DDD(DUK_DDDPRINT("regexp instance: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
- duk_replace(ctx, (duk_idx_t) a);
-#else
- /* The compiler should never emit DUK_OP_REGEXP if there is no
- * regexp support.
- */
- DUK__INTERNAL_ERROR("no regexp support");
-#endif
-
- break;
- }
-
- case DUK_OP_CSREG:
- case DUK_OP_CSREGI: {
- /*
- * Assuming a register binds to a variable declared within this
- * function (a declarative binding), the 'this' for the call
- * setup is always 'undefined'. E5 Section 10.2.1.1.6.
- */
-
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins); /* restricted to regs */
- duk_uint_fast_t idx;
-
- /* A -> target register (A, A+1) for call setup
- * (for DUK_OP_CSREGI, 'a' is indirect)
- * B -> register containing target function (not type checked here)
- */
-
- /* XXX: direct manipulation, or duk_replace_tval() */
-
- /* Note: target registers a and a+1 may overlap with DUK__REGP(b).
- * Careful here.
- */
-
- idx = (duk_uint_fast_t) DUK_DEC_A(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_CSREGI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("CSREG out of bounds");
- }
-#endif
-
- duk_push_tval(ctx, DUK__REGP(b));
- duk_replace(ctx, (duk_idx_t) idx);
- duk_push_undefined(ctx);
- duk_replace(ctx, (duk_idx_t) (idx + 1));
- break;
- }
-
- case DUK_OP_GETVAR: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
- duk_hstring *name;
-
- tv1 = DUK__CONSTP(bc);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
- DUK_DDD(DUK_DDDPRINT("GETVAR: '%!O'", (duk_heaphdr *) name));
- act = thr->callstack + thr->callstack_top - 1;
- (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
-
- duk_pop(ctx); /* 'this' binding is not needed here */
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- case DUK_OP_PUTVAR: {
- duk_activation *act;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
- duk_hstring *name;
-
- tv1 = DUK__CONSTP(bc);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
-
- /* XXX: putvar takes a duk_tval pointer, which is awkward and
- * should be reworked.
- */
-
- tv1 = DUK__REGP(a); /* val */
- act = thr->callstack + thr->callstack_top - 1;
- duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
- break;
- }
-
- case DUK_OP_DECLVAR: {
- duk_activation *act;
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv1;
- duk_hstring *name;
- duk_small_uint_t prop_flags;
- duk_bool_t is_func_decl;
- duk_bool_t is_undef_value;
-
- tv1 = DUK__REGCONSTP(b);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
-
- is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0);
- is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0);
-
- /* XXX: declvar takes an duk_tval pointer, which is awkward and
- * should be reworked.
- */
-
- /* Compiler is responsible for selecting property flags (configurability,
- * writability, etc).
- */
- prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
-
- if (is_undef_value) {
- duk_push_undefined(ctx);
- } else {
- duk_push_tval(ctx, DUK__REGCONSTP(c));
- }
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
-
- act = thr->callstack + thr->callstack_top - 1;
- if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
- /* already declared, must update binding value */
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
- duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
- }
-
- duk_pop(ctx);
- break;
- }
-
- case DUK_OP_DELVAR: {
- duk_activation *act;
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_tval *tv1;
- duk_hstring *name;
- duk_bool_t rc;
-
- tv1 = DUK__REGCONSTP(b);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
- DUK_DDD(DUK_DDDPRINT("DELVAR '%!O'", (duk_heaphdr *) name));
- act = thr->callstack + thr->callstack_top - 1;
- rc = duk_js_delvar_activation(thr, act, name);
-
- duk_push_boolean(ctx, rc);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- case DUK_OP_CSVAR:
- case DUK_OP_CSVARI: {
- /* 'this' value:
- * E5 Section 6.b.i
- *
- * The only (standard) case where the 'this' binding is non-null is when
- * (1) the variable is found in an object environment record, and
- * (2) that object environment record is a 'with' block.
- *
- */
-
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_uint_fast_t idx;
- duk_tval *tv1;
- duk_hstring *name;
-
- tv1 = DUK__REGCONSTP(b);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
- act = thr->callstack + thr->callstack_top - 1;
- (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
-
- /* Note: target registers a and a+1 may overlap with DUK__REGCONSTP(b)
- * and DUK__REGCONSTP(c). Careful here.
- */
-
- idx = (duk_uint_fast_t) DUK_DEC_A(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_CSVARI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("CSVAR out of bounds");
- }
-#endif
-
- duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
- duk_replace(ctx, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
- break;
- }
-
- case DUK_OP_CLOSURE: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_hcompiledfunction *fun;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_hobject *fun_temp;
-
- /* A -> target reg
- * BC -> inner function index
- */
-
- DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)",
- (long) a, (long) bc, (long) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, DUK__FUN())));
-
- DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */
- DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(thr->heap, DUK__FUN()));
-
- act = thr->callstack + thr->callstack_top - 1;
- fun = (duk_hcompiledfunction *) DUK_ACT_GET_FUNC(act);
- fun_temp = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, fun)[bc];
- DUK_ASSERT(fun_temp != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(fun_temp));
-
- DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O",
- (void *) fun_temp, (duk_heaphdr *) fun_temp));
-
- if (act->lex_env == NULL) {
- DUK_ASSERT(act->var_env == NULL);
- duk_js_init_activation_environment_records_delayed(thr, act);
- }
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
-
- /* functions always have a NEWENV flag, i.e. they get a
- * new variable declaration environment, so only lex_env
- * matters here.
- */
- duk_js_push_closure(thr,
- (duk_hcompiledfunction *) fun_temp,
- act->var_env,
- act->lex_env,
- 1 /*add_auto_proto*/);
- duk_replace(ctx, (duk_idx_t) a);
-
- break;
- }
-
- case DUK_OP_GETPROP: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_bool_t rc;
-
- /* A -> target reg
- * B -> object reg/const (may be const e.g. in "'foo'[1]")
- * C -> key reg/const
- */
-
- tv_obj = DUK__REGCONSTP(b);
- tv_key = DUK__REGCONSTP(c);
- DUK_DDD(DUK_DDDPRINT("GETPROP: a=%ld obj=%!T, key=%!T",
- (long) a,
- (duk_tval *) DUK__REGCONSTP(b),
- (duk_tval *) DUK__REGCONSTP(c)));
- rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
- DUK_UNREF(rc); /* ignore */
- DUK_DDD(DUK_DDDPRINT("GETPROP --> %!T",
- (duk_tval *) duk_get_tval(ctx, -1)));
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
-
- duk_replace(ctx, (duk_idx_t) a); /* val */
- break;
- }
-
- case DUK_OP_PUTPROP: {
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_tval *tv_val;
- duk_bool_t rc;
-
- /* A -> object reg
- * B -> key reg/const
- * C -> value reg/const
- *
- * Note: intentional difference to register arrangement
- * of e.g. GETPROP; 'A' must contain a register-only value.
- */
-
- tv_obj = DUK__REGP(a);
- tv_key = DUK__REGCONSTP(b);
- tv_val = DUK__REGCONSTP(c);
- DUK_DDD(DUK_DDDPRINT("PUTPROP: obj=%!T, key=%!T, val=%!T",
- (duk_tval *) DUK__REGP(a),
- (duk_tval *) DUK__REGCONSTP(b),
- (duk_tval *) DUK__REGCONSTP(c)));
- rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
- DUK_UNREF(rc); /* ignore */
- DUK_DDD(DUK_DDDPRINT("PUTPROP --> obj=%!T, key=%!T, val=%!T",
- (duk_tval *) DUK__REGP(a),
- (duk_tval *) DUK__REGCONSTP(b),
- (duk_tval *) DUK__REGCONSTP(c)));
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
- tv_val = NULL; /* invalidated */
-
- break;
- }
-
- case DUK_OP_DELPROP: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_bool_t rc;
-
- /* A -> result reg
- * B -> object reg
- * C -> key reg/const
- */
-
- tv_obj = DUK__REGP(b);
- tv_key = DUK__REGCONSTP(c);
- rc = duk_hobject_delprop(thr, tv_obj, tv_key, DUK__STRICT());
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
-
- duk_push_boolean(ctx, rc);
- duk_replace(ctx, (duk_idx_t) a); /* result */
- break;
- }
-
- case DUK_OP_CSPROP:
- case DUK_OP_CSPROPI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_uint_fast_t idx;
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_bool_t rc;
-
- /* E5 Section 11.2.3, step 6.a.i */
- /* E5 Section 10.4.3 */
-
- /* XXX: allow object to be a const, e.g. in 'foo'.toString()?
- * On the other hand, DUK_REGCONSTP() is slower and generates
- * more code.
- */
-
- tv_obj = DUK__REGP(b);
- tv_key = DUK__REGCONSTP(c);
- rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
- DUK_UNREF(rc); /* unused */
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
-
- /* Note: target registers a and a+1 may overlap with DUK__REGP(b)
- * and DUK__REGCONSTP(c). Careful here.
- */
-
- idx = (duk_uint_fast_t) DUK_DEC_A(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_CSPROPI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("CSPROP out of bounds");
- }
-#endif
-
- duk_push_tval(ctx, DUK__REGP(b)); /* [ ... val obj ] */
- duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
- duk_replace(ctx, (duk_idx_t) idx); /* val */
- break;
- }
-
- case DUK_OP_ADD:
- case DUK_OP_SUB:
- case DUK_OP_MUL:
- case DUK_OP_DIV:
- case DUK_OP_MOD: {
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_small_uint_fast_t op = DUK_DEC_OP(ins);
-
- if (op == DUK_OP_ADD) {
- /*
- * Handling DUK_OP_ADD this way is more compact (experimentally)
- * than a separate case with separate argument decoding.
- */
- duk__vm_arith_add(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a);
- } else {
- duk__vm_arith_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
- }
- break;
- }
-
- case DUK_OP_BAND:
- case DUK_OP_BOR:
- case DUK_OP_BXOR:
- case DUK_OP_BASL:
- case DUK_OP_BLSR:
- case DUK_OP_BASR: {
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_small_uint_fast_t op = DUK_DEC_OP(ins);
-
- duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c), a, op);
- break;
- }
-
- case DUK_OP_EQ:
- case DUK_OP_NEQ: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* E5 Sections 11.9.1, 11.9.3 */
- tmp = duk_js_equals(thr, DUK__REGCONSTP(b), DUK__REGCONSTP(c));
- if (DUK_DEC_OP(ins) == DUK_OP_NEQ) {
- tmp = !tmp;
- }
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- case DUK_OP_SEQ:
- case DUK_OP_SNEQ: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* E5 Sections 11.9.1, 11.9.3 */
- tmp = duk_js_strict_equals(DUK__REGCONSTP(b), DUK__REGCONSTP(c));
- if (DUK_DEC_OP(ins) == DUK_OP_SNEQ) {
- tmp = !tmp;
- }
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- /* Note: combining comparison ops must be done carefully because
- * of uncomparable values (NaN): it's not necessarily true that
- * (x >= y) === !(x < y). Also, evaluation order matters, and
- * although it would only seem to affect the compiler this is
- * actually not the case, because there are also run-time coercions
- * of the arguments (with potential side effects).
- *
- * XXX: can be combined; check code size.
- */
-
- case DUK_OP_GT: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* x > y --> y < x */
- tmp = duk_js_compare_helper(thr,
- DUK__REGCONSTP(c), /* y */
- DUK__REGCONSTP(b), /* x */
- 0); /* flags */
-
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- case DUK_OP_GE: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* x >= y --> not (x < y) */
- tmp = duk_js_compare_helper(thr,
- DUK__REGCONSTP(b), /* x */
- DUK__REGCONSTP(c), /* y */
- DUK_COMPARE_FLAG_EVAL_LEFT_FIRST |
- DUK_COMPARE_FLAG_NEGATE); /* flags */
-
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- case DUK_OP_LT: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* x < y */
- tmp = duk_js_compare_helper(thr,
- DUK__REGCONSTP(b), /* x */
- DUK__REGCONSTP(c), /* y */
- DUK_COMPARE_FLAG_EVAL_LEFT_FIRST); /* flags */
-
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- case DUK_OP_LE: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- /* x <= y --> not (x > y) --> not (y < x) */
- tmp = duk_js_compare_helper(thr,
- DUK__REGCONSTP(c), /* y */
- DUK__REGCONSTP(b), /* x */
- DUK_COMPARE_FLAG_NEGATE); /* flags */
-
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- case DUK_OP_IF: {
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_bool_t tmp;
-
- tmp = duk_js_toboolean(DUK__REGCONSTP(b));
- if (tmp == (duk_bool_t) a) {
- /* if boolean matches A, skip next inst */
- curr_pc++;
- } else {
- ;
- }
- break;
- }
-
- case DUK_OP_JUMP: {
- duk_int_fast_t abc = DUK_DEC_ABC(ins);
-
- curr_pc += abc - DUK_BC_JUMP_BIAS;
- break;
- }
-
- case DUK_OP_RETURN: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- /* duk_small_uint_fast_t c = DUK_DEC_C(ins); */
- duk_small_uint_t ret_result;
-
- /* A -> flags
- * B -> return value reg/const
- * C -> currently unused
- */
-
- DUK__SYNC_AND_NULL_CURR_PC();
-
- /* duk__handle_return() is guaranteed never to throw, except
- * for potential out-of-memory situations which will then
- * propagate out of the executor longjmp handler.
- */
-
- if (a & DUK_BC_RETURN_FLAG_HAVE_RETVAL) {
- duk_push_tval(ctx, DUK__REGCONSTP(b));
- } else {
- duk_push_undefined(ctx);
- }
- ret_result = duk__handle_return(thr,
- entry_thread,
- entry_callstack_top);
- if (ret_result == DUK__RETHAND_RESTART) {
- goto restart_execution;
- }
- DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
-
- DUK_DDD(DUK_DDDPRINT("exiting executor after RETURN handling"));
- return;
- }
-
- case DUK_OP_CALL:
- case DUK_OP_CALLI: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_uint_fast_t idx;
- duk_small_uint_t call_flags;
- duk_small_uint_t flag_tailcall;
- duk_small_uint_t flag_evalcall;
- duk_tval *tv_func;
- duk_hobject *obj_func;
- duk_bool_t setup_rc;
- duk_idx_t num_stack_args;
-#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- duk_hcompiledfunction *fun;
-#endif
-
- /* A -> flags
- * B -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
- * (for DUK_OP_CALLI, 'b' is indirect)
- * C -> nargs
- */
-
- /* these are not necessarily 0 or 1 (may be other non-zero), that's ok */
- flag_tailcall = (a & DUK_BC_CALL_FLAG_TAILCALL);
- flag_evalcall = (a & DUK_BC_CALL_FLAG_EVALCALL);
-
- idx = (duk_uint_fast_t) DUK_DEC_B(ins);
- if (DUK_DEC_OP(ins) == DUK_OP_CALLI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (!duk_is_valid_index(ctx, (duk_idx_t) idx)) {
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("CALL out of bounds");
- }
-#endif
-
- /*
- * To determine whether to use an optimized Ecmascript-to-Ecmascript
- * call, we need to know whether the final, non-bound function is an
- * Ecmascript function.
- *
- * This is now implemented so that we start to do an ecma-to-ecma call
- * setup which will resolve the bound chain as the first thing. If the
- * final function is not eligible, the return value indicates that the
- * ecma-to-ecma call is not possible. The setup will overwrite the call
- * target at DUK__REGP(idx) with the final, non-bound function (which
- * may be a lightfunc), and fudge arguments if necessary.
- *
- * XXX: If an ecma-to-ecma call is not possible, this initial call
- * setup will do bound function chain resolution but won't do the
- * "effective this binding" resolution which is quite confusing.
- * Perhaps add a helper for doing bound function and effective this
- * binding resolution - and call that explicitly? Ecma-to-ecma call
- * setup and normal function handling can then assume this prestep has
- * been done by the caller.
- */
-
- duk_set_top(ctx, (duk_idx_t) (idx + c + 2)); /* [ ... func this arg1 ... argN ] */
-
- call_flags = 0;
- if (flag_tailcall) {
- /* We request a tail call, but in some corner cases
- * call handling can decide that a tail call is
- * actually not possible.
- * See: test-bug-tailcall-preventyield-assert.c.
- */
- call_flags |= DUK_CALL_FLAG_IS_TAILCALL;
- }
-
- /* Compared to duk_handle_call():
- * - protected call: never
- * - ignore recursion limit: never
- */
- num_stack_args = c;
- setup_rc = duk_handle_ecma_call_setup(thr,
- num_stack_args,
- call_flags);
-
- if (setup_rc) {
- /* Ecma-to-ecma call possible, may or may not be a tail call.
- * Avoid C recursion by being clever.
- */
- DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
- /* curr_pc synced by duk_handle_ecma_call_setup() */
- goto restart_execution;
- }
- DUK_ASSERT(thr->ptr_curr_pc != NULL); /* restored if ecma-to-ecma setup fails */
-
- DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call not possible, target is native (may be lightfunc)"));
-
- /* Recompute argument count: bound function handling may have shifted. */
- num_stack_args = duk_get_top(ctx) - (idx + 2);
- DUK_DDD(DUK_DDDPRINT("recomputed arg count: %ld\n", (long) num_stack_args));
-
- tv_func = DUK__REGP(idx); /* Relookup if relocated */
- if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
-
- call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- /* There is no eval() special handling here: eval() is never
- * automatically converted to a lightfunc.
- */
- DUK_ASSERT(DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func) != duk_bi_global_object_eval);
-
- 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.
- */
-#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- fun = DUK__FUN();
-#endif
- duk_set_top(ctx, (duk_idx_t) fun->nregs);
-
- /* No need to reinit setjmp() catchpoint, as call handling
- * will store and restore our state.
- */
- } else {
- /* Call setup checks callability. */
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_func));
- obj_func = DUK_TVAL_GET_OBJECT(tv_func);
- DUK_ASSERT(obj_func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(obj_func));
-
- /*
- * Other cases, use C recursion.
- *
- * If a tail call was requested we ignore it and execute a normal call.
- * Since Duktape 0.11.0 the compiler emits a RETURN opcode even after
- * a tail call to avoid test-bug-tailcall-thread-yield-resume.js.
- *
- * Direct eval call: (1) call target (before following bound function
- * chain) is the built-in eval() function, and (2) call was made with
- * the identifier 'eval'.
- */
-
- call_flags = 0; /* not protected, respect reclimit, not constructor */
-
- if (DUK_HOBJECT_IS_NATIVEFUNCTION(obj_func) &&
- ((duk_hnativefunction *) obj_func)->func == duk_bi_global_object_eval) {
- if (flag_evalcall) {
- DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was 'eval' -> direct eval"));
- call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
- } else {
- DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was not 'eval' -> indirect eval"));
- }
- }
-
- 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.
- */
-#if !defined(DUK_USE_EXEC_FUN_LOCAL)
- fun = DUK__FUN();
-#endif
- duk_set_top(ctx, (duk_idx_t) fun->nregs);
-
- /* No need to reinit setjmp() catchpoint, as call handling
- * will store and restore our state.
- */
- }
-
- /* When debugger is enabled, we need to recheck the activation
- * status after returning. This is now handled by call handling
- * and heap->dbg_force_restart.
- */
- break;
- }
-
- case DUK_OP_TRYCATCH: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_catcher *cat;
- duk_tval *tv1;
- duk_small_uint_fast_t a;
- duk_uint_fast_t bc;
-
- /* A -> flags
- * BC -> reg_catch; base register for two registers used both during
- * trycatch setup and when catch is triggered
- *
- * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
- * reg_catch + 0: catch binding variable name (string).
- * Automatic declarative environment is established for
- * the duration of the 'catch' clause.
- *
- * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
- * reg_catch + 0: with 'target value', which is coerced to
- * an object and then used as a bindind object for an
- * environment record. The binding is initialized here, for
- * the 'try' clause.
- *
- * Note that a TRYCATCH generated for a 'with' statement has no
- * catch or finally parts.
- */
-
- /* XXX: TRYCATCH handling should be reworked to avoid creating
- * an explicit scope unless it is actually needed (e.g. function
- * instances or eval is executed inside the catch block). This
- * rework is not trivial because the compiler doesn't have an
- * intermediate representation. When the rework is done, the
- * opcode format can also be made more straightforward.
- */
-
- /* XXX: side effect handling is quite awkward here */
-
- DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
- "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
- (long) DUK_DEC_BC(ins),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
- (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
- (unsigned long) DUK_DEC_A(ins)));
-
- a = DUK_DEC_A(ins);
- bc = DUK_DEC_BC(ins);
-
- act = thr->callstack + thr->callstack_top - 1;
- DUK_ASSERT(thr->callstack_top >= 1);
-
- /* 'with' target must be created first, in case we run out of memory */
- /* XXX: refactor out? */
-
- if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
- DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object"));
-
- if (act->lex_env == NULL) {
- DUK_ASSERT(act->var_env == NULL);
- DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
-
- /* must relookup act in case of side effects */
- duk_js_init_activation_environment_records_delayed(thr, act);
- act = thr->callstack + thr->callstack_top - 1;
- DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
- }
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
-
- (void) duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
- -1); /* no prototype, updated below */
-
- duk_push_tval(ctx, DUK__REGP(bc));
- duk_to_object(ctx, -1);
- duk_dup(ctx, -1);
-
- /* [ ... env target ] */
- /* [ ... env target target ] */
-
- duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */
-
- /* [ ... env ] */
-
- DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT",
- (duk_tval *) duk_get_tval(ctx, -1)));
- }
-
- /* allocate catcher and populate it (should be atomic) */
-
- duk_hthread_catchstack_grow(thr);
- cat = thr->catchstack + thr->catchstack_top;
- DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size);
- thr->catchstack_top++;
-
- cat->flags = DUK_CAT_TYPE_TCF;
- cat->h_varname = NULL;
-
- if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
- cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
- }
- if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
- cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
- }
- if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
- DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
- cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
- tv1 = DUK__REGP(bc);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
-
- /* borrowed reference; although 'tv1' comes from a register,
- * its value was loaded using LDCONST so the constant will
- * also exist and be reachable.
- */
- cat->h_varname = DUK_TVAL_GET_STRING(tv1);
- } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
- /* env created above to stack top */
- duk_hobject *new_env;
-
- DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher"));
- cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
-
- DUK_DDD(DUK_DDDPRINT("activating object env: %!iT",
- (duk_tval *) duk_get_tval(ctx, -1)));
- DUK_ASSERT(act->lex_env != NULL);
- new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
- DUK_ASSERT(new_env != NULL);
-
- act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */
-
- act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
- act->lex_env = new_env;
- DUK_HOBJECT_INCREF(thr, new_env);
- duk_pop(ctx);
- } else {
- ;
- }
-
- /* Registers 'bc' and 'bc + 1' are written in longjmp handling
- * and if their previous values (which are temporaries) become
- * unreachable -and- have a finalizer, there'll be a function
- * call during error handling which is not supported now (GH-287).
- * Ensure that both 'bc' and 'bc + 1' have primitive values to
- * guarantee no finalizer calls in error handling. Scrubbing also
- * ensures finalizers for the previous values run here rather than
- * later. Error handling related values are also written to 'bc'
- * and 'bc + 1' but those values never become unreachable during
- * error handling, so there's no side effect problem even if the
- * error value has a finalizer.
- */
- duk_to_undefined(ctx, bc);
- duk_to_undefined(ctx, bc + 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */
- cat->callstack_index = thr->callstack_top - 1;
- cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
- cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
-
- DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
- "idx_base=%ld, h_varname=%!O",
- (unsigned long) cat->flags, (long) cat->callstack_index,
- (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
-
- curr_pc += 2; /* skip jump slots */
- break;
- }
-
- /* Pre/post inc/dec for register variables, important for loops. */
- case DUK_OP_PREINCR:
- case DUK_OP_PREDECR:
- case DUK_OP_POSTINCR:
- case DUK_OP_POSTDECR: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1, *tv2;
- duk_double_t x, y, z;
-
- /* Two lowest bits of opcode are used to distinguish
- * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
- */
- DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00);
- DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01);
- DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02);
- DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03);
-
- tv1 = DUK__REGP(bc);
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv1)) {
- duk_int64_t x_fi, y_fi, z_fi;
- x_fi = DUK_TVAL_GET_FASTINT(tv1);
- if (ins & DUK_ENC_OP(0x01)) {
- if (x_fi == DUK_FASTINT_MIN) {
- goto skip_fastint;
- }
- y_fi = x_fi - 1;
- } else {
- if (x_fi == DUK_FASTINT_MAX) {
- goto skip_fastint;
- }
- y_fi = x_fi + 1;
- }
-
- DUK_TVAL_SET_FASTINT(tv1, y_fi); /* no need for refcount update */
-
- tv2 = DUK__REGP(a);
- z_fi = (ins & DUK_ENC_OP(0x02)) ? x_fi : y_fi;
- DUK_TVAL_SET_FASTINT_UPDREF(thr, tv2, z_fi); /* side effects */
- break;
- }
- skip_fastint:
-#endif
- if (DUK_TVAL_IS_NUMBER(tv1)) {
- /* Fast path for the case where the register
- * is a number (e.g. loop counter).
- */
-
- x = DUK_TVAL_GET_NUMBER(tv1);
- if (ins & DUK_ENC_OP(0x01)) {
- y = x - 1.0;
- } else {
- y = x + 1.0;
- }
-
- DUK_TVAL_SET_NUMBER(tv1, y); /* no need for refcount update */
- } else {
- x = duk_to_number(ctx, bc);
-
- if (ins & DUK_ENC_OP(0x01)) {
- y = x - 1.0;
- } else {
- y = x + 1.0;
- }
-
- duk_push_number(ctx, y);
- duk_replace(ctx, bc);
- }
-
- tv2 = DUK__REGP(a);
- z = (ins & DUK_ENC_OP(0x02)) ? x : y;
- DUK_TVAL_SET_NUMBER_UPDREF(thr, tv2, z); /* side effects */
- break;
- }
-
- /* Preinc/predec for var-by-name, slow path. */
- case DUK_OP_PREINCV:
- case DUK_OP_PREDECV:
- case DUK_OP_POSTINCV:
- case DUK_OP_POSTDECV: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_double_t x, y;
- duk_tval *tv1;
- duk_hstring *name;
-
- /* Two lowest bits of opcode are used to distinguish
- * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
- */
- DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00);
- DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01);
- DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02);
- DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03);
-
- tv1 = DUK__CONSTP(bc);
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
- name = DUK_TVAL_GET_STRING(tv1);
- DUK_ASSERT(name != NULL);
- act = thr->callstack + thr->callstack_top - 1;
- (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
-
- /* XXX: fastint fast path would be very useful here */
-
- x = duk_to_number(ctx, -2);
- duk_pop_2(ctx);
- if (ins & DUK_ENC_OP(0x01)) {
- y = x - 1.0;
- } else {
- y = x + 1.0;
- }
-
- duk_push_number(ctx, y);
- tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(tv1 != NULL);
- duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
- duk_pop(ctx);
-
- duk_push_number(ctx, (ins & DUK_ENC_OP(0x02)) ? x : y);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- /* Preinc/predec for object properties. */
- case DUK_OP_PREINCP:
- case DUK_OP_PREDECP:
- case DUK_OP_POSTINCP:
- case DUK_OP_POSTDECP: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t a = DUK_DEC_A(ins);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_tval *tv_obj;
- duk_tval *tv_key;
- duk_tval *tv_val;
- duk_bool_t rc;
- duk_double_t x, y;
-
- /* A -> target reg
- * B -> object reg/const (may be const e.g. in "'foo'[1]")
- * C -> key reg/const
- */
-
- /* Two lowest bits of opcode are used to distinguish
- * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
- */
- DUK_ASSERT((DUK_OP_PREINCP & 0x03) == 0x00);
- DUK_ASSERT((DUK_OP_PREDECP & 0x03) == 0x01);
- DUK_ASSERT((DUK_OP_POSTINCP & 0x03) == 0x02);
- DUK_ASSERT((DUK_OP_POSTDECP & 0x03) == 0x03);
-
- tv_obj = DUK__REGCONSTP(b);
- tv_key = DUK__REGCONSTP(c);
- rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
- DUK_UNREF(rc); /* ignore */
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
-
- x = duk_to_number(ctx, -1);
- duk_pop(ctx);
- if (ins & DUK_ENC_OP(0x01)) {
- y = x - 1.0;
- } else {
- y = x + 1.0;
- }
-
- duk_push_number(ctx, y);
- tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1);
- DUK_ASSERT(tv_val != NULL);
- tv_obj = DUK__REGCONSTP(b);
- tv_key = DUK__REGCONSTP(c);
- rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
- DUK_UNREF(rc); /* ignore */
- tv_obj = NULL; /* invalidated */
- tv_key = NULL; /* invalidated */
- duk_pop(ctx);
-
- duk_push_number(ctx, (ins & DUK_ENC_OP(0x02)) ? x : y);
- duk_replace(ctx, (duk_idx_t) a);
- break;
- }
-
- case DUK_OP_EXTRA: {
- /* XXX: shared decoding of 'b' and 'c'? */
-
- duk_small_uint_fast_t extraop = DUK_DEC_A(ins);
- switch ((int) extraop) {
- /* XXX: switch cast? */
-
- case DUK_EXTRAOP_NOP: {
- /* nop */
- break;
- }
-
- case DUK_EXTRAOP_INVALID: {
- DUK_ERROR_FMT1(thr, DUK_ERR_INTERNAL_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_BC(ins));
- break;
- }
-
- case DUK_EXTRAOP_LDTHIS: {
- /* Note: 'this' may be bound to any value, not just an object */
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1, *tv2;
-
- tv1 = DUK__REGP(bc);
- tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */
- DUK_ASSERT(tv2 >= thr->valstack);
-
- DUK_DDD(DUK_DDDPRINT("LDTHIS: %!T to r%ld", (duk_tval *) tv2, (long) bc));
-
- DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
- break;
- }
-
- case DUK_EXTRAOP_LDUNDEF: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
-
- tv1 = DUK__REGP(bc);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
- break;
- }
-
- case DUK_EXTRAOP_LDNULL: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
-
- tv1 = DUK__REGP(bc);
- DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */
- break;
- }
-
- case DUK_EXTRAOP_LDTRUE:
- case DUK_EXTRAOP_LDFALSE: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
- duk_small_uint_fast_t bval = (extraop == DUK_EXTRAOP_LDTRUE ? 1 : 0);
-
- tv1 = DUK__REGP(bc);
- DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, bval); /* side effects */
- break;
- }
-
- case DUK_EXTRAOP_NEWOBJ: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
-
- duk_push_object(ctx);
- duk_replace(ctx, (duk_idx_t) b);
- break;
- }
-
- case DUK_EXTRAOP_NEWARR: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
-
- duk_push_array(ctx);
- duk_replace(ctx, (duk_idx_t) b);
- break;
- }
-
- case DUK_EXTRAOP_SETALEN: {
- duk_small_uint_fast_t b;
- duk_small_uint_fast_t c;
- duk_tval *tv1;
- duk_hobject *h;
- duk_uint32_t len;
-
- b = DUK_DEC_B(ins); tv1 = DUK__REGP(b);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
- h = DUK_TVAL_GET_OBJECT(tv1);
-
- c = DUK_DEC_C(ins); tv1 = DUK__REGP(c);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
-
- duk_hobject_set_length(thr, h, len);
-
- break;
- }
-
- case DUK_EXTRAOP_TYPEOF: {
- duk_context *ctx = (duk_context *) thr;
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_push_hstring(ctx, duk_js_typeof(thr, DUK__REGP(bc)));
- duk_replace(ctx, (duk_idx_t) bc);
- break;
- }
-
- case DUK_EXTRAOP_TYPEOFID: {
- duk_context *ctx = (duk_context *) thr;
- duk_activation *act;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_hstring *name;
- duk_tval *tv;
-
- /* B -> target register
- * C -> constant index of identifier name
- */
-
- tv = DUK__REGCONSTP(c); /* XXX: this could be a DUK__CONSTP instead */
- DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
- name = DUK_TVAL_GET_STRING(tv);
- act = thr->callstack + thr->callstack_top - 1;
- if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
- /* -> [... val this] */
- tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
- duk_push_hstring(ctx, duk_js_typeof(thr, tv));
- duk_replace(ctx, (duk_idx_t) b);
- duk_pop_2(ctx);
- } else {
- /* unresolvable, no stack changes */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
- duk_replace(ctx, (duk_idx_t) b);
- }
-
- break;
- }
-
- case DUK_EXTRAOP_INITENUM: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
-
- /*
- * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
- * If called with 'null' or 'undefined', this opcode returns 'null' as
- * the enumerator, which is special cased in NEXTENUM. This simplifies
- * the compiler part
- */
-
- /* B -> register for writing enumerator object
- * C -> value to be enumerated (register)
- */
-
- if (duk_is_null_or_undefined(ctx, (duk_idx_t) c)) {
- duk_push_null(ctx);
- duk_replace(ctx, (duk_idx_t) b);
- } else {
- duk_dup(ctx, (duk_idx_t) c);
- duk_to_object(ctx, -1);
- duk_hobject_enumerator_create(ctx, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
- duk_replace(ctx, (duk_idx_t) b);
- }
- break;
- }
-
- case DUK_EXTRAOP_NEXTENUM: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
-
- /*
- * NEXTENUM checks whether the enumerator still has unenumerated
- * keys. If so, the next key is loaded to the target register
- * and the next instruction is skipped. Otherwise the next instruction
- * will be executed, jumping out of the enumeration loop.
- */
-
- /* B -> target register for next key
- * C -> enum register
- */
-
- DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
- (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b),
- (duk_tval *) duk_get_tval(ctx, (duk_idx_t) c)));
-
- if (duk_is_object(ctx, (duk_idx_t) c)) {
- /* XXX: assert 'c' is an enumerator */
- duk_dup(ctx, (duk_idx_t) c);
- if (duk_hobject_enumerator_next(ctx, 0 /*get_value*/)) {
- /* [ ... enum ] -> [ ... next_key ] */
- DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
- (duk_tval *) duk_get_tval(ctx, -1)));
- curr_pc++;
- } else {
- /* [ ... enum ] -> [ ... ] */
- DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
- duk_push_undefined(ctx);
- }
- duk_replace(ctx, (duk_idx_t) b);
- } else {
- /* 'null' enumerator case -> behave as with an empty enumerator */
- DUK_ASSERT(duk_is_null(ctx, (duk_idx_t) c));
- DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
- }
- break;
- }
-
- case DUK_EXTRAOP_INITSET:
- case DUK_EXTRAOP_INITSETI:
- case DUK_EXTRAOP_INITGET:
- case DUK_EXTRAOP_INITGETI: {
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t is_set = (extraop == DUK_EXTRAOP_INITSET || extraop == DUK_EXTRAOP_INITSETI);
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_uint_fast_t idx;
-
- /* B -> object register
- * C -> C+0 contains key, C+1 closure (value)
- */
-
- /*
- * INITSET/INITGET are only used to initialize object literal keys.
- * The compiler ensures that there cannot be a previous data property
- * of the same name. It also ensures that setter and getter can only
- * be initialized once (or not at all).
- */
-
- idx = (duk_uint_fast_t) DUK_DEC_C(ins);
- if (extraop == DUK_EXTRAOP_INITSETI || extraop == DUK_EXTRAOP_INITGETI) {
- duk_tval *tv_ind = DUK__REGP(idx);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind));
- idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind);
- }
-
-#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
- if (idx + 2 > (duk_uint_fast_t) duk_get_top(ctx)) {
- /* XXX: use duk_is_valid_index() instead? */
- /* XXX: improve check; check against nregs, not against top */
- DUK__INTERNAL_ERROR("INITSET/INITGET out of bounds");
- }
-#endif
-
- /* XXX: this is now a very unoptimal implementation -- this can be
- * made very simple by direct manipulation of the object internals,
- * given the guarantees above.
- */
-
- duk_push_hobject_bidx(ctx, DUK_BIDX_OBJECT_CONSTRUCTOR);
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_DEFINE_PROPERTY);
- duk_push_undefined(ctx);
- duk_dup(ctx, (duk_idx_t) b);
- duk_dup(ctx, (duk_idx_t) (idx + 0));
- duk_push_object(ctx); /* -> [ Object defineProperty undefined obj key desc ] */
-
- duk_push_true(ctx);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_ENUMERABLE);
- duk_push_true(ctx);
- duk_put_prop_stridx(ctx, -2, DUK_STRIDX_CONFIGURABLE);
- duk_dup(ctx, (duk_idx_t) (idx + 1));
- duk_put_prop_stridx(ctx, -2, (is_set ? DUK_STRIDX_SET : DUK_STRIDX_GET));
-
- DUK_DDD(DUK_DDDPRINT("INITGET/INITSET: obj=%!T, key=%!T, desc=%!T",
- (duk_tval *) duk_get_tval(ctx, -3),
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- duk_call_method(ctx, 3); /* -> [ Object res ] */
- duk_pop_2(ctx);
-
- DUK_DDD(DUK_DDDPRINT("INITGET/INITSET AFTER: obj=%!T",
- (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b)));
- break;
- }
-
- case DUK_EXTRAOP_ENDTRY: {
- duk_catcher *cat;
- duk_tval *tv1;
-
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
-
- DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
- DUK_CAT_CLEAR_CATCH_ENABLED(cat);
-
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
- tv1 = NULL;
-
- tv1 = thr->valstack + cat->idx_base + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
- tv1 = NULL;
-
- DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
- } else {
- DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- }
-
- curr_pc = cat->pc_base + 1;
- break;
- }
-
- case DUK_EXTRAOP_ENDCATCH: {
- duk_activation *act;
- duk_catcher *cat;
- duk_tval *tv1;
-
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
-
- act = thr->callstack + thr->callstack_top - 1;
-
- if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
- duk_hobject *prev_env;
-
- /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
- DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
- DUK_ASSERT(act->lex_env != NULL);
-
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
-
- prev_env = act->lex_env;
- DUK_ASSERT(prev_env != NULL);
- act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
- DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
- DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
- }
-
- if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
- tv1 = NULL;
-
- tv1 = thr->valstack + cat->idx_base + 1;
- DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
- DUK_TVAL_SET_FASTINT_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
- tv1 = NULL;
-
- DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
- } else {
- DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- }
-
- curr_pc = cat->pc_base + 1;
- break;
- }
-
- case DUK_EXTRAOP_ENDFIN: {
- duk_context *ctx = (duk_context *) thr;
- duk_catcher *cat;
- duk_tval *tv1;
- duk_small_uint_t cont_type;
- duk_small_uint_t ret_result;
-
- /* Sync and NULL early. */
- DUK__SYNC_AND_NULL_CURR_PC();
-
- DUK_ASSERT(thr->catchstack_top >= 1);
- DUK_ASSERT(thr->callstack_top >= 1);
- DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
-
- /* CATCH flag may be enabled or disabled here; it may be enabled if
- * the statement has a catch block but the try block does not throw
- * an error.
- */
- DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
- /* XXX: assert idx_base */
-
- DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
- (duk_tval *) (thr->valstack + cat->idx_base + 0),
- (duk_tval *) (thr->valstack + cat->idx_base + 1)));
-
- tv1 = thr->valstack + cat->idx_base + 1; /* type */
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
- cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
-
- switch (cont_type) {
- case DUK_LJ_TYPE_NORMAL: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
- "dismantle catcher, resume execution after ENDFIN"));
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- goto restart_execution;
- }
- case DUK_LJ_TYPE_RETURN: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
- "catcher, handle return, lj.value1=%!T", thr->valstack + cat->idx_base));
-
- /* Not necessary to unwind catchstack: return handling will
- * do it. The finally flag of 'cat' is no longer set. The
- * catch flag may be set, but it's not checked by return handling.
- */
- DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
-#if 0
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
-#endif
-
- duk_push_tval(ctx, thr->valstack + cat->idx_base);
- ret_result = duk__handle_return(thr,
- entry_thread,
- entry_callstack_top);
- if (ret_result == DUK__RETHAND_RESTART) {
- goto restart_execution;
- }
- DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
-
- DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
- return;
- }
- case DUK_LJ_TYPE_BREAK:
- case DUK_LJ_TYPE_CONTINUE: {
- duk_uint_t label_id;
- duk_small_uint_t lj_type;
-
- /* Not necessary to unwind catchstack: break/continue
- * handling will do it. The finally flag of 'cat' is
- * no longer set. The catch flag may be set, but it's
- * not checked by break/continue handling.
- */
-#if 0
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
-#endif
-
- tv1 = thr->valstack + cat->idx_base;
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
-#if defined(DUK_USE_FASTINT)
- DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
- label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
-#else
- label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
-#endif
- lj_type = cont_type;
- duk__handle_break_or_continue(thr, label_id, lj_type);
- goto restart_execution;
- }
- default: {
- DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
- "dismantle catcher, re-throw error",
- (long) cont_type));
-
- duk_push_tval(ctx, thr->valstack + cat->idx_base);
-
- duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type);
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
- }
- }
-
- /* Must restart in all cases because we NULLed thr->ptr_curr_pc. */
- DUK_UNREACHABLE();
- break;
- }
-
- case DUK_EXTRAOP_THROW: {
- duk_context *ctx = (duk_context *) thr;
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-
- /* Note: errors are augmented when they are created, not
- * when they are thrown. So, don't augment here, it would
- * break re-throwing for instance.
- */
-
- /* Sync so that augmentation sees up-to-date activations, NULL
- * thr->ptr_curr_pc so that it's not used if side effects occur
- * in augmentation or longjmp handling.
- */
- DUK__SYNC_AND_NULL_CURR_PC();
-
- duk_dup(ctx, (duk_idx_t) bc);
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
-#if defined(DUK_USE_AUGMENT_ERROR_THROW)
- duk_err_augment_error_throw(thr);
- DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
- (duk_tval *) duk_get_tval(ctx, -1)));
-#endif
-
- duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
-
- DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
- duk_err_longjmp(thr);
- DUK_UNREACHABLE();
- break;
- }
-
- case DUK_EXTRAOP_INVLHS: {
- DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "invalid lvalue");
-
- DUK_UNREACHABLE();
- break;
- }
-
- case DUK_EXTRAOP_UNM:
- case DUK_EXTRAOP_UNP: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk__vm_arith_unary_op(thr, DUK__REGP(bc), bc, extraop);
- break;
- }
-
- case DUK_EXTRAOP_DEBUGGER: {
- /* Opcode only emitted by compiler when debugger
- * support is enabled. Ignore it silently without
- * debugger support, in case it has been loaded
- * from precompiled bytecode.
- */
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
- DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution"));
- DUK__SYNC_AND_NULL_CURR_PC();
- duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
- DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution"));
- goto restart_execution;
- } else {
- DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached"));
- }
-#else
- DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support"));
-#endif
- break;
- }
-
- case DUK_EXTRAOP_BREAK: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-
- DUK_DDD(DUK_DDDPRINT("BREAK: %ld", (long) bc));
-
- DUK__SYNC_AND_NULL_CURR_PC();
- duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK);
- goto restart_execution;
- }
-
- case DUK_EXTRAOP_CONTINUE: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-
- DUK_DDD(DUK_DDDPRINT("CONTINUE: %ld", (long) bc));
-
- DUK__SYNC_AND_NULL_CURR_PC();
- duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE);
- goto restart_execution;
- }
-
- case DUK_EXTRAOP_BNOT: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-
- duk__vm_bitwise_not(thr, DUK__REGP(bc), bc);
- break;
- }
-
- case DUK_EXTRAOP_LNOT: {
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
- duk_tval *tv1;
-
- tv1 = DUK__REGP(bc);
- duk__vm_logical_not(thr, tv1, tv1);
- break;
- }
-
- case DUK_EXTRAOP_INSTOF: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- tmp = duk_js_instanceof(thr, DUK__REGP(b), DUK__REGCONSTP(c));
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) b);
- break;
- }
-
- case DUK_EXTRAOP_IN: {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_fast_t b = DUK_DEC_B(ins);
- duk_small_uint_fast_t c = DUK_DEC_C(ins);
- duk_bool_t tmp;
-
- tmp = duk_js_in(thr, DUK__REGP(b), DUK__REGCONSTP(c));
- duk_push_boolean(ctx, tmp);
- duk_replace(ctx, (duk_idx_t) b);
- break;
- }
-
- case DUK_EXTRAOP_LABEL: {
- duk_catcher *cat;
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-
- /* allocate catcher and populate it (should be atomic) */
-
- duk_hthread_catchstack_grow(thr);
- cat = thr->catchstack + thr->catchstack_top;
- thr->catchstack_top++;
-
- cat->flags = DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT);
- cat->callstack_index = thr->callstack_top - 1;
- cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
- cat->idx_base = 0; /* unused for label */
- cat->h_varname = NULL;
-
- DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
- "idx_base=%ld, h_varname=%!O, label_id=%ld",
- (long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base,
- (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
-
- curr_pc += 2; /* skip jump slots */
- break;
- }
-
- case DUK_EXTRAOP_ENDLABEL: {
- duk_catcher *cat;
-#if defined(DUK_USE_DDDPRINT) || defined(DUK_USE_ASSERTIONS)
- duk_uint_fast_t bc = DUK_DEC_BC(ins);
-#endif
-#if defined(DUK_USE_DDDPRINT)
- DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
-#endif
-
- DUK_ASSERT(thr->catchstack_top >= 1);
-
- cat = thr->catchstack + thr->catchstack_top - 1;
- DUK_UNREF(cat);
- DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
- DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(cat) == bc);
-
- duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
- /* no need to unwind callstack */
- break;
- }
-
- default: {
- DUK__INTERNAL_ERROR("invalid extra opcode");
- }
-
- } /* end switch */
-
- break;
- }
-
- default: {
- /* this should never be possible, because the switch-case is
- * comprehensive
- */
- DUK__INTERNAL_ERROR("invalid opcode");
- break;
- }
-
- } /* end switch */
- }
- DUK_UNREACHABLE();
-
-#ifndef DUK_USE_VERBOSE_EXECUTOR_ERRORS
- internal_error:
- DUK_ERROR_INTERNAL(thr, "internal error in bytecode executor");
-#endif
-}
-
-#undef DUK__LONGJMP_RESTART
-#undef DUK__LONGJMP_FINISHED
-#undef DUK__LONGJMP_RETHROW
-
-#undef DUK__RETHAND_RESTART
-#undef DUK__RETHAND_FINISHED
-
-#undef DUK__FUN
-#undef DUK__STRICT
-#undef DUK__REG
-#undef DUK__REGP
-#undef DUK__CONST
-#undef DUK__CONSTP
-#undef DUK__RCISREG
-#undef DUK__REGCONST
-#undef DUK__REGCONSTP
-
-#undef DUK__INTERNAL_ERROR
-#undef DUK__SYNC_CURR_PC
-#undef DUK__SYNC_AND_NULL_CURR_PC
-#line 1 "duk_js_ops.c"
-/*
- * Ecmascript specification algorithm and conversion helpers.
- *
- * These helpers encapsulate the primitive Ecmascript operation
- * semantics, and are used by the bytecode executor and the API
- * (among other places). Note that some primitives are only
- * implemented as part of the API and have no "internal" helper.
- * (This is the case when an internal helper would not really be
- * useful; e.g. the operation is rare, uses value stack heavily,
- * etc.)
- *
- * The operation arguments depend on what is required to implement
- * the operation:
- *
- * - If an operation is simple and stateless, and has no side
- * effects, it won't take an duk_hthread argument and its
- * arguments may be duk_tval pointers (which are safe as long
- * as no side effects take place).
- *
- * - If complex coercions are required (e.g. a "ToNumber" coercion)
- * or errors may be thrown, the operation takes an duk_hthread
- * argument. This also implies that the operation may have
- * arbitrary side effects, invalidating any duk_tval pointers.
- *
- * - For operations with potential side effects, arguments can be
- * taken in several ways:
- *
- * a) as duk_tval pointers, which makes sense if the "common case"
- * can be resolved without side effects (e.g. coercion); the
- * arguments are pushed to the valstack for coercion if
- * necessary
- *
- * b) as duk_tval values
- *
- * c) implicitly on value stack top
- *
- * d) as indices to the value stack
- *
- * Future work:
- *
- * - Argument styles may not be the most sensible in every case now.
- *
- * - In-place coercions might be useful for several operations, if
- * in-place coercion is OK for the bytecode executor and the API.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * [[DefaultValue]] (E5 Section 8.12.8)
- *
- * ==> implemented in the API.
- */
-
-/*
- * ToPrimitive() (E5 Section 9.1)
- *
- * ==> implemented in the API.
- */
-
-/*
- * ToBoolean() (E5 Section 9.2)
- */
-
-DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED:
- case DUK_TAG_NULL:
- return 0;
- case DUK_TAG_BOOLEAN:
- return DUK_TVAL_GET_BOOLEAN(tv);
- case DUK_TAG_STRING: {
- duk_hstring *h = DUK_TVAL_GET_STRING(tv);
- DUK_ASSERT(h != NULL);
- return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
- }
- case DUK_TAG_OBJECT: {
- return 1;
- }
- case DUK_TAG_BUFFER: {
- /* mimic semantics for strings */
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- DUK_ASSERT(h != NULL);
- return (DUK_HBUFFER_GET_SIZE(h) > 0 ? 1 : 0);
- }
- case DUK_TAG_POINTER: {
- void *p = DUK_TVAL_GET_POINTER(tv);
- return (p != NULL ? 1 : 0);
- }
- case DUK_TAG_LIGHTFUNC: {
- return 1;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
- if (DUK_TVAL_GET_FASTINT(tv) != 0) {
- return 1;
- } else {
- return 0;
- }
-#endif
- default: {
- /* number */
- duk_double_t d;
- int c;
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
- d = DUK_TVAL_GET_DOUBLE(tv);
- c = DUK_FPCLASSIFY((double) d);
- if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
- return 0;
- } else {
- return 1;
- }
- }
- }
- DUK_UNREACHABLE();
-}
-
-/*
- * ToNumber() (E5 Section 9.3)
- *
- * Value to convert must be on stack top, and is popped before exit.
- *
- * See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
- * http://www.cs.indiana.edu/~burger/fp/index.html
- *
- * Notes on the conversion:
- *
- * - There are specific requirements on the accuracy of the conversion
- * through a "Mathematical Value" (MV), so this conversion is not
- * trivial.
- *
- * - Quick rejects (e.g. based on first char) are difficult because
- * the grammar allows leading and trailing white space.
- *
- * - Quick reject based on string length is difficult even after
- * accounting for white space; there may be arbitrarily many
- * decimal digits.
- *
- * - Standard grammar allows decimal values ("123"), hex values
- * ("0x123") and infinities
- *
- * - Unlike source code literals, ToNumber() coerces empty strings
- * and strings with only whitespace to zero (not NaN).
- */
-
-/* E5 Section 9.3.1 */
-DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_small_uint_t s2n_flags;
- duk_double_t d;
-
- /* Quite lenient, e.g. allow empty as zero, but don't allow trailing
- * garbage.
- */
- s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
- DUK_S2N_FLAG_ALLOW_EXP |
- DUK_S2N_FLAG_ALLOW_PLUS |
- DUK_S2N_FLAG_ALLOW_MINUS |
- DUK_S2N_FLAG_ALLOW_INF |
- DUK_S2N_FLAG_ALLOW_FRAC |
- DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
- DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
- DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
- DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
- DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
-
- duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
- d = duk_get_number(ctx, -1);
- duk_pop(ctx);
-
- return d;
-}
-
-DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
- duk_context *ctx = (duk_hthread *) thr;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(tv != NULL);
-
- switch (DUK_TVAL_GET_TAG(tv)) {
- case DUK_TAG_UNDEFINED: {
- /* return a specific NaN (although not strictly necessary) */
- duk_double_union du;
- DUK_DBLUNION_SET_NAN(&du);
- DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
- return du.d;
- }
- case DUK_TAG_NULL: {
- /* +0.0 */
- return 0.0;
- }
- case DUK_TAG_BOOLEAN: {
- if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
- return 1.0;
- }
- return 0.0;
- }
- case DUK_TAG_STRING: {
- duk_hstring *h = DUK_TVAL_GET_STRING(tv);
- duk_push_hstring(ctx, h);
- return duk__tonumber_string_raw(thr);
- }
- case DUK_TAG_OBJECT: {
- /* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint),
- * so use [[DefaultValue]] directly.
- */
- duk_double_t d;
- duk_push_tval(ctx, tv);
- duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
-
- /* recursive call for a primitive value (guaranteed not to cause second
- * recursion).
- */
- d = duk_js_tonumber(thr, duk_require_tval(ctx, -1));
-
- duk_pop(ctx);
- return d;
- }
- case DUK_TAG_BUFFER: {
- /* Coerce like a string. This makes sense because addition also treats
- * buffers like strings.
- */
- duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
- duk_push_hbuffer(ctx, h);
- duk_to_string(ctx, -1); /* XXX: expensive, but numconv now expects to see a string */
- return duk__tonumber_string_raw(thr);
- }
- case DUK_TAG_POINTER: {
- /* Coerce like boolean */
- void *p = DUK_TVAL_GET_POINTER(tv);
- return (p != NULL ? 1.0 : 0.0);
- }
- case DUK_TAG_LIGHTFUNC: {
- /* +(function(){}) -> NaN */
- return DUK_DOUBLE_NAN;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
- return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
-#endif
- default: {
- /* number */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
- DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
- return DUK_TVAL_GET_DOUBLE(tv);
- }
- }
-
- DUK_UNREACHABLE();
-}
-
-/*
- * ToInteger() (E5 Section 9.4)
- */
-
-/* exposed, used by e.g. duk_bi_date.c */
-DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
- duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
-
- if (c == DUK_FP_NAN) {
- return 0.0;
- } else if (c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
- /* XXX: FP_ZERO check can be removed, the else clause handles it
- * correctly (preserving sign).
- */
- return x;
- } else {
- duk_small_int_t s = (duk_small_int_t) DUK_SIGNBIT(x);
- x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
- if (s) {
- x = -x;
- }
- return x;
- }
-}
-
-DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
- /* XXX: fastint */
- duk_double_t d = duk_js_tonumber(thr, tv); /* invalidates tv */
- return duk_js_tointeger_number(d);
-}
-
-/*
- * ToInt32(), ToUint32(), ToUint16() (E5 Sections 9.5, 9.6, 9.7)
- */
-
-/* combined algorithm matching E5 Sections 9.5 and 9.6 */
-DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) {
- duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
- duk_small_int_t s;
-
- if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
- return 0.0;
- }
-
-
- /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
- s = (duk_small_int_t) DUK_SIGNBIT(x);
- x = DUK_FLOOR(DUK_FABS(x));
- if (s) {
- x = -x;
- }
-
- /* NOTE: fmod(x) result sign is same as sign of x, which
- * differs from what Javascript wants (see Section 9.6).
- */
-
- x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */
-
- if (x < 0.0) {
- x += DUK_DOUBLE_2TO32;
- }
- /* -> x in [0, 2**32[ */
-
- if (is_toint32) {
- if (x >= DUK_DOUBLE_2TO31) {
- /* x in [2**31, 2**32[ */
-
- x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */
- }
- }
-
- return x;
-}
-
-DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) {
- duk_double_t d;
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv)) {
- return DUK_TVAL_GET_FASTINT_I32(tv);
- }
-#endif
-
- d = duk_js_tonumber(thr, tv); /* invalidates tv */
- d = duk__toint32_touint32_helper(d, 1);
- DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
- DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0); /* [-0x80000000,0x7fffffff] */
- DUK_ASSERT(d == ((duk_double_t) ((duk_int32_t) d))); /* whole, won't clip */
- return (duk_int32_t) d;
-}
-
-
-DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) {
- duk_double_t d;
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv)) {
- return DUK_TVAL_GET_FASTINT_U32(tv);
- }
-#endif
-
- d = duk_js_tonumber(thr, tv); /* invalidates tv */
- d = duk__toint32_touint32_helper(d, 0);
- DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
- DUK_ASSERT(d >= 0.0 && d <= 4294967295.0); /* [0x00000000, 0xffffffff] */
- DUK_ASSERT(d == ((duk_double_t) ((duk_uint32_t) d))); /* whole, won't clip */
- return (duk_uint32_t) d;
-
-}
-
-DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
- /* should be a safe way to compute this */
- return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU);
-}
-
-/*
- * ToString() (E5 Section 9.8)
- *
- * ==> implemented in the API.
- */
-
-/*
- * ToObject() (E5 Section 9.9)
- *
- * ==> implemented in the API.
- */
-
-/*
- * CheckObjectCoercible() (E5 Section 9.10)
- *
- * Note: no API equivalent now.
- */
-
-#if 0 /* unused */
-DUK_INTERNAL void duk_js_checkobjectcoercible(duk_hthread *thr, duk_tval *tv_x) {
- duk_small_uint_t tag = DUK_TVAL_GET_TAG(tv_x);
-
- /* Note: this must match ToObject() behavior */
-
- if (tag == DUK_TAG_UNDEFINED ||
- tag == DUK_TAG_NULL ||
- tag == DUK_TAG_POINTER ||
- tag == DUK_TAG_BUFFER) {
- DUK_ERROR_TYPE(thr, "not object coercible");
- }
-}
-#endif
-
-/*
- * IsCallable() (E5 Section 9.11)
- *
- * XXX: API equivalent is a separate implementation now, and this has
- * currently no callers.
- */
-
-#if 0 /* unused */
-DUK_INTERNAL duk_bool_t duk_js_iscallable(duk_tval *tv_x) {
- duk_hobject *obj;
-
- if (!DUK_TVAL_IS_OBJECT(tv_x)) {
- return 0;
- }
- obj = DUK_TVAL_GET_OBJECT(tv_x);
- DUK_ASSERT(obj != NULL);
-
- return DUK_HOBJECT_IS_CALLABLE(obj);
-}
-#endif
-
-/*
- * Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
- * 9.12). These have much in common so they can share some helpers.
- *
- * Future work notes:
- *
- * - Current implementation (and spec definition) has recursion; this should
- * be fixed if possible.
- *
- * - String-to-number coercion should be possible without going through the
- * value stack (and be more compact) if a shared helper is invoked.
- */
-
-/* Note that this is the same operation for strict and loose equality:
- * - E5 Section 11.9.3, step 1.c (loose)
- * - E5 Section 11.9.6, step 4 (strict)
- */
-
-DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) {
-#if defined(DUK_USE_PARANOID_MATH)
- /* Straightforward algorithm, makes fewer compiler assumptions. */
- duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
- duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
- if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) {
- return 0;
- }
- if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
- return 1;
- }
- if (x == y) {
- return 1;
- }
- return 0;
-#else /* DUK_USE_PARANOID_MATH */
- /* Better equivalent algorithm. If the compiler is compliant, C and
- * Ecmascript semantics are identical for this particular comparison.
- * In particular, NaNs must never compare equal and zeroes must compare
- * equal regardless of sign. Could also use a macro, but this inlines
- * already nicely (no difference on gcc, for instance).
- */
- if (x == y) {
- /* IEEE requires that NaNs compare false */
- DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
- DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
- return 1;
- } else {
- /* IEEE requires that zeros compare the same regardless
- * of their signed, so if both x and y are zeroes, they
- * are caught above.
- */
- DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
- return 0;
- }
-#endif /* DUK_USE_PARANOID_MATH */
-}
-
-DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
-#if defined(DUK_USE_PARANOID_MATH)
- duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
- duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
-
- if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) {
- /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
- return 1;
- }
- if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
- /* Note: cannot assume that a non-zero return value of signbit() would
- * always be the same -- hence cannot (portably) use something like:
- *
- * signbit(x) == signbit(y)
- */
- duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
- duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
- return (sx == sy);
- }
-
- /* normal comparison; known:
- * - both x and y are not NaNs (but one of them can be)
- * - both x and y are not zero (but one of them can be)
- * - x and y may be denormal or infinite
- */
-
- return (x == y);
-#else /* DUK_USE_PARANOID_MATH */
- duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
- duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
-
- if (x == y) {
- /* IEEE requires that NaNs compare false */
- DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
- DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
-
- /* Using classification has smaller footprint than direct comparison. */
- if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) {
- /* Note: cannot assume that a non-zero return value of signbit() would
- * always be the same -- hence cannot (portably) use something like:
- *
- * signbit(x) == signbit(y)
- */
- duk_small_int_t sx = (DUK_SIGNBIT(x) ? 1 : 0);
- duk_small_int_t sy = (DUK_SIGNBIT(y) ? 1 : 0);
- return (sx == sy);
- }
- return 1;
- } else {
- /* IEEE requires that zeros compare the same regardless
- * of their signed, so if both x and y are zeroes, they
- * are caught above.
- */
- DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
-
- /* Difference to non-strict/strict comparison is that NaNs compare
- * equal and signed zero signs matter.
- */
- if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) {
- /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
- return 1;
- }
- return 0;
- }
-#endif /* DUK_USE_PARANOID_MATH */
-}
-
-DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
- duk_context *ctx = (duk_context *) thr;
- duk_tval *tv_tmp;
-
- /* If flags != 0 (strict or SameValue), thr can be NULL. For loose
- * equals comparison it must be != NULL.
- */
- DUK_ASSERT(flags != 0 || thr != NULL);
-
- /*
- * Same type?
- *
- * Note: since number values have no explicit tag in the 8-byte
- * representation, need the awkward if + switch.
- */
-
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
- if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) {
- return 1;
- } else {
- return 0;
- }
- }
- else
-#endif
- if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
- /* Catches both doubles and cases where only one argument is a fastint */
- if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
- /* SameValue */
- return duk__js_samevalue_number(DUK_TVAL_GET_NUMBER(tv_x),
- DUK_TVAL_GET_NUMBER(tv_y));
- } else {
- /* equals and strict equals */
- return duk__js_equals_number(DUK_TVAL_GET_NUMBER(tv_x),
- DUK_TVAL_GET_NUMBER(tv_y));
- }
- } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
- switch (DUK_TVAL_GET_TAG(tv_x)) {
- case DUK_TAG_UNDEFINED:
- case DUK_TAG_NULL: {
- return 1;
- }
- case DUK_TAG_BOOLEAN: {
- return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
- }
- case DUK_TAG_POINTER: {
- return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
- }
- case DUK_TAG_STRING:
- case DUK_TAG_OBJECT: {
- /* heap pointer comparison suffices */
- return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
- }
- case DUK_TAG_BUFFER: {
- if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
- /* heap pointer comparison suffices */
- return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
- } else {
- /* non-strict equality for buffers compares contents */
- duk_hbuffer *h_x = DUK_TVAL_GET_BUFFER(tv_x);
- duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
- duk_size_t len_x = DUK_HBUFFER_GET_SIZE(h_x);
- duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
- void *buf_x;
- void *buf_y;
- if (len_x != len_y) {
- return 0;
- }
- buf_x = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_x);
- buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
- /* if len_x == len_y == 0, buf_x and/or buf_y may
- * be NULL, but that's OK.
- */
- DUK_ASSERT(len_x == len_y);
- DUK_ASSERT(len_x == 0 || buf_x != NULL);
- DUK_ASSERT(len_y == 0 || buf_y != NULL);
- return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
- }
- }
- case DUK_TAG_LIGHTFUNC: {
- /* At least 'magic' has a significant impact on function
- * identity.
- */
- duk_small_uint_t lf_flags_x;
- duk_small_uint_t lf_flags_y;
- duk_c_function func_x;
- duk_c_function func_y;
-
- DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x);
- DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y);
- return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default: {
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y));
- DUK_UNREACHABLE();
- return 0;
- }
- }
- }
-
- if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
- return 0;
- }
-
- DUK_ASSERT(flags == 0); /* non-strict equality from here on */
-
- /*
- * Types are different; various cases for non-strict comparison
- *
- * Since comparison is symmetric, we use a "swap trick" to reduce
- * code size.
- */
-
- /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
- if ((DUK_TVAL_IS_UNDEFINED(tv_x) && DUK_TVAL_IS_NULL(tv_y)) ||
- (DUK_TVAL_IS_NULL(tv_x) && DUK_TVAL_IS_UNDEFINED(tv_y))) {
- return 1;
- }
-
- /* Number/string-or-buffer -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
- if (DUK_TVAL_IS_NUMBER(tv_x) && (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
- /* the next 'if' is guaranteed to match after swap */
- tv_tmp = tv_x;
- tv_x = tv_y;
- tv_y = tv_tmp;
- }
- if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) && DUK_TVAL_IS_NUMBER(tv_y)) {
- /* XXX: this is possible without resorting to the value stack */
- duk_double_t d1, d2;
- d2 = DUK_TVAL_GET_NUMBER(tv_y);
- duk_push_tval(ctx, tv_x);
- duk_to_string(ctx, -1); /* buffer values are coerced first to string here */
- duk_to_number(ctx, -1);
- d1 = duk_require_number(ctx, -1);
- duk_pop(ctx);
- return duk__js_equals_number(d1, d2);
- }
-
- /* Buffer/string -> compare contents. */
- if (DUK_TVAL_IS_BUFFER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
- tv_tmp = tv_x;
- tv_x = tv_y;
- tv_y = tv_tmp;
- }
- if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_BUFFER(tv_y)) {
- duk_hstring *h_x = DUK_TVAL_GET_STRING(tv_x);
- duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
- duk_size_t len_x = DUK_HSTRING_GET_BYTELEN(h_x);
- duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
- const void *buf_x;
- const void *buf_y;
- if (len_x != len_y) {
- return 0;
- }
- buf_x = (const void *) DUK_HSTRING_GET_DATA(h_x);
- buf_y = (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
- /* if len_x == len_y == 0, buf_x and/or buf_y may
- * be NULL, but that's OK.
- */
- DUK_ASSERT(len_x == len_y);
- DUK_ASSERT(len_x == 0 || buf_x != NULL);
- DUK_ASSERT(len_y == 0 || buf_y != NULL);
- return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
- }
-
- /* Boolean/any -> coerce boolean to number and try again. If boolean is
- * compared to a pointer, the final comparison after coercion now always
- * yields false (as pointer vs. number compares to false), but this is
- * not special cased.
- */
- if (DUK_TVAL_IS_BOOLEAN(tv_x)) {
- tv_tmp = tv_x;
- tv_x = tv_y;
- tv_y = tv_tmp;
- }
- if (DUK_TVAL_IS_BOOLEAN(tv_y)) {
- /* ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. */
- duk_bool_t rc;
- DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
- duk_push_tval(ctx, tv_x);
- duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
- rc = duk_js_equals_helper(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1),
- 0 /*flags:nonstrict*/);
- duk_pop_2(ctx);
- return rc;
- }
-
- /* String-number-buffer/object -> coerce object to primitive (apparently without hint), then try again. */
- if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) &&
- DUK_TVAL_IS_OBJECT(tv_y)) {
- tv_tmp = tv_x;
- tv_x = tv_y;
- tv_y = tv_tmp;
- }
- if (DUK_TVAL_IS_OBJECT(tv_x) &&
- (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_NUMBER(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
- duk_bool_t rc;
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* apparently no hint? */
- rc = duk_js_equals_helper(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -2),
- DUK_GET_TVAL_NEGIDX(ctx, -1),
- 0 /*flags:nonstrict*/);
- duk_pop_2(ctx);
- return rc;
- }
-
- /* Nothing worked -> not equal. */
- return 0;
-}
-
-/*
- * Comparisons (x >= y, x > y, x <= y, x < y)
- *
- * E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first
- * flags to get the rest.
- */
-
-/* XXX: this should probably just operate on the stack top, because it
- * needs to push stuff on the stack anyway...
- */
-
-DUK_INTERNAL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2) {
- duk_size_t prefix_len;
- duk_small_int_t rc;
-
- prefix_len = (len1 <= len2 ? len1 : len2);
-
- /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length
- * inputs so no zero length check is needed.
- */
- rc = DUK_MEMCMP((const void *) buf1,
- (const void *) buf2,
- (size_t) prefix_len);
-
- if (rc < 0) {
- return -1;
- } else if (rc > 0) {
- return 1;
- }
-
- /* prefix matches, lengths matter now */
- if (len1 < len2) {
- /* e.g. "x" < "xx" */
- return -1;
- } else if (len1 > len2) {
- return 1;
- }
-
- return 0;
-}
-
-DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) {
- /*
- * String comparison (E5 Section 11.8.5, step 4), which
- * needs to compare codepoint by codepoint.
- *
- * However, UTF-8 allows us to use strcmp directly: the shared
- * prefix will be encoded identically (UTF-8 has unique encoding)
- * and the first differing character can be compared with a simple
- * unsigned byte comparison (which strcmp does).
- *
- * This will not work properly for non-xutf-8 strings, but this
- * is not an issue for compliance.
- */
-
- DUK_ASSERT(h1 != NULL);
- DUK_ASSERT(h2 != NULL);
-
- return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1),
- (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2),
- (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1),
- (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2));
-}
-
-#if 0 /* unused */
-DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) {
- /* Similar to String comparison. */
-
- DUK_ASSERT(h1 != NULL);
- DUK_ASSERT(h2 != NULL);
- DUK_UNREF(heap);
-
- return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1),
- (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2),
- (duk_size_t) DUK_HBUFFER_GET_SIZE(h1),
- (duk_size_t) DUK_HBUFFER_GET_SIZE(h2));
-}
-#endif
-
-DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
- duk_context *ctx = (duk_context *) thr;
- duk_double_t d1, d2;
- duk_small_int_t c1, c2;
- duk_small_int_t s1, s2;
- duk_small_int_t rc;
- duk_bool_t retval;
-
- /* Fast path for fastints */
-#if defined(DUK_USE_FASTINT)
- if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
- duk_int64_t v1 = DUK_TVAL_GET_FASTINT(tv_x);
- duk_int64_t v2 = DUK_TVAL_GET_FASTINT(tv_y);
- if (v1 < v2) {
- /* 'lt is true' */
- retval = 1;
- } else {
- retval = 0;
- }
- if (flags & DUK_COMPARE_FLAG_NEGATE) {
- retval ^= 1;
- }
- return retval;
- }
-#endif /* DUK_USE_FASTINT */
-
- /* Fast path for numbers (one of which may be a fastint) */
-#if 1 /* XXX: make fast paths optional for size minimization? */
- if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
- d1 = DUK_TVAL_GET_NUMBER(tv_x);
- d2 = DUK_TVAL_GET_NUMBER(tv_y);
- c1 = DUK_FPCLASSIFY(d1);
- c2 = DUK_FPCLASSIFY(d2);
-
- if (c1 == DUK_FP_NORMAL && c2 == DUK_FP_NORMAL) {
- /* XXX: this is a very narrow check, and doesn't cover
- * zeroes, subnormals, infinities, which compare normally.
- */
-
- if (d1 < d2) {
- /* 'lt is true' */
- retval = 1;
- } else {
- retval = 0;
- }
- if (flags & DUK_COMPARE_FLAG_NEGATE) {
- retval ^= 1;
- }
- return retval;
- }
- }
-#endif
-
- /* Slow path */
-
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
-
- if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
- duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
- } else {
- duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
- duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
- }
-
- /* Note: reuse variables */
- tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
- tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
-
- if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
- duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
- duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
- DUK_ASSERT(h1 != NULL);
- DUK_ASSERT(h2 != NULL);
-
- rc = duk_js_string_compare(h1, h2);
- if (rc < 0) {
- goto lt_true;
- } else {
- goto lt_false;
- }
- } else {
- /* Ordering should not matter (E5 Section 11.8.5, step 3.a) but
- * preserve it just in case.
- */
-
- if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
- d1 = duk_to_number(ctx, -2);
- d2 = duk_to_number(ctx, -1);
- } else {
- d2 = duk_to_number(ctx, -1);
- d1 = duk_to_number(ctx, -2);
- }
-
- c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
- s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
- c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
- s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
-
- if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
- goto lt_undefined;
- }
-
- if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
- /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
- * steps e, f, and g.
- */
- goto lt_false;
- }
-
- if (d1 == d2) {
- goto lt_false;
- }
-
- if (c1 == DUK_FP_INFINITE && s1 == 0) {
- /* x == +Infinity */
- goto lt_false;
- }
-
- if (c2 == DUK_FP_INFINITE && s2 == 0) {
- /* y == +Infinity */
- goto lt_true;
- }
-
- if (c2 == DUK_FP_INFINITE && s2 != 0) {
- /* y == -Infinity */
- goto lt_false;
- }
-
- if (c1 == DUK_FP_INFINITE && s1 != 0) {
- /* x == -Infinity */
- goto lt_true;
- }
-
- if (d1 < d2) {
- goto lt_true;
- }
-
- goto lt_false;
- }
-
- lt_undefined:
- /* Note: undefined from Section 11.8.5 always results in false
- * return (see e.g. Section 11.8.3) - hence special treatment here.
- */
- retval = 0;
- goto cleanup;
-
- lt_true:
- if (flags & DUK_COMPARE_FLAG_NEGATE) {
- retval = 0;
- goto cleanup;
- } else {
- retval = 1;
- goto cleanup;
- }
- /* never here */
-
- lt_false:
- if (flags & DUK_COMPARE_FLAG_NEGATE) {
- retval = 1;
- goto cleanup;
- } else {
- retval = 0;
- goto cleanup;
- }
- /* never here */
-
- cleanup:
- duk_pop_2(ctx);
- return retval;
-}
-
-/*
- * instanceof
- */
-
-/*
- * E5 Section 11.8.6 describes the main algorithm, which uses
- * [[HasInstance]]. [[HasInstance]] is defined for only
- * function objects:
- *
- * - Normal functions:
- * E5 Section 15.3.5.3
- * - Functions established with Function.prototype.bind():
- * E5 Section 15.3.4.5.3
- *
- * For other objects, a TypeError is thrown.
- *
- * Limited Proxy support: don't support 'getPrototypeOf' trap but
- * continue lookup in Proxy target if the value is a Proxy.
- */
-
-DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *func;
- duk_hobject *val;
- duk_hobject *proto;
- duk_uint_t sanity;
-
- /*
- * Get the values onto the stack first. It would be possible to cover
- * some normal cases without resorting to the value stack.
- *
- * The right hand side could be a light function (as they generally
- * behave like objects). Light functions never have a 'prototype'
- * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
- * Using duk_require_hobject() is thus correct (except for error msg).
- */
-
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- func = duk_require_hobject(ctx, -1);
-
- /*
- * For bound objects, [[HasInstance]] just calls the target function
- * [[HasInstance]]. If that is again a bound object, repeat until
- * we find a non-bound Function object.
- */
-
- /* XXX: this bound function resolution also happens elsewhere,
- * move into a shared helper.
- */
-
- sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
- do {
- /* check func supports [[HasInstance]] (this is checked for every function
- * in the bound chain, including the final one)
- */
-
- if (!DUK_HOBJECT_IS_CALLABLE(func)) {
- /*
- * Note: of native Ecmascript objects, only Function instances
- * have a [[HasInstance]] internal property. Custom objects might
- * also have it, but not in current implementation.
- *
- * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
- */
- DUK_ERROR_TYPE(thr, "invalid instanceof rval");
- }
-
- if (!DUK_HOBJECT_HAS_BOUND(func)) {
- break;
- }
-
- /* [ ... lval rval ] */
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [ ... lval rval new_rval ] */
- duk_replace(ctx, -1); /* -> [ ... lval new_rval ] */
- func = duk_require_hobject(ctx, -1);
-
- /* func support for [[HasInstance]] checked in the beginning of the loop */
- } while (--sanity > 0);
-
- if (sanity == 0) {
- DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
- }
-
- /*
- * 'func' is now a non-bound object which supports [[HasInstance]]
- * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on
- * to execute E5 Section 15.3.5.3.
- */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func));
- DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
-
- /* [ ... lval rval(func) ] */
-
- /* Handle lightfuncs through object coercion for now. */
- /* XXX: direct implementation */
- val = duk_get_hobject_or_lfunc_coerce(ctx, -2);
- if (!val) {
- goto pop_and_false;
- }
-
- duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
- proto = duk_require_hobject(ctx, -1);
- duk_pop(ctx); /* -> [ ... lval rval ] */
-
- DUK_ASSERT(val != NULL);
-
-#if defined(DUK_USE_ES6_PROXY)
- val = duk_hobject_resolve_proxy_target(thr, val);
- DUK_ASSERT(val != NULL);
-#endif
-
- sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
- do {
- /*
- * Note: prototype chain is followed BEFORE first comparison. This
- * means that the instanceof lval is never itself compared to the
- * rval.prototype property. This is apparently intentional, see E5
- * Section 15.3.5.3, step 4.a.
- *
- * Also note:
- *
- * js> (function() {}) instanceof Function
- * true
- * js> Function instanceof Function
- * true
- *
- * For the latter, h_proto will be Function.prototype, which is the
- * built-in Function prototype. Because Function.[[Prototype]] is
- * also the built-in Function prototype, the result is true.
- */
-
- DUK_ASSERT(val != NULL);
- val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
-
- if (!val) {
- goto pop_and_false;
- }
-
- DUK_ASSERT(val != NULL);
-#if defined(DUK_USE_ES6_PROXY)
- val = duk_hobject_resolve_proxy_target(thr, val);
-#endif
-
- if (val == proto) {
- goto pop_and_true;
- }
-
- /* follow prototype chain */
- } while (--sanity > 0);
-
- if (sanity == 0) {
- DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
- }
- DUK_UNREACHABLE();
-
- pop_and_false:
- duk_pop_2(ctx);
- return 0;
-
- pop_and_true:
- duk_pop_2(ctx);
- return 1;
-}
-
-/*
- * in
- */
-
-/*
- * E5 Sections 11.8.7, 8.12.6.
- *
- * Basically just a property existence check using [[HasProperty]].
- */
-
-DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
- duk_context *ctx = (duk_context *) thr;
- duk_bool_t retval;
-
- /*
- * Get the values onto the stack first. It would be possible to cover
- * some normal cases without resorting to the value stack (e.g. if
- * lval is already a string).
- */
-
- /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
- * must be string coerced before the internal HasProperty() algorithm is
- * invoked. A fast path skipping coercion could be safely implemented for
- * numbers (as number-to-string coercion has no side effects). For ES6
- * proxy behavior, the trap 'key' argument must be in a string coerced
- * form (which is a shame).
- */
-
- /* TypeError if rval is not an object (or lightfunc which should behave
- * like a Function instance).
- */
- duk_push_tval(ctx, tv_x);
- duk_push_tval(ctx, tv_y);
- duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC);
- duk_to_string(ctx, -2); /* coerce lval with ToString() */
-
- retval = duk_hobject_hasprop(thr,
- DUK_GET_TVAL_NEGIDX(ctx, -1),
- DUK_GET_TVAL_NEGIDX(ctx, -2));
-
- duk_pop_2(ctx);
- return retval;
-}
-
-/*
- * typeof
- *
- * E5 Section 11.4.3.
- *
- * Very straightforward. The only question is what to return for our
- * non-standard tag / object types.
- *
- * There is an unfortunate string constant define naming problem with
- * typeof return values for e.g. "Object" and "object"; careful with
- * the built-in string defines. The LC_XXX defines are used for the
- * lowercase variants now.
- */
-
-DUK_INTERNAL duk_hstring *duk_js_typeof(duk_hthread *thr, duk_tval *tv_x) {
- duk_small_int_t stridx = 0;
-
- DUK_UNREF(thr);
-
- switch (DUK_TVAL_GET_TAG(tv_x)) {
- case DUK_TAG_UNDEFINED: {
- stridx = DUK_STRIDX_LC_UNDEFINED;
- break;
- }
- case DUK_TAG_NULL: {
- /* Note: not a typo, "object" is returned for a null value */
- stridx = DUK_STRIDX_LC_OBJECT;
- break;
- }
- case DUK_TAG_BOOLEAN: {
- stridx = DUK_STRIDX_LC_BOOLEAN;
- break;
- }
- case DUK_TAG_POINTER: {
- /* implementation specific */
- stridx = DUK_STRIDX_LC_POINTER;
- break;
- }
- case DUK_TAG_STRING: {
- stridx = DUK_STRIDX_LC_STRING;
- break;
- }
- case DUK_TAG_OBJECT: {
- duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
- DUK_ASSERT(obj != NULL);
- if (DUK_HOBJECT_IS_CALLABLE(obj)) {
- stridx = DUK_STRIDX_LC_FUNCTION;
- } else {
- stridx = DUK_STRIDX_LC_OBJECT;
- }
- break;
- }
- case DUK_TAG_BUFFER: {
- /* implementation specific */
- stridx = DUK_STRIDX_LC_BUFFER;
- break;
- }
- case DUK_TAG_LIGHTFUNC: {
- stridx = DUK_STRIDX_LC_FUNCTION;
- break;
- }
-#if defined(DUK_USE_FASTINT)
- case DUK_TAG_FASTINT:
-#endif
- default: {
- /* number */
- DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
- stridx = DUK_STRIDX_LC_NUMBER;
- break;
- }
- }
-
- DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
- return DUK_HTHREAD_GET_STRING(thr, stridx);
-}
-
-/*
- * Array index and length
- *
- * Array index: E5 Section 15.4
- * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
- *
- * The DUK_HSTRING_GET_ARRIDX_SLOW() and DUK_HSTRING_GET_ARRIDX_FAST() macros
- * call duk_js_to_arrayindex_string_helper().
- */
-
-DUK_INTERNAL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx) {
- duk_uarridx_t res, new_res;
-
- if (blen == 0 || blen > 10) {
- goto parse_fail;
- }
- if (str[0] == (duk_uint8_t) '0' && blen > 1) {
- goto parse_fail;
- }
-
- /* Accept 32-bit decimal integers, no leading zeroes, signs, etc.
- * Leading zeroes are not accepted (zero index "0" is an exception
- * handled above).
- */
-
- res = 0;
- while (blen-- > 0) {
- duk_uint8_t c = *str++;
- if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') {
- new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0');
- if (new_res < res) {
- /* overflow, more than 32 bits -> not an array index */
- goto parse_fail;
- }
- res = new_res;
- } else {
- goto parse_fail;
- }
- }
-
- *out_idx = res;
- return 1;
-
- parse_fail:
- *out_idx = DUK_HSTRING_NO_ARRAY_INDEX;
- return 0;
-}
-
-/* Called by duk_hstring.h macros */
-DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) {
- duk_uarridx_t res;
- duk_small_int_t rc;
-
- if (!DUK_HSTRING_HAS_ARRIDX(h)) {
- return DUK_HSTRING_NO_ARRAY_INDEX;
- }
-
- rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h),
- DUK_HSTRING_GET_BYTELEN(h),
- &res);
- DUK_UNREF(rc);
- DUK_ASSERT(rc != 0);
- return res;
-}
-#line 1 "duk_js_var.c"
-/*
- * Identifier access and function closure handling.
- *
- * Provides the primitives for slow path identifier accesses: GETVAR,
- * PUTVAR, DELVAR, etc. The fast path, direct register accesses, should
- * be used for most identifier accesses. Consequently, these slow path
- * primitives should be optimized for maximum compactness.
- *
- * Ecmascript environment records (declarative and object) are represented
- * as internal objects with control keys. Environment records have a
- * parent record ("outer environment reference") which is represented by
- * the implicit prototype for technical reasons (in other words, it is a
- * convenient field). The prototype chain is not followed in the ordinary
- * sense for variable lookups.
- *
- * See identifier-handling.rst for more details on the identifier algorithms
- * and the internal representation. See function-objects.rst for details on
- * what function templates and instances are expected to look like.
- *
- * Care must be taken to avoid duk_tval pointer invalidation caused by
- * e.g. value stack or object resizing.
- *
- * TODO: properties for function instances could be initialized much more
- * efficiently by creating a property allocation for a certain size and
- * filling in keys and values directly (and INCREFing both with "bulk incref"
- * primitives.
- *
- * XXX: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit
- * awkward (especially because they follow the prototype chain); rework
- * if "raw" own property helpers are added.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Local result type for duk__get_identifier_reference() lookup.
- */
-
-typedef struct {
- duk_hobject *holder; /* for object-bound identifiers */
- duk_tval *value; /* for register-bound and declarative env identifiers */
- duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */
- duk_tval *this_binding;
- duk_hobject *env;
-} duk__id_lookup_result;
-
-/*
- * Create a new function object based on a "template function" which contains
- * compiled bytecode, constants, etc, but lacks a lexical environment.
- *
- * Ecmascript requires that each created closure is a separate object, with
- * its own set of editable properties. However, structured property values
- * (such as the formal arguments list and the variable map) are shared.
- * Also the bytecode, constants, and inner functions are shared.
- *
- * See E5 Section 13.2 for detailed requirements on the function objects;
- * there are no similar requirements for function "templates" which are an
- * implementation dependent internal feature. Also see function-objects.rst
- * for a discussion on the function instance properties provided by this
- * implementation.
- *
- * Notes:
- *
- * * Order of internal properties should match frequency of use, since the
- * properties will be linearly scanned on lookup (functions usually don't
- * have enough properties to warrant a hash part).
- *
- * * The created closure is independent of its template; they do share the
- * same 'data' buffer object, but the template object itself can be freed
- * even if the closure object remains reachable.
- */
-
-DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompiledfunction *f) {
- duk_tval *tv, *tv_end;
- duk_hobject **funcs, **funcs_end;
-
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, f) != NULL); /* compiled functions must be created 'atomically' */
- DUK_UNREF(thr);
-
- tv = DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(thr->heap, f);
- tv_end = DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(thr->heap, f);
- while (tv < tv_end) {
- DUK_TVAL_INCREF(thr, tv);
- tv++;
- }
-
- funcs = DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(thr->heap, f);
- funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
- while (funcs < funcs_end) {
- DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs);
- funcs++;
- }
-}
-
-/* Push a new closure on the stack.
- *
- * Note: if fun_temp has NEWENV, i.e. a new lexical and variable declaration
- * is created when the function is called, only outer_lex_env matters
- * (outer_var_env is ignored and may or may not be same as outer_lex_env).
- */
-
-DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = {
- /* order: most frequent to least frequent */
- DUK_STRIDX_INT_VARMAP,
- DUK_STRIDX_INT_FORMALS,
- DUK_STRIDX_NAME,
- DUK_STRIDX_INT_PC2LINE,
- DUK_STRIDX_FILE_NAME,
- DUK_STRIDX_INT_SOURCE
-};
-
-DUK_INTERNAL
-void duk_js_push_closure(duk_hthread *thr,
- duk_hcompiledfunction *fun_temp,
- duk_hobject *outer_var_env,
- duk_hobject *outer_lex_env,
- duk_bool_t add_auto_proto) {
- duk_context *ctx = (duk_context *) thr;
- duk_hcompiledfunction *fun_clos;
- duk_small_uint_t i;
- duk_uint_t len_value;
-
- DUK_ASSERT(fun_temp != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_temp) != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_temp) != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_temp) != NULL);
- DUK_ASSERT(outer_var_env != NULL);
- DUK_ASSERT(outer_lex_env != NULL);
- DUK_UNREF(len_value);
-
- duk_push_compiledfunction(ctx);
- duk_push_hobject(ctx, &fun_temp->obj); /* -> [ ... closure template ] */
-
- fun_clos = (duk_hcompiledfunction *) duk_get_hcompiledfunction(ctx, -2);
- DUK_ASSERT(fun_clos != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION((duk_hobject *) fun_clos));
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_clos) == NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_clos) == NULL);
-
- DUK_HCOMPILEDFUNCTION_SET_DATA(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_temp));
- DUK_HCOMPILEDFUNCTION_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_temp));
- DUK_HCOMPILEDFUNCTION_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_temp));
-
- /* Note: all references inside 'data' need to get their refcounts
- * upped too. This is the case because refcounts are decreased
- * through every function referencing 'data' independently.
- */
-
- DUK_HBUFFER_INCREF(thr, DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos));
- duk__inc_data_inner_refcounts(thr, fun_temp);
-
- fun_clos->nregs = fun_temp->nregs;
- fun_clos->nargs = fun_temp->nargs;
-#if defined(DUK_USE_DEBUGGER_SUPPORT)
- fun_clos->start_line = fun_temp->start_line;
- fun_clos->end_line = fun_temp->end_line;
-#endif
-
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_DATA(thr->heap, fun_clos) != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_FUNCS(thr->heap, fun_clos) != NULL);
- DUK_ASSERT(DUK_HCOMPILEDFUNCTION_GET_BYTECODE(thr->heap, fun_clos) != NULL);
-
- /* XXX: could also copy from template, but there's no way to have any
- * other value here now (used code has no access to the template).
- */
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
-
- /*
- * Init/assert flags, copying them where appropriate. Some flags
- * (like NEWENV) are processed separately below.
- */
-
- /* XXX: copy flags using a mask */
-
- DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
- DUK_HOBJECT_SET_CONSTRUCTABLE(&fun_clos->obj); /* Note: not set in template (has no "prototype") */
- DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&fun_clos->obj));
- DUK_ASSERT(DUK_HOBJECT_HAS_COMPILEDFUNCTION(&fun_clos->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_NATIVEFUNCTION(&fun_clos->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj));
- /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
- if (DUK_HOBJECT_HAS_STRICT(&fun_temp->obj)) {
- DUK_HOBJECT_SET_STRICT(&fun_clos->obj);
- }
- if (DUK_HOBJECT_HAS_NOTAIL(&fun_temp->obj)) {
- DUK_HOBJECT_SET_NOTAIL(&fun_clos->obj);
- }
- /* DUK_HOBJECT_FLAG_NEWENV: handled below */
- if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
- /* Although NAMEBINDING is not directly needed for using
- * function instances, it's needed by bytecode dump/load
- * so copy it too.
- */
- DUK_HOBJECT_SET_NAMEBINDING(&fun_clos->obj);
- }
- if (DUK_HOBJECT_HAS_CREATEARGS(&fun_temp->obj)) {
- DUK_HOBJECT_SET_CREATEARGS(&fun_clos->obj);
- }
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj));
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj));
-
- /*
- * Setup environment record properties based on the template and
- * its flags.
- *
- * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
- * records represent identifiers "outside" the function; the
- * "inner" environment records are created on demand. Otherwise,
- * the environment records are those that will be directly used
- * (e.g. for declarations).
- *
- * _Lexenv is always set; _Varenv defaults to _Lexenv if missing,
- * so _Varenv is only set if _Lexenv != _Varenv.
- *
- * This is relatively complex, see doc/identifier-handling.rst.
- */
-
- if (DUK_HOBJECT_HAS_NEWENV(&fun_temp->obj)) {
- DUK_HOBJECT_SET_NEWENV(&fun_clos->obj);
-
- if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
- duk_hobject *proto;
-
- /*
- * Named function expression, name needs to be bound
- * in an intermediate environment record. The "outer"
- * lexical/variable environment will thus be:
- *
- * a) { funcname: <func>, __prototype: outer_lex_env }
- * b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing)
- */
-
- DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_NAME)); /* required if NAMEBINDING set */
-
- if (outer_lex_env) {
- proto = outer_lex_env;
- } else {
- proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- }
-
- /* -> [ ... closure template env ] */
- (void) duk_push_object_helper_proto(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- proto);
-
- /* It's important that duk_xdef_prop() is a 'raw define' so that any
- * properties in an ancestor are never an issue (they should never be
- * e.g. non-writable, but just in case).
- */
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); /* -> [ ... closure template env funcname ] */
- duk_dup(ctx, -4); /* -> [ ... closure template env funcname closure ] */
- duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
- /* env[funcname] = closure */
-
- /* [ ... closure template env ] */
-
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
- /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
- * will be ignored anyway
- */
-
- /* [ ... closure template ] */
- } else {
- /*
- * Other cases (function declaration, anonymous function expression,
- * strict direct eval code). The "outer" environment will be whatever
- * the caller gave us.
- */
-
- duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
- /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
- * will be ignored anyway
- */
-
- /* [ ... closure template ] */
- }
- } else {
- /*
- * Function gets no new environment when called. This is the
- * case for global code, indirect eval code, and non-strict
- * direct eval code. There is no direct correspondence to the
- * E5 specification, as global/eval code is not exposed as a
- * function.
- */
-
- DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj));
-
- duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV, DUK_PROPDESC_FLAGS_WC);
-
- if (outer_var_env != outer_lex_env) {
- duk_push_hobject(ctx, outer_var_env); /* -> [ ... closure template env ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_WC);
- }
- }
-#ifdef DUK_USE_DDDPRINT
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_VARENV);
- duk_get_prop_stridx(ctx, -3, DUK_STRIDX_INT_LEXENV);
- DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipT, lexenv -> %!ipT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
- duk_pop_2(ctx);
-#endif
-
- /*
- * Copy some internal properties directly
- *
- * The properties will be writable and configurable, but not enumerable.
- */
-
- /* [ ... closure template ] */
-
- DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
- duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i];
- if (duk_get_prop_stridx(ctx, -1, stridx)) {
- /* [ ... closure template val ] */
- DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
- duk_xdef_prop_stridx(ctx, -3, stridx, DUK_PROPDESC_FLAGS_WC);
- } else {
- DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
- duk_pop(ctx);
- }
- }
-
- /*
- * "length" maps to number of formals (E5 Section 13.2) for function
- * declarations/expressions (non-bound functions). Note that 'nargs'
- * is NOT necessarily equal to the number of arguments.
- */
-
- /* [ ... closure template ] */
-
- len_value = 0;
-
- /* XXX: use helper for size optimization */
- if (duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_FORMALS)) {
- /* [ ... closure template formals ] */
- DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_LENGTH));
- DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_UINT_MAX); /* formal arg limits */
- len_value = (duk_uint_t) duk_get_length(ctx, -1);
- } else {
- /* XXX: what to do if _Formals is not empty but compiler has
- * optimized it away -- read length from an explicit property
- * then?
- */
- }
- duk_pop(ctx);
-
- duk_push_uint(ctx, len_value); /* [ ... closure template len_value ] */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
-
- /*
- * "prototype" is, by default, a fresh object with the "constructor"
- * property.
- *
- * Note that this creates a circular reference for every function
- * instance (closure) which prevents refcount-based collection of
- * function instances.
- *
- * XXX: Try to avoid creating the default prototype object, because
- * many functions are not used as constructors and the default
- * prototype is unnecessary. Perhaps it could be created on-demand
- * when it is first accessed?
- */
-
- /* [ ... closure template ] */
-
- if (add_auto_proto) {
- duk_push_object(ctx); /* -> [ ... closure template newobj ] */
- duk_dup(ctx, -3); /* -> [ ... closure template newobj closure ] */
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
- duk_compact(ctx, -1); /* compact the prototype */
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
- }
-
- /*
- * "arguments" and "caller" must be mapped to throwers for strict
- * mode and bound functions (E5 Section 15.3.5).
- *
- * XXX: This is expensive to have for every strict function instance.
- * Try to implement as virtual properties or on-demand created properties.
- */
-
- /* [ ... closure template ] */
-
- if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
- duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
- duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_LC_ARGUMENTS, DUK_PROPDESC_FLAGS_NONE);
- } else {
-#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
- DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
- duk_push_null(ctx);
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
-#else
- DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
-#endif
- }
-
- /*
- * "name" is a non-standard property found in at least V8, Rhino, smjs.
- * For Rhino and smjs it is non-writable, non-enumerable, and non-configurable;
- * for V8 it is writable, non-enumerable, non-configurable. It is also defined
- * for an anonymous function expression in which case the value is an empty string.
- * We could also leave name 'undefined' for anonymous functions but that would
- * differ from behavior of other engines, so use an empty string.
- *
- * XXX: make optional? costs something per function.
- */
-
- /* [ ... closure template ] */
-
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME)) {
- /* [ ... closure template name ] */
- DUK_ASSERT(duk_is_string(ctx, -1));
- } else {
- /* [ ... closure template undefined ] */
- duk_pop(ctx);
- duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING);
- }
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template ] */
-
- /*
- * Compact the closure, in most cases no properties will be added later.
- * Also, without this the closures end up having unused property slots
- * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
- * A better future solution would be to allocate the closure directly
- * to correct size (and setup the properties directly without going
- * through the API).
- */
-
- duk_compact(ctx, -2);
-
- /*
- * Some assertions (E5 Section 13.2).
- */
-
- DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
- DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
- DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
- DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH) != 0);
- DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
- DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_NAME) != 0); /* non-standard */
- DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
- duk_has_prop_stridx(ctx, -2, DUK_STRIDX_CALLER) != 0);
- DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
- duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
-
- /*
- * Finish
- */
-
- /* [ ... closure template ] */
-
- DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
- (duk_tval *) duk_get_tval(ctx, -1),
- (duk_tval *) duk_get_tval(ctx, -2)));
-
- duk_pop(ctx);
-
- /* [ ... closure ] */
-}
-
-/*
- * Delayed activation environment record initialization (for functions
- * with NEWENV).
- *
- * The non-delayed initialization is handled by duk_handle_call().
- */
-
-/* shared helper */
-DUK_INTERNAL
-duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
- duk_hobject *func,
- duk_size_t idx_bottom) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *env;
- duk_hobject *parent;
- duk_tval *tv;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(func != NULL);
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
- if (tv) {
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(DUK_TVAL_GET_OBJECT(tv)));
- parent = DUK_TVAL_GET_OBJECT(tv);
- } else {
- parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- }
-
- (void) duk_push_object_helper(ctx,
- DUK_HOBJECT_FLAG_EXTENSIBLE |
- DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
- -1); /* no prototype, updated below */
- env = duk_require_hobject(ctx, -1);
- DUK_ASSERT(env != NULL);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */
-
- /* open scope information, for compiled functions only */
-
- if (DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- duk_push_hthread(ctx, thr);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_THREAD);
- duk_push_hobject(ctx, func);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_CALLEE);
- duk_push_size_t(ctx, idx_bottom);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INT_REGBASE);
- }
-
- return env;
-}
-
-DUK_INTERNAL
-void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
- duk_activation *act) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *func;
- duk_hobject *env;
-
- func = DUK_ACT_GET_FUNC(act);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound functions are never in act 'func' */
-
- /*
- * Delayed initialization only occurs for 'NEWENV' functions.
- */
-
- DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
- DUK_ASSERT(act->lex_env == NULL);
- DUK_ASSERT(act->var_env == NULL);
-
- env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
- DUK_ASSERT(env != NULL);
-
- DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
-#ifdef DUK_USE_DDDPRINT
- {
- duk_hobject *p = env;
- while (p) {
- DUK_DDD(DUK_DDDPRINT(" -> %!ipO", (duk_heaphdr *) p));
- p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p);
- }
- }
-#endif
-
- act->lex_env = env;
- act->var_env = env;
- DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */
- DUK_HOBJECT_INCREF(thr, env);
-
- duk_pop(ctx);
-}
-
-/*
- * Closing environment records.
- *
- * The environment record MUST be closed with the thread where its activation
- * is. In other words (if 'env' is open):
- *
- * - 'thr' must match _env.thread
- * - 'func' must match _env.callee
- * - 'regbase' must match _env.regbase
- *
- * These are not looked up from the env to minimize code size.
- *
- * XXX: should access the own properties directly instead of using the API
- */
-
-DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) {
- duk_context *ctx = (duk_context *) thr;
- duk_uint_fast32_t i;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(env != NULL);
- /* func is NULL for lightfuncs */
-
- if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
- DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, "
- "or already closed: %!iO",
- (duk_heaphdr *) env));
- return;
- }
-
- DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld",
- (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase));
-
- duk_push_hobject(ctx, env);
-
- /* assertions: env must be closed in the same thread as where it runs */
-#ifdef DUK_USE_ASSERTIONS
- {
- /* [... env] */
-
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
- DUK_ASSERT(duk_is_object(ctx, -1));
- DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func);
- }
- duk_pop(ctx);
-
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD)) {
- DUK_ASSERT(duk_is_object(ctx, -1));
- DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr);
- }
- duk_pop(ctx);
-
- if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE)) {
- DUK_ASSERT(duk_is_number(ctx, -1));
- DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase);
- }
- duk_pop(ctx);
-
- /* [... env] */
- }
-#endif
-
- if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- duk_hobject *varmap;
- duk_hstring *key;
- duk_tval *tv;
- duk_uint_t regnum;
-
- /* XXX: additional conditions when to close variables? we don't want to do it
- * unless the environment may have "escaped" (referenced in a function closure).
- * With delayed environments, the existence is probably good enough of a check.
- */
-
- /* XXX: any way to detect faster whether something needs to be closed?
- * We now look up _Callee and then skip the rest.
- */
-
- /* Note: we rely on the _Varmap having a bunch of nice properties, like:
- * - being compacted and unmodified during this process
- * - not containing an array part
- * - having correct value types
- */
-
- /* [... env] */
-
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
- DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case"));
- duk_pop(ctx);
- goto skip_varmap;
- }
-
- /* [... env callee] */
-
- if (!duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VARMAP)) {
- DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties"));
- duk_pop_2(ctx);
- goto skip_varmap;
- }
- varmap = duk_require_hobject(ctx, -1);
- DUK_ASSERT(varmap != NULL);
-
- DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
-
- /* [... env callee varmap] */
-
- DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
-
- for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
- key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
- DUK_ASSERT(key != NULL); /* assume keys are compacted */
-
- DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
-
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */
- regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
- DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */
- DUK_ASSERT(regnum < ((duk_hcompiledfunction *) func)->nregs); /* regnum is sane */
- DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
- DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
-
- /* XXX: slightly awkward */
- duk_push_hstring(ctx, key);
- duk_push_tval(ctx, thr->valstack + regbase + regnum);
- DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T",
- (const char *) duk_require_string(ctx, -2),
- (long) regnum,
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /* [... env callee varmap key val] */
-
- /* if property already exists, overwrites silently */
- duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */
- }
-
- duk_pop_2(ctx);
-
- /* [... env] */
- }
-
- skip_varmap:
-
- /* [... env] */
-
- duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_CALLEE);
- duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_THREAD);
- duk_del_prop_stridx(ctx, -1, DUK_STRIDX_INT_REGBASE);
-
- duk_pop(ctx);
-
- DUK_HOBJECT_SET_ENVRECCLOSED(env);
-
- DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O",
- (duk_heaphdr *) env));
-}
-
-/*
- * GETIDREF: a GetIdentifierReference-like helper.
- *
- * Provides a parent traversing lookup and a single level lookup
- * (for HasBinding).
- *
- * Instead of returning the value, returns a bunch of values allowing
- * the caller to read, write, or delete the binding. Value pointers
- * are duk_tval pointers which can be mutated directly as long as
- * refcounts are properly updated. Note that any operation which may
- * reallocate valstacks or compact objects may invalidate the returned
- * duk_tval (but not object) pointers, so caller must be very careful.
- *
- * If starting environment record 'env' is given, 'act' is ignored.
- * However, if 'env' is NULL, the caller may identify, in 'act', an
- * activation which hasn't had its declarative environment initialized
- * yet. The activation registers are then looked up, and its parent
- * traversed normally.
- *
- * The 'out' structure values are only valid if the function returns
- * success (non-zero).
- */
-
-/* lookup name from an open declarative record's registers */
-DUK_LOCAL
-duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
- duk_hstring *name,
- duk_hobject *env,
- duk__id_lookup_result *out) {
- duk_hthread *env_thr;
- duk_hobject *env_func;
- duk_size_t env_regbase;
- duk_hobject *varmap;
- duk_tval *tv;
- duk_size_t reg_rel;
- duk_size_t idx;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(name != NULL);
- DUK_ASSERT(env != NULL);
- DUK_ASSERT(out != NULL);
-
- DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env));
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr));
- if (!tv) {
- /* env is closed, should be missing _Callee, _Thread, _Regbase */
- DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL);
- DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL);
- DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL);
- return 0;
- }
-
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_COMPILEDFUNCTION(DUK_TVAL_GET_OBJECT(tv)));
- env_func = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(env_func != NULL);
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
- if (!tv) {
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- varmap = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(varmap != NULL);
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
- if (!tv) {
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
- DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */
- DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) env_func)->nregs);
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr));
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
- env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(env_thr != NULL);
-
- /* Note: env_thr != thr is quite possible and normal, so careful
- * with what thread is used for valstack lookup.
- */
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr));
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
-
- idx = env_regbase + reg_rel;
- tv = env_thr->valstack + idx;
- DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */
-
- out->value = tv;
- out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
- out->this_binding = NULL; /* implicit this value always undefined for
- * declarative environment records.
- */
- out->env = env;
- out->holder = NULL;
-
- return 1;
-}
-
-/* lookup name from current activation record's functions' registers */
-DUK_LOCAL
-duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
- duk_hstring *name,
- duk_activation *act,
- duk__id_lookup_result *out) {
- duk_tval *tv;
- duk_hobject *func;
- duk_hobject *varmap;
- duk_size_t reg_rel;
- duk_size_t idx;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(name != NULL);
- DUK_ASSERT(act != NULL);
- DUK_ASSERT(out != NULL);
-
- func = DUK_ACT_GET_FUNC(act);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
-
- if (!DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
- return 0;
- }
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
- if (!tv) {
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- varmap = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(varmap != NULL);
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
- if (!tv) {
- return 0;
- }
- DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
- reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
- DUK_ASSERT_DISABLE(reg_rel >= 0);
- DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) func)->nregs);
-
- idx = act->idx_bottom + reg_rel;
- DUK_ASSERT(idx >= act->idx_bottom);
- tv = thr->valstack + idx;
-
- out->value = tv;
- out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
- out->this_binding = NULL; /* implicit this value always undefined for
- * declarative environment records.
- */
- out->env = NULL;
- out->holder = NULL;
-
- return 1;
-}
-
-DUK_LOCAL
-duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
- duk_hobject *env,
- duk_hstring *name,
- duk_activation *act,
- duk_bool_t parents,
- duk__id_lookup_result *out) {
- duk_tval *tv;
- duk_tval *tv_target;
- duk_tval tv_name;
- duk_uint_t sanity;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(env != NULL || act != NULL);
- DUK_ASSERT(name != NULL);
- DUK_ASSERT(out != NULL);
-
- DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env));
- DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env));
-
- /*
- * Conceptually, we look for the identifier binding by starting from
- * 'env' and following to chain of environment records (represented
- * by the prototype chain).
- *
- * If 'env' is NULL, the current activation does not yet have an
- * allocated declarative environment record; this should be treated
- * exactly as if the environment record existed but had no bindings
- * other than register bindings.
- *
- * Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared
- * the environment will always be initialized immediately; hence
- * a NULL 'env' should only happen with the flag set. This is the
- * case for: (1) function calls, and (2) strict, direct eval calls.
- */
-
- if (env == NULL && act != NULL) {
- duk_hobject *func;
-
- DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
- "delayed env case, look up activation regs first"));
-
- /*
- * Try registers
- */
-
- if (duk__getid_activation_regs(thr, name, act, out)) {
- DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
- "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
- "(found from register bindings when env=NULL)",
- (duk_heaphdr *) name, (duk_tval *) out->value,
- (long) out->attrs, (duk_tval *) out->this_binding,
- (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
- return 1;
- }
-
- DUK_DDD(DUK_DDDPRINT("not found in current activation regs"));
-
- /*
- * Not found in registers, proceed to the parent record.
- * Here we need to determine what the parent would be,
- * if 'env' was not NULL (i.e. same logic as when initializing
- * the record).
- *
- * Note that environment initialization is only deferred when
- * DUK_HOBJECT_HAS_NEWENV is set, and this only happens for:
- * - Function code
- * - Strict eval code
- *
- * We only need to check _Lexenv here; _Varenv exists only if it
- * differs from _Lexenv (and thus _Lexenv will also be present).
- */
-
- if (!parents) {
- DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
- "(not found from register bindings when env=NULL)"));
- goto fail_not_found;
- }
-
- func = DUK_ACT_GET_FUNC(act);
- DUK_ASSERT(func != NULL);
- DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_LEXENV(thr));
- if (tv) {
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- env = DUK_TVAL_GET_OBJECT(tv);
- } else {
- DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARENV(thr)) == NULL);
- env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
- }
-
- DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO",
- (duk_heaphdr *) env));
- }
-
- /*
- * Prototype walking starting from 'env'.
- *
- * ('act' is not needed anywhere here.)
- */
-
- sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
- while (env != NULL) {
- duk_small_int_t cl;
- duk_int_t attrs;
-
- DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
- (duk_heaphdr *) name,
- (void *) env,
- (duk_heaphdr *) env));
-
- DUK_ASSERT(env != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
- DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
-
- cl = DUK_HOBJECT_GET_CLASS_NUMBER(env);
- DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV);
- if (cl == DUK_HOBJECT_CLASS_DECENV) {
- /*
- * Declarative environment record.
- *
- * Identifiers can never be stored in ancestors and are
- * always plain values, so we can use an internal helper
- * and access the value directly with an duk_tval ptr.
- *
- * A closed environment is only indicated by it missing
- * the "book-keeping" properties required for accessing
- * register-bound variables.
- */
-
- if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
- /* already closed */
- goto skip_regs;
- }
-
- if (duk__getid_open_decl_env_regs(thr, name, env, out)) {
- DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
- "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
- "(declarative environment record, scope open, found in regs)",
- (duk_heaphdr *) name, (duk_tval *) out->value,
- (long) out->attrs, (duk_tval *) out->this_binding,
- (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
- return 1;
- }
- skip_regs:
-
- tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs);
- if (tv) {
- out->value = tv;
- out->attrs = attrs;
- out->this_binding = NULL; /* implicit this value always undefined for
- * declarative environment records.
- */
- out->env = env;
- out->holder = env;
-
- DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
- "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
- "(declarative environment record, found in properties)",
- (duk_heaphdr *) name, (duk_tval *) out->value,
- (long) out->attrs, (duk_tval *) out->this_binding,
- (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
- return 1;
- }
- } else {
- /*
- * Object environment record.
- *
- * Binding (target) object is an external, uncontrolled object.
- * Identifier may be bound in an ancestor property, and may be
- * an accessor. Target can also be a Proxy which we must support
- * here.
- */
-
- /* XXX: we could save space by using _Target OR _This. If _Target, assume
- * this binding is undefined. If _This, assumes this binding is _This, and
- * target is also _This. One property would then be enough.
- */
-
- duk_hobject *target;
- duk_bool_t found;
-
- DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV);
-
- tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
- DUK_ASSERT(tv_target != NULL);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
- target = DUK_TVAL_GET_OBJECT(tv_target);
- DUK_ASSERT(target != NULL);
-
- /* Target may be a Proxy or property may be an accessor, so we must
- * use an actual, Proxy-aware hasprop check here.
- *
- * out->holder is NOT set to the actual duk_hobject where the
- * property is found, but rather the object binding target object.
- */
-
- if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) {
- DUK_ASSERT(name != NULL);
- DUK_TVAL_SET_STRING(&tv_name, name);
-
- found = duk_hobject_hasprop(thr, tv_target, &tv_name);
- } else {
- /* XXX: duk_hobject_hasprop() would be correct for
- * non-Proxy objects too, but it is about ~20-25%
- * slower at present so separate code paths for
- * Proxy and non-Proxy now.
- */
- found = duk_hobject_hasprop_raw(thr, target, name);
- }
-
- if (found) {
- out->value = NULL; /* can't get value, may be accessor */
- out->attrs = 0; /* irrelevant when out->value == NULL */
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr));
- out->this_binding = tv; /* may be NULL */
- out->env = env;
- out->holder = target;
-
- DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
- "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
- "(object environment record)",
- (duk_heaphdr *) name, (duk_tval *) out->value,
- (long) out->attrs, (duk_tval *) out->this_binding,
- (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
- return 1;
- }
- }
-
- if (!parents) {
- DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
- "(not found from first traversed env)"));
- goto fail_not_found;
- }
-
- if (sanity-- == 0) {
- DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
- }
- env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);
- };
-
- /*
- * Not found (even in global object)
- */
-
- fail_not_found:
- return 0;
-}
-
-/*
- * HASVAR: check identifier binding from a given environment record
- * without traversing its parents.
- *
- * This primitive is not exposed to user code as such, but is used
- * internally for e.g. declaration binding instantiation.
- *
- * See E5 Sections:
- * 10.2.1.1.1 HasBinding(N)
- * 10.2.1.2.1 HasBinding(N)
- *
- * Note: strictness has no bearing on this check. Hence we don't take
- * a 'strict' parameter.
- */
-
-#if 0 /*unused*/
-DUK_INTERNAL
-duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr,
- duk_hobject *env,
- duk_hstring *name) {
- duk__id_lookup_result ref;
- duk_bool_t parents;
-
- DUK_DDD(DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O "
- "(env -> %!dO)",
- (void *) thr, (void *) env, (duk_heaphdr *) name,
- (duk_heaphdr *) env));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(env != NULL);
- DUK_ASSERT(name != NULL);
-
- DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
- DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
-
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
- DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
-
- /* lookup results is ignored */
- parents = 0;
- return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref);
-}
-#endif
-
-/*
- * GETVAR
- *
- * See E5 Sections:
- * 11.1.2 Identifier Reference
- * 10.3.1 Identifier Resolution
- * 11.13.1 Simple Assignment [example of where the Reference is GetValue'd]
- * 8.7.1 GetValue (V)
- * 8.12.1 [[GetOwnProperty]] (P)
- * 8.12.2 [[GetProperty]] (P)
- * 8.12.3 [[Get]] (P)
- *
- * If 'throw' is true, always leaves two values on top of stack: [val this].
- *
- * If 'throw' is false, returns 0 if identifier cannot be resolved, and the
- * stack will be unaffected in this case. If identifier is resolved, returns
- * 1 and leaves [val this] on top of stack.
- *
- * Note: the 'strict' flag of a reference returned by GetIdentifierReference
- * is ignored by GetValue. Hence we don't take a 'strict' parameter.
- *
- * The 'throw' flag is needed for implementing 'typeof' for an unreferenced
- * identifier. An unreference identifier in other contexts generates a
- * ReferenceError.
- */
-
-DUK_LOCAL
-duk_bool_t duk__getvar_helper(duk_hthread *thr,
- duk_hobject *env,
- duk_activation *act,
- duk_hstring *name,
- duk_bool_t throw_flag) {
- duk_context *ctx = (duk_context *) thr;
- duk__id_lookup_result ref;
- duk_tval tv_tmp_obj;
- duk_tval tv_tmp_key;
- duk_bool_t parents;
-
- DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O "
- "(env -> %!dO)",
- (void *) thr, (void *) env, (void *) act,
- (duk_heaphdr *) name, (duk_heaphdr *) env));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(name != NULL);
- /* env and act may be NULL */
-
- DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
- DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
-
- parents = 1; /* follow parent chain */
- if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
- if (ref.value) {
- DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
- duk_push_tval(ctx, ref.value);
- duk_push_undefined(ctx);
- } else {
- DUK_ASSERT(ref.holder != NULL);
-
- /* Note: getprop may invoke any getter and invalidate any
- * duk_tval pointers, so this must be done first.
- */
-
- if (ref.this_binding) {
- duk_push_tval(ctx, ref.this_binding);
- } else {
- duk_push_undefined(ctx);
- }
-
- DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
- DUK_TVAL_SET_STRING(&tv_tmp_key, name);
- (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */
-
- /* ref.value, ref.this.binding invalidated here by getprop call */
-
- duk_insert(ctx, -2); /* [this value] -> [value this] */
- }
-
- return 1;
- } else {
- if (throw_flag) {
- DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
- "identifier '%s' undefined",
- (const char *) DUK_HSTRING_GET_DATA(name));
- }
-
- return 0;
- }
-}
-
-DUK_INTERNAL
-duk_bool_t duk_js_getvar_envrec(duk_hthread *thr,
- duk_hobject *env,
- duk_hstring *name,
- duk_bool_t throw_flag) {
- return duk__getvar_helper(thr, env, NULL, name, throw_flag);
-}
-
-DUK_INTERNAL
-duk_bool_t duk_js_getvar_activation(duk_hthread *thr,
- duk_activation *act,
- duk_hstring *name,
- duk_bool_t throw_flag) {
- DUK_ASSERT(act != NULL);
- return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag);
-}
-
-/*
- * PUTVAR
- *
- * See E5 Sections:
- * 11.1.2 Identifier Reference
- * 10.3.1 Identifier Resolution
- * 11.13.1 Simple Assignment [example of where the Reference is PutValue'd]
- * 8.7.2 PutValue (V,W) [see especially step 3.b, undefined -> automatic global in non-strict mode]
- * 8.12.4 [[CanPut]] (P)
- * 8.12.5 [[Put]] (P)
- *
- * Note: may invalidate any valstack (or object) duk_tval pointers because
- * putting a value may reallocate any object or any valstack. Caller beware.
- */
-
-DUK_LOCAL
-void duk__putvar_helper(duk_hthread *thr,
- duk_hobject *env,
- duk_activation *act,
- duk_hstring *name,
- duk_tval *val,
- duk_bool_t strict) {
- duk__id_lookup_result ref;
- duk_tval tv_tmp_obj;
- duk_tval tv_tmp_key;
- duk_bool_t parents;
-
- DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
- "(env -> %!dO, val -> %!T)",
- (void *) thr, (void *) env, (void *) act,
- (duk_heaphdr *) name, (void *) val, (long) strict,
- (duk_heaphdr *) env, (duk_tval *) val));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(name != NULL);
- DUK_ASSERT(val != NULL);
- /* env and act may be NULL */
-
- DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
- DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
- DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val);
-
- /*
- * In strict mode E5 protects 'eval' and 'arguments' from being
- * assigned to (or even declared anywhere). Attempt to do so
- * should result in a compile time SyntaxError. See the internal
- * design documentation for details.
- *
- * Thus, we should never come here, run-time, for strict code,
- * and name 'eval' or 'arguments'.
- */
-
- DUK_ASSERT(!strict ||
- (name != DUK_HTHREAD_STRING_EVAL(thr) &&
- name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)));
-
- /*
- * Lookup variable and update in-place if found.
- */
-
- parents = 1; /* follow parent chain */
-
- if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
- if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
- /* Update duk_tval in-place if pointer provided and the
- * property is writable. If the property is not writable
- * (immutable binding), use duk_hobject_putprop() which
- * will respect mutability.
- */
- duk_tval *tv_val;
-
- DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
-
- tv_val = ref.value;
- DUK_ASSERT(tv_val != NULL);
- DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */
-
- /* ref.value and ref.this_binding invalidated here */
- } else {
- DUK_ASSERT(ref.holder != NULL);
-
- DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
- DUK_TVAL_SET_STRING(&tv_tmp_key, name);
- (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
-
- /* ref.value and ref.this_binding invalidated here */
- }
-
- return;
- }
-
- /*
- * Not found: write to global object (non-strict) or ReferenceError
- * (strict); see E5 Section 8.7.2, step 3.
- */
-
- if (strict) {
- DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
- DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "identifier not defined");
- }
-
- DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
-
- DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
- DUK_TVAL_SET_STRING(&tv_tmp_key, name);
- (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0); /* 0 = no throw */
-
- /* NB: 'val' may be invalidated here because put_value may realloc valstack,
- * caller beware.
- */
-}
-
-DUK_INTERNAL
-void duk_js_putvar_envrec(duk_hthread *thr,
- duk_hobject *env,
- duk_hstring *name,
- duk_tval *val,
- duk_bool_t strict) {
- duk__putvar_helper(thr, env, NULL, name, val, strict);
-}
-
-DUK_INTERNAL
-void duk_js_putvar_activation(duk_hthread *thr,
- duk_activation *act,
- duk_hstring *name,
- duk_tval *val,
- duk_bool_t strict) {
- DUK_ASSERT(act != NULL);
- duk__putvar_helper(thr, act->lex_env, act, name, val, strict);
-}
-
-/*
- * DELVAR
- *
- * See E5 Sections:
- * 11.4.1 The delete operator
- * 10.2.1.1.5 DeleteBinding (N) [declarative environment record]
- * 10.2.1.2.5 DeleteBinding (N) [object environment record]
- *
- * Variable bindings established inside eval() are deletable (configurable),
- * other bindings are not, including variables declared in global level.
- * Registers are always non-deletable, and the deletion of other bindings
- * is controlled by the configurable flag.
- *
- * For strict mode code, the 'delete' operator should fail with a compile
- * time SyntaxError if applied to identifiers. Hence, no strict mode
- * run-time deletion of identifiers should ever happen. This function
- * should never be called from strict mode code!
- */
-
-DUK_LOCAL
-duk_bool_t duk__delvar_helper(duk_hthread *thr,
- duk_hobject *env,
- duk_activation *act,
- duk_hstring *name) {
- duk__id_lookup_result ref;
- duk_bool_t parents;
-
- DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O "
- "(env -> %!dO)",
- (void *) thr, (void *) env, (void *) act,
- (duk_heaphdr *) name, (duk_heaphdr *) env));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(name != NULL);
- /* env and act may be NULL */
-
- DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
-
- parents = 1; /* follow parent chain */
-
- if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
- if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
- /* Identifier found in registers (always non-deletable)
- * or declarative environment record and non-configurable.
- */
- return 0;
- }
- DUK_ASSERT(ref.holder != NULL);
-
- return duk_hobject_delprop_raw(thr, ref.holder, name, 0);
- }
-
- /*
- * Not found (even in global object).
- *
- * In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1,
- * step 3.b. In strict mode this case is a compile time SyntaxError so
- * we should not come here.
- */
-
- DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O "
- "(treated as silent success)",
- (duk_heaphdr *) name));
- return 1;
-}
-
-#if 0 /*unused*/
-DUK_INTERNAL
-duk_bool_t duk_js_delvar_envrec(duk_hthread *thr,
- duk_hobject *env,
- duk_hstring *name) {
- return duk__delvar_helper(thr, env, NULL, name);
-}
-#endif
-
-DUK_INTERNAL
-duk_bool_t duk_js_delvar_activation(duk_hthread *thr,
- duk_activation *act,
- duk_hstring *name) {
- DUK_ASSERT(act != NULL);
- return duk__delvar_helper(thr, act->lex_env, act, name);
-}
-
-/*
- * DECLVAR
- *
- * See E5 Sections:
- * 10.4.3 Entering Function Code
- * 10.5 Declaration Binding Instantion
- * 12.2 Variable Statement
- * 11.1.2 Identifier Reference
- * 10.3.1 Identifier Resolution
- *
- * Variable declaration behavior is mainly discussed in Section 10.5,
- * and is not discussed in the execution semantics (Sections 11-13).
- *
- * Conceptually declarations happen when code (global, eval, function)
- * is entered, before any user code is executed. In practice, register-
- * bound identifiers are 'declared' automatically (by virtue of being
- * allocated to registers with the initial value 'undefined'). Other
- * identifiers are declared in the function prologue with this primitive.
- *
- * Since non-register bindings eventually back to an internal object's
- * properties, the 'prop_flags' argument is used to specify binding
- * type:
- *
- * - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false
- * - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false
- * - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it
- * doesn't really matter for internal objects
- *
- * All bindings are non-deletable mutable bindings except:
- *
- * - Declarations in eval code (mutable, deletable)
- * - 'arguments' binding in strict function code (immutable)
- * - Function name binding of a function expression (immutable)
- *
- * Declarations may go to declarative environment records (always
- * so for functions), but may also go to object environment records
- * (e.g. global code). The global object environment has special
- * behavior when re-declaring a function (but not a variable); see
- * E5.1 specification, Section 10.5, step 5.e.
- *
- * Declarations always go to the 'top-most' environment record, i.e.
- * we never check the record chain. It's not an error even if a
- * property (even an immutable or non-deletable one) of the same name
- * already exists.
- *
- * If a declared variable already exists, its value needs to be updated
- * (if possible). Returns 1 if a PUTVAR needs to be done by the caller;
- * otherwise returns 0.
- */
-
-DUK_LOCAL
-duk_bool_t duk__declvar_helper(duk_hthread *thr,
- duk_hobject *env,
- duk_hstring *name,
- duk_tval *val,
- duk_small_int_t prop_flags,
- duk_bool_t is_func_decl) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *holder;
- duk_bool_t parents;
- duk__id_lookup_result ref;
- duk_tval *tv;
-
- DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld "
- "(env -> %!iO)",
- (void *) thr, (void *) env, (duk_heaphdr *) name,
- (duk_tval *) val, (unsigned long) prop_flags,
- (unsigned int) is_func_decl, (duk_heaphdr *) env));
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(env != NULL);
- DUK_ASSERT(name != NULL);
- DUK_ASSERT(val != NULL);
-
- /* Note: in strict mode the compiler should reject explicit
- * declaration of 'eval' or 'arguments'. However, internal
- * bytecode may declare 'arguments' in the function prologue.
- * We don't bother checking (or asserting) for these now.
- */
-
- /* Note: val is a stable duk_tval pointer. The caller makes
- * a value copy into its stack frame, so 'tv_val' is not subject
- * to side effects here.
- */
-
- /*
- * Check whether already declared.
- *
- * We need to check whether the binding exists in the environment
- * without walking its parents. However, we still need to check
- * register-bound identifiers and the prototype chain of an object
- * environment target object.
- */
-
- parents = 0; /* just check 'env' */
- if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
- duk_int_t e_idx;
- duk_int_t h_idx;
- duk_small_int_t flags;
-
- /*
- * Variable already declared, ignore re-declaration.
- * The only exception is the updated behavior of E5.1 for
- * global function declarations, E5.1 Section 10.5, step 5.e.
- * This behavior does not apply to global variable declarations.
- */
-
- if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) {
- DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring"));
- return 1; /* 1 -> needs a PUTVAR */
- }
-
- /*
- * Special behavior in E5.1.
- *
- * Note that even though parents == 0, the conflicting property
- * may be an inherited property (currently our global object's
- * prototype is Object.prototype). Step 5.e first operates on
- * the existing property (which is potentially in an ancestor)
- * and then defines a new property in the global object (and
- * never modifies the ancestor).
- *
- * Also note that this logic would become even more complicated
- * if the conflicting property might be a virtual one. Object
- * prototype has no virtual properties, though.
- *
- * XXX: this is now very awkward, rework.
- */
-
- DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, "
- "updated E5.1 processing"));
-
- DUK_ASSERT(ref.holder != NULL);
- holder = ref.holder;
-
- /* holder will be set to the target object, not the actual object
- * where the property was found (see duk__get_identifier_reference()).
- */
- DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL);
- DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder)); /* global object doesn't have array part */
-
- /* XXX: use a helper for prototype traversal; no loop check here */
- /* must be found: was found earlier, and cannot be inherited */
- for (;;) {
- DUK_ASSERT(holder != NULL);
- duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx);
- if (e_idx >= 0) {
- break;
- }
- /* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
- * asserted above.
- */
- holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder);
- }
- DUK_ASSERT(holder != NULL);
- DUK_ASSERT(e_idx >= 0);
- /* SCANBUILD: scan-build produces a NULL pointer dereference warning
- * below; it never actually triggers because holder is actually never
- * NULL.
- */
-
- /* ref.holder is global object, holder is the object with the
- * conflicting property.
- */
-
- flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx);
- if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
- if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
- "accessor -> reject"));
- goto fail_existing_attributes;
- }
- if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) &&
- (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) {
- DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
- "plain property which is not writable and "
- "enumerable -> reject"));
- goto fail_existing_attributes;
- }
-
- DUK_DDD(DUK_DDDPRINT("existing property is not configurable but "
- "is plain, enumerable, and writable -> "
- "allow redeclaration"));
- }
-
- if (holder == ref.holder) {
- /* XXX: if duk_hobject_define_property_internal() was updated
- * to handle a pre-existing accessor property, this would be
- * a simple call (like for the ancestor case).
- */
- DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself"));
-
- if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
- duk_hobject *tmp;
-
- tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx);
- DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
- DUK_UNREF(tmp);
- tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx);
- DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL);
- DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
- DUK_UNREF(tmp);
- } else {
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
- DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);
- }
-
- /* Here val would be potentially invalid if we didn't make
- * a value copy at the caller.
- */
-
- tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
- DUK_TVAL_SET_TVAL(tv, val);
- DUK_TVAL_INCREF(thr, tv);
- DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags);
-
- DUK_DDD(DUK_DDDPRINT("updated global binding, final result: "
- "value -> %!T, prop_flags=0x%08lx",
- (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx),
- (unsigned long) prop_flags));
- } else {
- DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
-
- DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
- duk_push_tval(ctx, val);
- duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
- }
-
- return 0;
- }
-
- /*
- * Not found (in registers or record objects). Declare
- * to current variable environment.
- */
-
- /*
- * Get holder object
- */
-
- if (DUK_HOBJECT_IS_DECENV(env)) {
- holder = env;
- } else {
- DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env));
-
- tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
- DUK_ASSERT(tv != NULL);
- DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
- holder = DUK_TVAL_GET_OBJECT(tv);
- DUK_ASSERT(holder != NULL);
- }
-
- /*
- * Define new property
- *
- * Note: this may fail if the holder is not extensible.
- */
-
- /* XXX: this is awkward as we use an internal method which doesn't handle
- * extensibility etc correctly. Basically we'd want to do a [[DefineOwnProperty]]
- * or Object.defineProperty() here.
- */
-
- if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) {
- goto fail_not_extensible;
- }
-
- duk_push_hobject(ctx, holder);
- duk_push_hstring(ctx, name);
- duk_push_tval(ctx, val);
- duk_xdef_prop(ctx, -3, prop_flags); /* [holder name val] -> [holder] */
- duk_pop(ctx);
-
- return 0;
-
- fail_existing_attributes:
- fail_not_extensible:
- DUK_ERROR_TYPE(thr, "declaration failed");
- return 0;
-}
-
-DUK_INTERNAL
-duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
- duk_activation *act,
- duk_hstring *name,
- duk_tval *val,
- duk_small_int_t prop_flags,
- duk_bool_t is_func_decl) {
- duk_hobject *env;
- duk_tval tv_val_copy;
-
- /*
- * Make a value copy of the input val. This ensures that
- * side effects cannot invalidate the pointer.
- */
-
- DUK_TVAL_SET_TVAL(&tv_val_copy, val);
- val = &tv_val_copy;
-
- /*
- * Delayed env creation check
- */
-
- if (!act->var_env) {
- DUK_ASSERT(act->lex_env == NULL);
- duk_js_init_activation_environment_records_delayed(thr, act);
- }
- DUK_ASSERT(act->lex_env != NULL);
- DUK_ASSERT(act->var_env != NULL);
-
- env = act->var_env;
- DUK_ASSERT(env != NULL);
- DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
-
- return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl);
-}
-#line 1 "duk_lexer.c"
-/*
- * Lexer for source files, ToNumber() string conversions, RegExp expressions,
- * and JSON.
- *
- * Provides a stream of Ecmascript tokens from an UTF-8/CESU-8 buffer. The
- * caller can also rewind the token stream into a certain position which is
- * needed by the compiler part for multi-pass scanning. Tokens are
- * represented as duk_token structures, and contain line number information.
- * Token types are identified with DUK_TOK_* defines.
- *
- * Characters are decoded into a fixed size lookup window consisting of
- * decoded Unicode code points, with window positions past the end of the
- * input filled with an invalid codepoint (-1). The tokenizer can thus
- * perform multiple character lookups efficiently and with few sanity
- * checks (such as access outside the end of the input), which keeps the
- * tokenization code small at the cost of performance.
- *
- * Character data in tokens, such as identifier names and string literals,
- * is encoded into CESU-8 format on-the-fly while parsing the token in
- * question. The string data is made reachable to garbage collection by
- * placing the token-related values in value stack entries allocated for
- * this purpose by the caller. The characters exist in Unicode code point
- * form only in the fixed size lookup window, which keeps character data
- * expansion (of especially ASCII data) low.
- *
- * Token parsing supports the full range of Unicode characters as described
- * in the E5 specification. Parsing has been optimized for ASCII characters
- * because ordinary Ecmascript code consists almost entirely of ASCII
- * characters. Matching of complex Unicode codepoint sets (such as in the
- * IdentifierStart and IdentifierPart productions) is optimized for size,
- * and is done using a linear scan of a bit-packed list of ranges. This is
- * very slow, but should never be entered unless the source code actually
- * contains Unicode characters.
- *
- * Ecmascript tokenization is partially context sensitive. First,
- * additional future reserved words are recognized in strict mode (see E5
- * Section 7.6.1.2). Second, a forward slash character ('/') can be
- * recognized either as starting a RegExp literal or as a division operator,
- * depending on context. The caller must provide necessary context flags
- * when requesting a new token.
- *
- * Future work:
- *
- * * Make line number tracking optional, as it consumes space.
- *
- * * Add a feature flag for disabling UTF-8 decoding of input, as most
- * source code is ASCII. Because of Unicode escapes written in ASCII,
- * this does not allow Unicode support to be removed from e.g.
- * duk_unicode_is_identifier_start() nor does it allow removal of CESU-8
- * encoding of e.g. string literals.
- *
- * * Add a feature flag for disabling Unicode compliance of e.g. identifier
- * names. This allows for a build more than a kilobyte smaller, because
- * Unicode ranges needed by duk_unicode_is_identifier_start() and
- * duk_unicode_is_identifier_part() can be dropped. String literals
- * should still be allowed to contain escaped Unicode, so this still does
- * not allow removal of CESU-8 encoding of e.g. string literals.
- *
- * * Character lookup tables for codepoints above BMP could be stripped.
- *
- * * Strictly speaking, E5 specification requires that source code consists
- * of 16-bit code units, and if not, must be conceptually converted to
- * that format first. The current lexer processes Unicode code points
- * and allows characters outside the BMP. These should be converted to
- * surrogate pairs while reading the source characters into the window,
- * not after tokens have been formed (as is done now). However, the fix
- * is not trivial because two characters are decoded from one codepoint.
- *
- * * Optimize for speed as well as size. Large if-else ladders are (at
- * least potentially) slow.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Various defines and file specific helper macros
- */
-
-#define DUK__MAX_RE_DECESC_DIGITS 9
-#define DUK__MAX_RE_QUANT_DIGITS 9 /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */
-
-/* whether to use macros or helper function depends on call count */
-#define DUK__ISDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_9)
-#define DUK__ISHEXDIGIT(x) duk__is_hex_digit((x))
-#define DUK__ISOCTDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_7)
-#define DUK__ISDIGIT03(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_3)
-#define DUK__ISDIGIT47(x) ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7)
-
-/* lexer character window helpers */
-#define DUK__LOOKUP(lex_ctx,index) ((lex_ctx)->window[(index)].codepoint)
-#define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_bytes((lex_ctx), (count) * sizeof(duk_lexer_codepoint))
-#define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count))
-#define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx))
-#define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x))
-
-/* lookup shorthands (note: assume context variable is named 'lex_ctx') */
-#define DUK__L0() DUK__LOOKUP(lex_ctx, 0)
-#define DUK__L1() DUK__LOOKUP(lex_ctx, 1)
-#define DUK__L2() DUK__LOOKUP(lex_ctx, 2)
-#define DUK__L3() DUK__LOOKUP(lex_ctx, 3)
-#define DUK__L4() DUK__LOOKUP(lex_ctx, 4)
-#define DUK__L5() DUK__LOOKUP(lex_ctx, 5)
-
-/* packed advance/token number macro used by multiple functions */
-#define DUK__ADVTOK(advbytes,tok) ((((advbytes) * sizeof(duk_lexer_codepoint)) << 8) + (tok))
-
-/*
- * Advance lookup window by N characters, filling in new characters as
- * necessary. After returning caller is guaranteed a character window of
- * at least DUK_LEXER_WINDOW_SIZE characters.
- *
- * The main function duk__advance_bytes() is called at least once per every
- * token so it has a major lexer/compiler performance impact. There are two
- * variants for the main duk__advance_bytes() algorithm: a sliding window
- * approach which is slightly faster at the cost of larger code footprint,
- * and a simple copying one.
- *
- * Decoding directly from the source string would be another lexing option.
- * But the lookup window based approach has the advantage of hiding the
- * source string and its encoding effectively which gives more flexibility
- * going forward to e.g. support chunked streaming of source from flash.
- *
- * Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to
- * U+10FFFF, causing an error if the input is unparseable. Leniency means:
- *
- * * Unicode code point validation is intentionally not performed,
- * except to check that the codepoint does not exceed 0x10ffff.
- *
- * * In particular, surrogate pairs are allowed and not combined, which
- * allows source files to represent all SourceCharacters with CESU-8.
- * Broken surrogate pairs are allowed, as Ecmascript does not mandate
- * their validation.
- *
- * * Allow non-shortest UTF-8 encodings.
- *
- * Leniency here causes few security concerns because all character data is
- * decoded into Unicode codepoints before lexer processing, and is then
- * re-encoded into CESU-8. The source can be parsed as strict UTF-8 with
- * a compiler option. However, Ecmascript source characters include -all-
- * 16-bit unsigned integer codepoints, so leniency seems to be appropriate.
- *
- * Note that codepoints above the BMP are not strictly SourceCharacters,
- * but the lexer still accepts them as such. Before ending up in a string
- * or an identifier name, codepoints above BMP are converted into surrogate
- * pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as
- * expected by Ecmascript.
- *
- * An alternative approach to dealing with invalid or partial sequences
- * would be to skip them and replace them with e.g. the Unicode replacement
- * character U+FFFD. This has limited utility because a replacement character
- * will most likely cause a parse error, unless it occurs inside a string.
- * Further, Ecmascript source is typically pure ASCII.
- *
- * See:
- *
- * http://en.wikipedia.org/wiki/UTF-8
- * http://en.wikipedia.org/wiki/CESU-8
- * http://tools.ietf.org/html/rfc3629
- * http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
- *
- * Future work:
- *
- * * Reject other invalid Unicode sequences (see Wikipedia entry for examples)
- * in strict UTF-8 mode.
- *
- * * Size optimize. An attempt to use a 16-byte lookup table for the first
- * byte resulted in a code increase though.
- *
- * * Is checking against maximum 0x10ffff really useful? 4-byte encoding
- * imposes a certain limit anyway.
- *
- * * Support chunked streaming of source code. Can be implemented either
- * by streaming chunks of bytes or chunks of codepoints.
- */
-
-#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
-DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t start_offset_bytes) {
- duk_lexer_codepoint *cp, *cp_end;
- duk_ucodepoint_t x;
- duk_small_uint_t contlen;
- const duk_uint8_t *p, *p_end;
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- duk_ucodepoint_t mincp;
-#endif
- duk_int_t input_line;
-
- /* Use temporaries and update lex_ctx only when finished. */
- input_line = lex_ctx->input_line;
- p = lex_ctx->input + lex_ctx->input_offset;
- p_end = lex_ctx->input + lex_ctx->input_length;
-
- cp = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->buffer + start_offset_bytes);
- cp_end = lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE;
-
- for (; cp != cp_end; cp++) {
- cp->offset = (duk_size_t) (p - lex_ctx->input);
- cp->line = input_line;
-
- /* XXX: potential issue with signed pointers, p_end < p. */
- if (DUK_UNLIKELY(p >= p_end)) {
- /* If input_offset were assigned a negative value, it would
- * result in a large positive value. Most likely it would be
- * larger than input_length and be caught here. In any case
- * no memory unsafe behavior would happen.
- */
- cp->codepoint = -1;
- continue;
- }
-
- x = (duk_ucodepoint_t) (*p++);
-
- /* Fast path. */
-
- if (DUK_LIKELY(x < 0x80UL)) {
- DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
- if (DUK_UNLIKELY(x <= 0x000dUL)) {
- if ((x == 0x000aUL) ||
- ((x == 0x000dUL) && (p >= p_end || *p != 0x000aUL))) {
- /* lookup for 0x000a above assumes shortest encoding now */
-
- /* E5 Section 7.3, treat the following as newlines:
- * LF
- * CR [not followed by LF]
- * LS
- * PS
- *
- * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
- * the line number.
- */
- input_line++;
- }
- }
-
- cp->codepoint = (duk_codepoint_t) x;
- continue;
- }
-
- /* Slow path. */
-
- if (x < 0xc0UL) {
- /* 10xx xxxx -> invalid */
- goto error_encoding;
- } else if (x < 0xe0UL) {
- /* 110x xxxx 10xx xxxx */
- contlen = 1;
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- mincp = 0x80UL;
-#endif
- x = x & 0x1fUL;
- } else if (x < 0xf0UL) {
- /* 1110 xxxx 10xx xxxx 10xx xxxx */
- contlen = 2;
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- mincp = 0x800UL;
-#endif
- x = x & 0x0fUL;
- } else if (x < 0xf8UL) {
- /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
- contlen = 3;
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- mincp = 0x10000UL;
-#endif
- x = x & 0x07UL;
- } else {
- /* no point in supporting encodings of 5 or more bytes */
- goto error_encoding;
- }
-
- DUK_ASSERT(p_end >= p);
- if ((duk_size_t) contlen > (duk_size_t) (p_end - p)) {
- goto error_clipped;
- }
-
- while (contlen > 0) {
- duk_small_uint_t y;
- y = *p++;
- if ((y & 0xc0U) != 0x80U) {
- /* check that byte has the form 10xx xxxx */
- goto error_encoding;
- }
- x = x << 6;
- x += y & 0x3fUL;
- contlen--;
- }
-
- /* check final character validity */
-
- if (x > 0x10ffffUL) {
- goto error_encoding;
- }
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
- goto error_encoding;
- }
-#endif
-
- DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
- if ((x == 0x2028UL) || (x == 0x2029UL)) {
- input_line++;
- }
-
- cp->codepoint = (duk_codepoint_t) x;
- }
-
- lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
- lex_ctx->input_line = input_line;
- return;
-
- error_clipped: /* clipped codepoint */
- error_encoding: /* invalid codepoint encoding or codepoint */
- lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
- lex_ctx->input_line = input_line;
-
- DUK_ERROR_SYNTAX(lex_ctx->thr, "utf-8 decode failed");
-}
-
-DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
- duk_small_uint_t used_bytes, avail_bytes;
-
- DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
- DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
- DUK_ASSERT(lex_ctx->window >= lex_ctx->buffer);
- DUK_ASSERT(lex_ctx->window < lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE);
- DUK_ASSERT((duk_uint8_t *) lex_ctx->window + count_bytes <= (duk_uint8_t *) lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint));
-
- /* Zero 'count' is also allowed to make call sites easier.
- * Arithmetic in bytes generates better code in GCC.
- */
-
- lex_ctx->window = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->window + count_bytes); /* avoid multiply */
- used_bytes = (duk_small_uint_t) ((duk_uint8_t *) lex_ctx->window - (duk_uint8_t *) lex_ctx->buffer);
- avail_bytes = DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint) - used_bytes;
- if (avail_bytes < (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))) {
- /* Not enough data to provide a full window, so "scroll" window to
- * start of buffer and fill up the rest.
- */
- DUK_MEMMOVE((void *) lex_ctx->buffer,
- (const void *) lex_ctx->window,
- (size_t) avail_bytes);
- lex_ctx->window = lex_ctx->buffer;
- duk__fill_lexer_buffer(lex_ctx, avail_bytes);
- }
-}
-
-DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
- lex_ctx->window = lex_ctx->buffer;
- duk__fill_lexer_buffer(lex_ctx, 0);
-}
-#else /* DUK_USE_LEXER_SLIDING_WINDOW */
-DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
- duk_ucodepoint_t x;
- duk_small_uint_t len;
- duk_small_uint_t i;
- const duk_uint8_t *p;
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- duk_ucodepoint_t mincp;
-#endif
- duk_size_t input_offset;
-
- input_offset = lex_ctx->input_offset;
- if (DUK_UNLIKELY(input_offset >= lex_ctx->input_length)) {
- /* If input_offset were assigned a negative value, it would
- * result in a large positive value. Most likely it would be
- * larger than input_length and be caught here. In any case
- * no memory unsafe behavior would happen.
- */
- return -1;
- }
-
- p = lex_ctx->input + input_offset;
- x = (duk_ucodepoint_t) (*p);
-
- if (DUK_LIKELY(x < 0x80UL)) {
- /* 0xxx xxxx -> fast path */
-
- /* input offset tracking */
- lex_ctx->input_offset++;
-
- DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
- if (DUK_UNLIKELY(x <= 0x000dUL)) {
- if ((x == 0x000aUL) ||
- ((x == 0x000dUL) && (lex_ctx->input_offset >= lex_ctx->input_length ||
- lex_ctx->input[lex_ctx->input_offset] != 0x000aUL))) {
- /* lookup for 0x000a above assumes shortest encoding now */
-
- /* E5 Section 7.3, treat the following as newlines:
- * LF
- * CR [not followed by LF]
- * LS
- * PS
- *
- * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
- * the line number.
- */
- lex_ctx->input_line++;
- }
- }
-
- return (duk_codepoint_t) x;
- }
-
- /* Slow path. */
-
- if (x < 0xc0UL) {
- /* 10xx xxxx -> invalid */
- goto error_encoding;
- } else if (x < 0xe0UL) {
- /* 110x xxxx 10xx xxxx */
- len = 2;
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- mincp = 0x80UL;
-#endif
- x = x & 0x1fUL;
- } else if (x < 0xf0UL) {
- /* 1110 xxxx 10xx xxxx 10xx xxxx */
- len = 3;
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- mincp = 0x800UL;
-#endif
- x = x & 0x0fUL;
- } else if (x < 0xf8UL) {
- /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
- len = 4;
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- mincp = 0x10000UL;
-#endif
- x = x & 0x07UL;
- } else {
- /* no point in supporting encodings of 5 or more bytes */
- goto error_encoding;
- }
-
- DUK_ASSERT(lex_ctx->input_length >= lex_ctx->input_offset);
- if ((duk_size_t) len > (duk_size_t) (lex_ctx->input_length - lex_ctx->input_offset)) {
- goto error_clipped;
- }
-
- p++;
- for (i = 1; i < len; i++) {
- duk_small_uint_t y;
- y = *p++;
- if ((y & 0xc0U) != 0x80U) {
- /* check that byte has the form 10xx xxxx */
- goto error_encoding;
- }
- x = x << 6;
- x += y & 0x3fUL;
- }
-
- /* check final character validity */
-
- if (x > 0x10ffffUL) {
- goto error_encoding;
- }
-#if defined(DUK_USE_STRICT_UTF8_SOURCE)
- if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
- goto error_encoding;
- }
-#endif
-
- /* input offset tracking */
- lex_ctx->input_offset += len;
-
- /* line tracking */
- DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
- if ((x == 0x2028UL) || (x == 0x2029UL)) {
- lex_ctx->input_line++;
- }
-
- return (duk_codepoint_t) x;
-
- error_clipped: /* clipped codepoint */
- error_encoding: /* invalid codepoint encoding or codepoint */
- DUK_ERROR_SYNTAX(lex_ctx->thr, "utf-8 decode failed");
- return 0;
-}
-
-DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
- duk_small_uint_t keep_bytes;
- duk_lexer_codepoint *cp, *cp_end;
-
- DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
- DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
-
- /* Zero 'count' is also allowed to make call sites easier. */
-
- keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes;
- DUK_MEMMOVE((void *) lex_ctx->window,
- (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes),
- (size_t) keep_bytes);
-
- cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes);
- cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE;
- for (; cp != cp_end; cp++) {
- cp->offset = lex_ctx->input_offset;
- cp->line = lex_ctx->input_line;
- cp->codepoint = duk__read_char(lex_ctx);
- }
-}
-
-DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
- /* Call with count == DUK_LEXER_WINDOW_SIZE to fill buffer initially. */
- duk__advance_bytes(lex_ctx, DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)); /* fill window */
-}
-#endif /* DUK_USE_LEXER_SLIDING_WINDOW */
-
-/*
- * (Re)initialize the temporary byte buffer. May be called extra times
- * with little impact.
- */
-
-DUK_LOCAL void duk__initbuffer(duk_lexer_ctx *lex_ctx) {
- /* Reuse buffer as is unless buffer has grown large. */
- if (DUK_HBUFFER_DYNAMIC_GET_SIZE(lex_ctx->buf) < DUK_LEXER_TEMP_BUF_LIMIT) {
- /* Keep current size */
- } else {
- duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, DUK_LEXER_TEMP_BUF_LIMIT);
- }
-
- DUK_BW_INIT_WITHBUF(lex_ctx->thr, &lex_ctx->bw, lex_ctx->buf);
-}
-
-/*
- * Append a Unicode codepoint to the temporary byte buffer. Performs
- * CESU-8 surrogate pair encoding for codepoints above the BMP.
- * Existing surrogate pairs are allowed and also encoded into CESU-8.
- */
-
-DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
- /*
- * Since character data is only generated by decoding the source or by
- * the compiler itself, we rely on the input codepoints being correct
- * and avoid a check here.
- *
- * Character data can also come here through decoding of Unicode
- * escapes ("\udead\ubeef") so all 16-but unsigned values can be
- * present, even when the source file itself is strict UTF-8.
- */
-
- DUK_ASSERT(x >= 0 && x <= 0x10ffff);
-
- DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x);
-}
-
-/*
- * Intern the temporary byte buffer into a valstack slot
- * (in practice, slot1 or slot2).
- */
-
-DUK_LOCAL void duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
- duk_context *ctx = (duk_context *) lex_ctx->thr;
-
- DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
-
- DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw);
- duk_replace(ctx, valstack_idx);
-}
-
-/*
- * Init lexer context
- */
-
-DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) {
- DUK_ASSERT(lex_ctx != NULL);
-
- DUK_MEMZERO(lex_ctx, sizeof(*lex_ctx));
-#if defined(DUK_USE_EXPLICIT_NULL_INIT)
-#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
- lex_ctx->window = NULL;
-#endif
- lex_ctx->thr = NULL;
- lex_ctx->input = NULL;
- lex_ctx->buf = NULL;
-#endif
-}
-
-/*
- * Set lexer input position and reinitialize lookup window.
- */
-
-/* NB: duk_lexer_getpoint() is a macro only */
-
-DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
- DUK_ASSERT_DISABLE(pt->offset >= 0); /* unsigned */
- DUK_ASSERT(pt->line >= 1);
- lex_ctx->input_offset = pt->offset;
- lex_ctx->input_line = pt->line;
- duk__init_lexer_window(lex_ctx);
-}
-
-/*
- * Lexing helpers
- */
-
-/* numeric value of a hex digit (also covers octal and decimal digits) */
-DUK_LOCAL duk_codepoint_t duk__hexval(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
- duk_small_int_t t;
-
- /* Here 'x' is a Unicode codepoint */
- if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
- t = duk_hex_dectab[x];
- if (DUK_LIKELY(t >= 0)) {
- return t;
- }
- }
-
- /* Throwing an error this deep makes the error rather vague, but
- * saves hundreds of bytes of code.
- */
- DUK_ERROR_SYNTAX(lex_ctx->thr, "decode error");
- return 0;
-}
-
-/* having this as a separate function provided a size benefit */
-DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) {
- if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
- return (duk_hex_dectab[x] >= 0);
- }
- return 0;
-}
-
-DUK_LOCAL duk_codepoint_t duk__decode_hexesc_from_window(duk_lexer_ctx *lex_ctx, duk_small_int_t lookup_offset) {
- /* validation performed by duk__hexval */
- return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset].codepoint) << 4) |
- (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1].codepoint));
-}
-
-DUK_LOCAL duk_codepoint_t duk__decode_uniesc_from_window(duk_lexer_ctx *lex_ctx, duk_small_int_t lookup_offset) {
- /* validation performed by duk__hexval */
- return (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset].codepoint) << 12) |
- (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 1].codepoint) << 8) |
- (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 2].codepoint) << 4) |
- (duk__hexval(lex_ctx, lex_ctx->window[lookup_offset + 3].codepoint));
-}
-
-/*
- * Parse Ecmascript source InputElementDiv or InputElementRegExp
- * (E5 Section 7), skipping whitespace, comments, and line terminators.
- *
- * Possible results are:
- * (1) a token
- * (2) a line terminator (skipped)
- * (3) a comment (skipped)
- * (4) EOF
- *
- * White space is automatically skipped from the current position (but
- * not after the input element). If input has already ended, returns
- * DUK_TOK_EOF indefinitely. If a parse error occurs, uses an DUK_ERROR()
- * macro call (and hence a longjmp through current heap longjmp context).
- * Comments and line terminator tokens are automatically skipped.
- *
- * The input element being matched is determined by regexp_mode; if set,
- * parses a InputElementRegExp, otherwise a InputElementDiv. The
- * difference between these are handling of productions starting with a
- * forward slash.
- *
- * If strict_mode is set, recognizes additional future reserved words
- * specific to strict mode, and refuses to parse octal literals.
- *
- * The matching strategy below is to (currently) use a six character
- * lookup window to quickly determine which production is the -longest-
- * matching one, and then parse that. The top-level if-else clauses
- * match the first character, and the code blocks for each clause
- * handle -all- alternatives for that first character. Ecmascript
- * specification uses the "longest match wins" semantics, so the order
- * of the if-clauses matters.
- *
- * Misc notes:
- *
- * * Ecmascript numeric literals do not accept a sign character.
- * Consequently e.g. "-1.0" is parsed as two tokens: a negative
- * sign and a positive numeric literal. The compiler performs
- * the negation during compilation, so this has no adverse impact.
- *
- * * There is no token for "undefined": it is just a value available
- * from the global object (or simply established by doing a reference
- * to an undefined value).
- *
- * * Some contexts want Identifier tokens, which are IdentifierNames
- * excluding reserved words, while some contexts want IdentifierNames
- * directly. In the latter case e.g. "while" is interpreted as an
- * identifier name, not a DUK_TOK_WHILE token. The solution here is
- * to provide both token types: DUK_TOK_WHILE goes to 't' while
- * DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains
- * the identifier / keyword name.
- *
- * * Directive prologue needs to identify string literals such as
- * "use strict" and 'use strict', which are sensitive to line
- * continuations and escape sequences. For instance, "use\u0020strict"
- * is a valid directive but is distinct from "use strict". The solution
- * here is to decode escapes while tokenizing, but to keep track of the
- * number of escapes. Directive detection can then check that the
- * number of escapes is zero.
- *
- * * Multi-line comments with one or more internal LineTerminator are
- * treated like a line terminator to comply with automatic semicolon
- * insertion.
- */
-
-DUK_INTERNAL
-void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
- duk_token *out_token,
- duk_bool_t strict_mode,
- duk_bool_t regexp_mode) {
- duk_codepoint_t x; /* temporary, must be signed and 32-bit to hold Unicode code points */
- duk_small_uint_t advtok = 0; /* (advance << 8) + token_type, updated at function end,
- * init is unnecessary but suppresses "may be used uninitialized" warnings.
- */
- duk_bool_t got_lineterm = 0; /* got lineterm preceding non-whitespace, non-lineterm token */
-
- if (++lex_ctx->token_count >= lex_ctx->token_limit) {
- DUK_ERROR_RANGE(lex_ctx->thr, "token limit");
- return; /* unreachable */
- }
-
- out_token->t = DUK_TOK_EOF;
- out_token->t_nores = -1; /* marker: copy t if not changed */
-#if 0 /* not necessary to init, disabled for faster parsing */
- out_token->num = DUK_DOUBLE_NAN;
- out_token->str1 = NULL;
- out_token->str2 = NULL;
-#endif
- out_token->num_escapes = 0;
- /* out_token->lineterm set by caller */
-
- /* This would be nice, but parsing is faster without resetting the
- * value slots. The only side effect is that references to temporary
- * string values may linger until lexing is finished; they're then
- * freed normally.
- */
-#if 0
- duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
- duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
-#endif
-
- /* 'advtok' indicates how much to advance and which token id to assign
- * at the end. This shared functionality minimizes code size. All
- * code paths are required to set 'advtok' to some value, so no default
- * init value is used. Code paths calling DUK_ERROR() never return so
- * they don't need to set advtok.
- */
-
- /*
- * Matching order:
- *
- * Punctuator first chars, also covers comments, regexps
- * LineTerminator
- * Identifier or reserved word, also covers null/true/false literals
- * NumericLiteral
- * StringLiteral
- * EOF
- *
- * The order does not matter as long as the longest match is
- * always correctly identified. There are order dependencies
- * in the clauses, so it's not trivial to convert to a switch.
- */
-
- restart_lineupdate:
- out_token->start_line = lex_ctx->window[0].line;
-
- restart:
- out_token->start_offset = lex_ctx->window[0].offset;
-
- x = DUK__L0();
-
- switch (x) {
- case DUK_ASC_SPACE:
- case DUK_ASC_HT: /* fast paths for space and tab */
- DUK__ADVANCECHARS(lex_ctx, 1);
- goto restart;
- case DUK_ASC_LF: /* LF line terminator; CR LF and Unicode lineterms are handled in slow path */
- DUK__ADVANCECHARS(lex_ctx, 1);
- got_lineterm = 1;
- goto restart_lineupdate;
- case DUK_ASC_SLASH: /* '/' */
- if (DUK__L1() == '/') {
- /*
- * E5 Section 7.4, allow SourceCharacter (which is any 16-bit
- * code point).
- */
-
- /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */
- for (;;) {
- x = DUK__L0();
- if (x < 0 || duk_unicode_is_line_terminator(x)) {
- break;
- }
- DUK__ADVANCECHARS(lex_ctx, 1);
- }
- goto restart; /* line terminator will be handled on next round */
- } else if (DUK__L1() == '*') {
- /*
- * E5 Section 7.4. If the multi-line comment contains a newline,
- * it is treated like a single line terminator for automatic
- * semicolon insertion.
- */
-
- duk_bool_t last_asterisk = 0;
- DUK__ADVANCECHARS(lex_ctx, 2);
- for (;;) {
- x = DUK__L0();
- if (x < 0) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof in multiline comment");
- }
- DUK__ADVANCECHARS(lex_ctx, 1);
- if (last_asterisk && x == '/') {
- break;
- }
- if (duk_unicode_is_line_terminator(x)) {
- got_lineterm = 1;
- }
- last_asterisk = (x == '*');
- }
- goto restart_lineupdate;
- } else if (regexp_mode) {
-#if defined(DUK_USE_REGEXP_SUPPORT)
- /*
- * "/" followed by something in regexp mode. See E5 Section 7.8.5.
- *
- * RegExp parsing is a bit complex. First, the regexp body is delimited
- * by forward slashes, but the body may also contain forward slashes as
- * part of an escape sequence or inside a character class (delimited by
- * square brackets). A mini state machine is used to implement these.
- *
- * Further, an early (parse time) error must be thrown if the regexp
- * would cause a run-time error when used in the expression new RegExp(...).
- * Parsing here simply extracts the (candidate) regexp, and also accepts
- * invalid regular expressions (which are delimited properly). The caller
- * (compiler) must perform final validation and regexp compilation.
- *
- * RegExp first char may not be '/' (single line comment) or '*' (multi-
- * line comment). These have already been checked above, so there is no
- * need below for special handling of the first regexp character as in
- * the E5 productions.
- *
- * About unicode escapes within regexp literals:
- *
- * E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes.
- * However, Section 6 states that regexps accept the escapes,
- * see paragraph starting with "In string literals...".
- * The regexp grammar, which sees the decoded regexp literal
- * (after lexical parsing) DOES have a \uHHHH unicode escape.
- * So, for instance:
- *
- * /\u1234/
- *
- * should first be parsed by the lexical grammar as:
- *
- * '\' 'u' RegularExpressionBackslashSequence
- * '1' RegularExpressionNonTerminator
- * '2' RegularExpressionNonTerminator
- * '3' RegularExpressionNonTerminator
- * '4' RegularExpressionNonTerminator
- *
- * and the escape itself is then parsed by the regexp engine.
- * This is the current implementation.
- *
- * Minor spec inconsistency:
- *
- * E5 Section 7.8.5 RegularExpressionBackslashSequence is:
- *
- * \ RegularExpressionNonTerminator
- *
- * while Section A.1 RegularExpressionBackslashSequence is:
- *
- * \ NonTerminator
- *
- * The latter is not normative and a typo.
- *
- */
-
- /* first, parse regexp body roughly */
-
- duk_small_int_t state = 0; /* 0=base, 1=esc, 2=class, 3=class+esc */
-
- DUK__INITBUFFER(lex_ctx);
- for (;;) {
- DUK__ADVANCECHARS(lex_ctx, 1); /* skip opening slash on first loop */
- x = DUK__L0();
- if (x < 0 || duk_unicode_is_line_terminator(x)) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in regexp");
- }
- x = DUK__L0(); /* re-read to avoid spill / fetch */
- if (state == 0) {
- if (x == '/') {
- DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing slash */
- break;
- } else if (x == '\\') {
- state = 1;
- } else if (x == '[') {
- state = 2;
- }
- } else if (state == 1) {
- state = 0;
- } else if (state == 2) {
- if (x == ']') {
- state = 0;
- } else if (x == '\\') {
- state = 3;
- }
- } else { /* state == 3 */
- state = 2;
- }
- DUK__APPENDBUFFER(lex_ctx, x);
- }
- duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
- out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
-
- /* second, parse flags */
-
- DUK__INITBUFFER(lex_ctx);
- for (;;) {
- x = DUK__L0();
- if (!duk_unicode_is_identifier_part(x)) {
- break;
- }
- x = DUK__L0(); /* re-read to avoid spill / fetch */
- DUK__APPENDBUFFER(lex_ctx, x);
- DUK__ADVANCECHARS(lex_ctx, 1);
- }
- duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
- out_token->str2 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
-
- DUK__INITBUFFER(lex_ctx); /* free some memory */
-
- /* validation of the regexp is caller's responsibility */
-
- advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP);
-#else
- DUK_ERROR_SYNTAX(lex_ctx->thr, "regexp support disabled");
-#endif
- } else if (DUK__L1() == '=') {
- /* "/=" and not in regexp mode */
- advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ);
- } else {
- /* "/" and not in regexp mode */
- advtok = DUK__ADVTOK(1, DUK_TOK_DIV);
- }
- break;
- case DUK_ASC_LCURLY: /* '{' */
- advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY);
- break;
- case DUK_ASC_RCURLY: /* '}' */
- advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY);
- break;
- case DUK_ASC_LPAREN: /* '(' */
- advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN);
- break;
- case DUK_ASC_RPAREN: /* ')' */
- advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN);
- break;
- case DUK_ASC_LBRACKET: /* '[' */
- advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET);
- break;
- case DUK_ASC_RBRACKET: /* ']' */
- advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET);
- break;
- case DUK_ASC_PERIOD: /* '.' */
- if (DUK__ISDIGIT(DUK__L1())) {
- /* Period followed by a digit can only start DecimalLiteral
- * (handled in slow path). We could jump straight into the
- * DecimalLiteral handling but should avoid goto to inside
- * a block.
- */
- goto slow_path;
- }
- advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD);
- break;
- case DUK_ASC_SEMICOLON: /* ';' */
- advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON);
- break;
- case DUK_ASC_COMMA: /* ',' */
- advtok = DUK__ADVTOK(1, DUK_TOK_COMMA);
- break;
- case DUK_ASC_LANGLE: /* '<' */
- if (DUK__L1() == '<' && DUK__L2() == '=') {
- advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ);
- } else if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_LE);
- } else if (DUK__L1() == '<') {
- advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_LT);
- }
- break;
- case DUK_ASC_RANGLE: /* '>' */
- if (DUK__L1() == '>' && DUK__L2() == '>' && DUK__L3() == '=') {
- advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ);
- } else if (DUK__L1() == '>' && DUK__L2() == '>') {
- advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT);
- } else if (DUK__L1() == '>' && DUK__L2() == '=') {
- advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ);
- } else if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_GE);
- } else if (DUK__L1() == '>') {
- advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_GT);
- }
- break;
- case DUK_ASC_EQUALS: /* '=' */
- if (DUK__L1() == '=' && DUK__L2() == '=') {
- advtok = DUK__ADVTOK(3, DUK_TOK_SEQ);
- } else if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_EQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN);
- }
- break;
- case DUK_ASC_EXCLAMATION: /* '!' */
- if (DUK__L1() == '=' && DUK__L2() == '=') {
- advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ);
- } else if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_NEQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_LNOT);
- }
- break;
- case DUK_ASC_PLUS: /* '+' */
- if (DUK__L1() == '+') {
- advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT);
- } else if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_ADD);
- }
- break;
- case DUK_ASC_MINUS: /* '-' */
- if (DUK__L1() == '-') {
- advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT);
- } else if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_SUB);
- }
- break;
- case DUK_ASC_STAR: /* '*' */
- if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_MUL);
- }
- break;
- case DUK_ASC_PERCENT: /* '%' */
- if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_MOD);
- }
- break;
- case DUK_ASC_AMP: /* '&' */
- if (DUK__L1() == '&') {
- advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
- } else if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_BAND);
- }
- break;
- case DUK_ASC_PIPE: /* '|' */
- if (DUK__L1() == '|') {
- advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
- } else if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_BOR);
- }
- break;
- case DUK_ASC_CARET: /* '^' */
- if (DUK__L1() == '=') {
- advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ);
- } else {
- advtok = DUK__ADVTOK(1, DUK_TOK_BXOR);
- }
- break;
- case DUK_ASC_TILDE: /* '~' */
- advtok = DUK__ADVTOK(1, DUK_TOK_BNOT);
- break;
- case DUK_ASC_QUESTION: /* '?' */
- advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION);
- break;
- case DUK_ASC_COLON: /* ':' */
- advtok = DUK__ADVTOK(1, DUK_TOK_COLON);
- break;
- case DUK_ASC_DOUBLEQUOTE: /* '"' */
- case DUK_ASC_SINGLEQUOTE: { /* '\'' */
- duk_small_int_t quote = x; /* Note: duk_uint8_t type yields larger code */
- duk_small_int_t adv;
-
- DUK__INITBUFFER(lex_ctx);
- for (;;) {
- DUK__ADVANCECHARS(lex_ctx, 1); /* eat opening quote on first loop */
- x = DUK__L0();
- if (x < 0 || duk_unicode_is_line_terminator(x)) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in string literal");
- }
- if (x == quote) {
- DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */
- break;
- }
- if (x == '\\') {
- /* DUK__L0 -> '\' char
- * DUK__L1 ... DUK__L5 -> more lookup
- */
-
- x = DUK__L1();
-
- /* How much to advance before next loop; note that next loop
- * will advance by 1 anyway, so -1 from the total escape
- * length (e.g. len('\uXXXX') - 1 = 6 - 1). As a default,
- * 1 is good.
- */
- adv = 2 - 1; /* note: long live range */
-
- if (x < 0) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof or line terminator in string literal");
- }
- if (duk_unicode_is_line_terminator(x)) {
- /* line continuation */
- if (x == 0x000d && DUK__L2() == 0x000a) {
- /* CR LF again a special case */
- adv = 3 - 1;
- }
- } else if (x == '\'') {
- DUK__APPENDBUFFER(lex_ctx, 0x0027);
- } else if (x == '"') {
- DUK__APPENDBUFFER(lex_ctx, 0x0022);
- } else if (x == '\\') {
- DUK__APPENDBUFFER(lex_ctx, 0x005c);
- } else if (x == 'b') {
- DUK__APPENDBUFFER(lex_ctx, 0x0008);
- } else if (x == 'f') {
- DUK__APPENDBUFFER(lex_ctx, 0x000c);
- } else if (x == 'n') {
- DUK__APPENDBUFFER(lex_ctx, 0x000a);
- } else if (x == 'r') {
- DUK__APPENDBUFFER(lex_ctx, 0x000d);
- } else if (x == 't') {
- DUK__APPENDBUFFER(lex_ctx, 0x0009);
- } else if (x == 'v') {
- DUK__APPENDBUFFER(lex_ctx, 0x000b);
- } else if (x == 'x') {
- adv = 4 - 1;
- DUK__APPENDBUFFER(lex_ctx, duk__decode_hexesc_from_window(lex_ctx, 2));
- } else if (x == 'u') {
- adv = 6 - 1;
- DUK__APPENDBUFFER(lex_ctx, duk__decode_uniesc_from_window(lex_ctx, 2));
- } else if (DUK__ISDIGIT(x)) {
- duk_codepoint_t ch = 0; /* initialized to avoid warnings of unused var */
-
- /*
- * Octal escape or zero escape:
- * \0 (lookahead not DecimalDigit)
- * \1 ... \7 (lookahead not DecimalDigit)
- * \ZeroToThree OctalDigit (lookahead not DecimalDigit)
- * \FourToSeven OctalDigit (no lookahead restrictions)
- * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions)
- *
- * Zero escape is part of the standard syntax. Octal escapes are
- * defined in E5 Section B.1.2, and are only allowed in non-strict mode.
- * Any other productions starting with a decimal digit are invalid.
- */
-
- if (x == '0' && !DUK__ISDIGIT(DUK__L2())) {
- /* Zero escape (also allowed in non-strict mode) */
- ch = 0;
- /* adv = 2 - 1 default OK */
-#if defined(DUK_USE_OCTAL_SUPPORT)
- } else if (strict_mode) {
- /* No other escape beginning with a digit in strict mode */
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid escape in string literal");
- } else if (DUK__ISDIGIT03(x) && DUK__ISOCTDIGIT(DUK__L2()) && DUK__ISOCTDIGIT(DUK__L3())) {
- /* Three digit octal escape, digits validated. */
- adv = 4 - 1;
- ch = (duk__hexval(lex_ctx, x) << 6) +
- (duk__hexval(lex_ctx, DUK__L2()) << 3) +
- duk__hexval(lex_ctx, DUK__L3());
- } else if (((DUK__ISDIGIT03(x) && !DUK__ISDIGIT(DUK__L3())) || DUK__ISDIGIT47(x)) &&
- DUK__ISOCTDIGIT(DUK__L2())) {
- /* Two digit octal escape, digits validated.
- *
- * The if-condition is a bit tricky. We could catch e.g.
- * '\039' in the three-digit escape and fail it there (by
- * validating the digits), but we want to avoid extra
- * additional validation code.
- */
- adv = 3 - 1;
- ch = (duk__hexval(lex_ctx, x) << 3) +
- duk__hexval(lex_ctx, DUK__L2());
- } else if (DUK__ISDIGIT(x) && !DUK__ISDIGIT(DUK__L2())) {
- /* One digit octal escape, digit validated. */
- /* adv = 2 default OK */
- ch = duk__hexval(lex_ctx, x);
-#else
- /* fall through to error */
-#endif
- } else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid escape in string literal");
- }
-
- DUK__APPENDBUFFER(lex_ctx, ch);
- } else {
- /* escaped NonEscapeCharacter */
- DUK__APPENDBUFFER(lex_ctx, x);
- }
- DUK__ADVANCECHARS(lex_ctx, adv);
-
- /* Track number of escapes; count not really needed but directive
- * prologues need to detect whether there were any escapes or line
- * continuations or not.
- */
- out_token->num_escapes++;
- } else {
- /* part of string */
- DUK__APPENDBUFFER(lex_ctx, x);
- }
- }
-
- duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
- out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
-
- DUK__INITBUFFER(lex_ctx); /* free some memory */
-
- advtok = DUK__ADVTOK(0, DUK_TOK_STRING);
- break;
- }
- default:
- goto slow_path;
- } /* switch */
-
- goto skip_slow_path;
-
- slow_path:
- if (duk_unicode_is_line_terminator(x)) {
- if (x == 0x000d && DUK__L1() == 0x000a) {
- /*
- * E5 Section 7.3: CR LF is detected as a single line terminator for
- * line numbers. Here we also detect it as a single line terminator
- * token.
- */
- DUK__ADVANCECHARS(lex_ctx, 2);
- } else {
- DUK__ADVANCECHARS(lex_ctx, 1);
- }
- got_lineterm = 1;
- goto restart_lineupdate;
- } else if (duk_unicode_is_identifier_start(x) || x == '\\') {
- /*
- * Parse an identifier and then check whether it is:
- * - reserved word (keyword or other reserved word)
- * - "null" (NullLiteral)
- * - "true" (BooleanLiteral)
- * - "false" (BooleanLiteral)
- * - anything else => identifier
- *
- * This does not follow the E5 productions cleanly, but is
- * useful and compact.
- *
- * Note that identifiers may contain Unicode escapes,
- * see E5 Sections 6 and 7.6. They must be decoded first,
- * and the result checked against allowed characters.
- * The above if-clause accepts an identifier start and an
- * '\' character -- no other token can begin with a '\'.
- *
- * Note that "get" and "set" are not reserved words in E5
- * specification so they are recognized as plain identifiers
- * (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not
- * used now). The compiler needs to work around this.
- *
- * Strictly speaking, following Ecmascript longest match
- * specification, an invalid escape for the first character
- * should cause a syntax error. However, an invalid escape
- * for IdentifierParts should just terminate the identifier
- * early (longest match), and let the next tokenization
- * fail. For instance Rhino croaks with 'foo\z' when
- * parsing the identifier. This has little practical impact.
- */
-
- duk_small_int_t i, i_end;
- duk_bool_t first = 1;
- duk_hstring *str;
-
- DUK__INITBUFFER(lex_ctx);
- for (;;) {
- /* re-lookup first char on first loop */
- if (DUK__L0() == '\\') {
- duk_codepoint_t ch;
- if (DUK__L1() != 'u') {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid unicode escape in identifier");
- }
-
- ch = duk__decode_uniesc_from_window(lex_ctx, 2);
-
- /* IdentifierStart is stricter than IdentifierPart, so if the first
- * character is escaped, must have a stricter check here.
- */
- if (!(first ? duk_unicode_is_identifier_start(ch) : duk_unicode_is_identifier_part(ch))) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid unicode escape in identifier");
- }
- DUK__APPENDBUFFER(lex_ctx, ch);
- DUK__ADVANCECHARS(lex_ctx, 6);
-
- /* Track number of escapes: necessary for proper keyword
- * detection.
- */
- out_token->num_escapes++;
- } else {
- /* Note: first character is checked against this. But because
- * IdentifierPart includes all IdentifierStart characters, and
- * the first character (if unescaped) has already been checked
- * in the if condition, this is OK.
- */
- if (!duk_unicode_is_identifier_part(DUK__L0())) {
- break;
- }
- DUK__APPENDBUFFER(lex_ctx, DUK__L0());
- DUK__ADVANCECHARS(lex_ctx, 1);
- }
- first = 0;
- }
-
- duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
- out_token->str1 = duk_get_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
- str = out_token->str1;
- DUK_ASSERT(str != NULL);
- out_token->t_nores = DUK_TOK_IDENTIFIER;
-
- DUK__INITBUFFER(lex_ctx); /* free some memory */
-
- /*
- * Interned identifier is compared against reserved words, which are
- * currently interned into the heap context. See genbuiltins.py.
- *
- * Note that an escape in the identifier disables recognition of
- * keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to
- * identifier named "if"). This is not necessarily compliant,
- * see test-dec-escaped-char-in-keyword.js.
- *
- * Note: "get" and "set" are awkward. They are not officially
- * ReservedWords (and indeed e.g. "var set = 1;" is valid), and
- * must come out as DUK_TOK_IDENTIFIER. The compiler needs to
- * work around this a bit.
- */
-
- /* XXX: optimize by adding the token numbers directly into the
- * always interned duk_hstring objects (there should be enough
- * flag bits free for that)?
- */
-
- i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED);
-
- advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
- if (out_token->num_escapes == 0) {
- for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
- DUK_ASSERT(i >= 0 && i < DUK_HEAP_NUM_STRINGS);
- if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) {
- advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
- break;
- }
- }
- }
- } else if (DUK__ISDIGIT(x) || (x == '.')) {
- /* Note: decimal number may start with a period, but must be followed by a digit */
-
- /*
- * DecimalLiteral, HexIntegerLiteral, OctalIntegerLiteral
- * "pre-parsing", followed by an actual, accurate parser step.
- *
- * Note: the leading sign character ('+' or '-') is -not- part of
- * the production in E5 grammar, and that the a DecimalLiteral
- * starting with a '0' must be followed by a non-digit. Leading
- * zeroes are syntax errors and must be checked for.
- *
- * XXX: the two step parsing process is quite awkward, it would
- * be more straightforward to allow numconv to parse the longest
- * valid prefix (it already does that, it only needs to indicate
- * where the input ended). However, the lexer decodes characters
- * using a lookup window, so this is not a trivial change.
- */
-
- /* XXX: because of the final check below (that the literal is not
- * followed by a digit), this could maybe be simplified, if we bail
- * out early from a leading zero (and if there are no periods etc).
- * Maybe too complex.
- */
-
- duk_double_t val;
- duk_bool_t int_only = 0;
- duk_bool_t allow_hex = 0;
- duk_small_int_t state; /* 0=before period/exp,
- * 1=after period, before exp
- * 2=after exp, allow '+' or '-'
- * 3=after exp and exp sign
- */
- duk_small_uint_t s2n_flags;
- duk_codepoint_t y;
-
- DUK__INITBUFFER(lex_ctx);
- y = DUK__L1();
- if (x == '0' && (y == 'x' || y == 'X')) {
- DUK__APPENDBUFFER(lex_ctx, x);
- DUK__APPENDBUFFER(lex_ctx, y);
- DUK__ADVANCECHARS(lex_ctx, 2);
- int_only = 1;
- allow_hex = 1;
-#if defined(DUK_USE_OCTAL_SUPPORT)
- } else if (!strict_mode && x == '0' && DUK__ISDIGIT(y)) {
- /* Note: if DecimalLiteral starts with a '0', it can only be
- * followed by a period or an exponent indicator which starts
- * with 'e' or 'E'. Hence the if-check above ensures that
- * OctalIntegerLiteral is the only valid NumericLiteral
- * alternative at this point (even if y is, say, '9').
- */
-
- DUK__APPENDBUFFER(lex_ctx, x);
- DUK__ADVANCECHARS(lex_ctx, 1);
- int_only = 1;
-#endif
- }
-
- state = 0;
- for (;;) {
- x = DUK__L0(); /* re-lookup curr char on first round */
- if (DUK__ISDIGIT(x)) {
- /* Note: intentionally allow leading zeroes here, as the
- * actual parser will check for them.
- */
- if (state == 2) {
- state = 3;
- }
- } else if (allow_hex && DUK__ISHEXDIGIT(x)) {
- /* Note: 'e' and 'E' are also accepted here. */
- ;
- } else if (x == '.') {
- if (state >= 1 || int_only) {
- break;
- } else {
- state = 1;
- }
- } else if (x == 'e' || x == 'E') {
- if (state >= 2 || int_only) {
- break;
- } else {
- state = 2;
- }
- } else if (x == '-' || x == '+') {
- if (state != 2) {
- break;
- } else {
- state = 3;
- }
- } else {
- break;
- }
- DUK__APPENDBUFFER(lex_ctx, x);
- DUK__ADVANCECHARS(lex_ctx, 1);
- }
-
- /* XXX: better coercion */
- duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
-
- s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
- DUK_S2N_FLAG_ALLOW_FRAC |
- DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
- DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
-#if defined(DUK_USE_OCTAL_SUPPORT)
- (strict_mode ? 0 : DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) |
-#endif
- DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
-
- duk_dup((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
- duk_numconv_parse((duk_context *) lex_ctx->thr, 10 /*radix*/, s2n_flags);
- val = duk_to_number((duk_context *) lex_ctx->thr, -1);
- if (DUK_ISNAN(val)) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid numeric literal");
- }
- duk_replace((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
-
- DUK__INITBUFFER(lex_ctx); /* free some memory */
-
- /* Section 7.8.3 (note): NumericLiteral must be followed by something other than
- * IdentifierStart or DecimalDigit.
- */
-
- if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid numeric literal");
- }
-
- out_token->num = val;
- advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER);
- } else if (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) {
- DUK__ADVANCECHARS(lex_ctx, 1);
- goto restart;
- } else if (x < 0) {
- advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
- } else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid token");
- }
- skip_slow_path:
-
- /*
- * Shared exit path
- */
-
- DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
- out_token->t = advtok & 0xff;
- if (out_token->t_nores < 0) {
- out_token->t_nores = out_token->t;
- }
- out_token->lineterm = got_lineterm;
-
- /* Automatic semicolon insertion is allowed if a token is preceded
- * by line terminator(s), or terminates a statement list (right curly
- * or EOF).
- */
- if (got_lineterm || out_token->t == DUK_TOK_RCURLY || out_token->t == DUK_TOK_EOF) {
- out_token->allow_auto_semi = 1;
- } else {
- out_token->allow_auto_semi = 0;
- }
-}
-
-#if defined(DUK_USE_REGEXP_SUPPORT)
-
-/*
- * Parse a RegExp token. The grammar is described in E5 Section 15.10.
- * Terminal constructions (such as quantifiers) are parsed directly here.
- *
- * 0xffffffffU is used as a marker for "infinity" in quantifiers. Further,
- * DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that
- * will be accepted for a quantifier.
- */
-
-DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
- duk_small_int_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
- duk_codepoint_t x, y;
-
- if (++lex_ctx->token_count >= lex_ctx->token_limit) {
- DUK_ERROR_RANGE(lex_ctx->thr, "token limit");
- return; /* unreachable */
- }
-
- DUK_MEMZERO(out_token, sizeof(*out_token));
-
- x = DUK__L0();
- y = DUK__L1();
-
- DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld", (long) x, (long) y));
-
- switch (x) {
- case '|': {
- advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION);
- break;
- }
- case '^': {
- advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START);
- break;
- }
- case '$': {
- advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END);
- break;
- }
- case '?': {
- out_token->qmin = 0;
- out_token->qmax = 1;
- if (y == '?') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
- out_token->greedy = 0;
- } else {
- advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
- out_token->greedy = 1;
- }
- break;
- }
- case '*': {
- out_token->qmin = 0;
- out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
- if (y == '?') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
- out_token->greedy = 0;
- } else {
- advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
- out_token->greedy = 1;
- }
- break;
- }
- case '+': {
- out_token->qmin = 1;
- out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
- if (y == '?') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
- out_token->greedy = 0;
- } else {
- advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
- out_token->greedy = 1;
- }
- break;
- }
- case '{': {
- /* Production allows 'DecimalDigits', including leading zeroes */
- duk_uint_fast32_t val1 = 0;
- duk_uint_fast32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
- duk_small_int_t digits = 0;
-#if defined(DUK_USE_ES6_REGEXP_BRACES)
- duk_lexer_point lex_pt;
-#endif
-
-#if defined(DUK_USE_ES6_REGEXP_BRACES)
- /* Store lexer position, restoring if quantifier is invalid. */
- DUK_LEXER_GETPOINT(lex_ctx, &lex_pt);
-#endif
-
- for (;;) {
- DUK__ADVANCECHARS(lex_ctx, 1); /* eat '{' on entry */
- x = DUK__L0();
- if (DUK__ISDIGIT(x)) {
- digits++;
- val1 = val1 * 10 + (duk_uint_fast32_t) duk__hexval(lex_ctx, x);
- } else if (x == ',') {
- if (digits > DUK__MAX_RE_QUANT_DIGITS) {
- goto invalid_quantifier;
- }
- if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
- goto invalid_quantifier;
- }
- if (DUK__L1() == '}') {
- /* form: { DecimalDigits , }, val1 = min count */
- if (digits == 0) {
- goto invalid_quantifier;
- }
- out_token->qmin = val1;
- out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
- DUK__ADVANCECHARS(lex_ctx, 2);
- break;
- }
- val2 = val1;
- val1 = 0;
- digits = 0; /* not strictly necessary because of lookahead '}' above */
- } else if (x == '}') {
- if (digits > DUK__MAX_RE_QUANT_DIGITS) {
- goto invalid_quantifier;
- }
- if (digits == 0) {
- goto invalid_quantifier;
- }
- if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
- /* val2 = min count, val1 = max count */
- out_token->qmin = val2;
- out_token->qmax = val1;
- } else {
- /* val1 = count */
- out_token->qmin = val1;
- out_token->qmax = val1;
- }
- DUK__ADVANCECHARS(lex_ctx, 1);
- break;
- } else {
- goto invalid_quantifier;
- }
- }
- if (DUK__L0() == '?') {
- out_token->greedy = 0;
- DUK__ADVANCECHARS(lex_ctx, 1);
- } else {
- out_token->greedy = 1;
- }
- advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER);
- break;
- invalid_quantifier:
-#if defined(DUK_USE_ES6_REGEXP_BRACES)
- /* Failed to match the quantifier, restore lexer and parse
- * opening brace as a literal.
- */
- DUK_LEXER_SETPOINT(lex_ctx, &lex_pt);
- advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
- out_token->num = '{';
-#else
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp quantifier");
-#endif
- break;
- }
- case '.': {
- advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD);
- break;
- }
- case '\\': {
- /* The E5.1 specification does not seem to allow IdentifierPart characters
- * to be used as identity escapes. Unfortunately this includes '$', which
- * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'.
- * Many other implementations (including V8 and Rhino, for instance) do
- * accept '\$' as a valid identity escape, which is quite pragmatic.
- * See: test-regexp-identity-escape-dollar.js.
- */
-
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); /* default: char escape (two chars) */
- if (y == 'b') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY);
- } else if (y == 'B') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY);
- } else if (y == 'f') {
- out_token->num = 0x000c;
- } else if (y == 'n') {
- out_token->num = 0x000a;
- } else if (y == 't') {
- out_token->num = 0x0009;
- } else if (y == 'r') {
- out_token->num = 0x000d;
- } else if (y == 'v') {
- out_token->num = 0x000b;
- } else if (y == 'c') {
- x = DUK__L2();
- if ((x >= 'a' && x <= 'z') ||
- (x >= 'A' && x <= 'Z')) {
- out_token->num = (x % 32);
- advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
- } else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- }
- } else if (y == 'x') {
- out_token->num = duk__decode_hexesc_from_window(lex_ctx, 2);
- advtok = DUK__ADVTOK(4, DUK_RETOK_ATOM_CHAR);
- } else if (y == 'u') {
- out_token->num = duk__decode_uniesc_from_window(lex_ctx, 2);
- advtok = DUK__ADVTOK(6, DUK_RETOK_ATOM_CHAR);
- } else if (y == 'd') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
- } else if (y == 'D') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT);
- } else if (y == 's') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE);
- } else if (y == 'S') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE);
- } else if (y == 'w') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR);
- } else if (y == 'W') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR);
- } else if (DUK__ISDIGIT(y)) {
- /* E5 Section 15.10.2.11 */
- if (y == '0') {
- if (DUK__ISDIGIT(DUK__L2())) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- }
- out_token->num = 0x0000;
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
- } else {
- /* XXX: shared parsing? */
- duk_uint_fast32_t val = 0;
- duk_small_int_t i;
- for (i = 0; ; i++) {
- if (i >= DUK__MAX_RE_DECESC_DIGITS) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- }
- DUK__ADVANCECHARS(lex_ctx, 1); /* eat backslash on entry */
- x = DUK__L0();
- if (!DUK__ISDIGIT(x)) {
- break;
- }
- val = val * 10 + (duk_uint_fast32_t) duk__hexval(lex_ctx, x);
- }
- /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
- advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
- out_token->num = val;
- }
- } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) ||
-#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
- y == '$' ||
-#endif
- y == DUK_UNICODE_CP_ZWNJ ||
- y == DUK_UNICODE_CP_ZWJ) {
- /* IdentityEscape, with dollar added as a valid additional
- * non-standard escape (see test-regexp-identity-escape-dollar.js).
- * Careful not to match end-of-buffer (<0) here.
- */
- out_token->num = y;
- } else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- }
- break;
- }
- case '(': {
- /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */
-
- if (y == '?') {
- if (DUK__L2() == '=') {
- /* (?= */
- advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD);
- } else if (DUK__L2() == '!') {
- /* (?! */
- advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD);
- } else if (DUK__L2() == ':') {
- /* (?: */
- advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP);
- }
- } else {
- /* ( */
- advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP);
- }
- break;
- }
- case ')': {
- advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP);
- break;
- }
- case '[': {
- /*
- * To avoid creating a heavy intermediate value for the list of ranges,
- * only the start token ('[' or '[^') is parsed here. The regexp
- * compiler parses the ranges itself.
- */
- advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS);
- if (y == '^') {
- advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED);
- }
- break;
- }
-#if !defined(DUK_USE_ES6_REGEXP_BRACES)
- case '}':
-#endif
- case ']': {
- /* Although these could be parsed as PatternCharacters unambiguously (here),
- * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters.
- */
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp character");
- break;
- }
- case -1: {
- /* EOF */
- advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
- break;
- }
- default: {
- /* PatternCharacter, all excluded characters are matched by cases above */
- advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
- out_token->num = x;
- break;
- }
- }
-
- /*
- * Shared exit path
- */
-
- DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
- out_token->t = advtok & 0xff;
-}
-
-/*
- * Special parser for character classes; calls callback for every
- * range parsed and returns the number of ranges present.
- */
-
-/* XXX: this duplicates functionality in duk_regexp.c where a similar loop is
- * required anyway. We could use that BUT we need to update the regexp compiler
- * 'nranges' too. Work this out a bit more cleanly to save space.
- */
-
-/* XXX: the handling of character range detection is a bit convoluted.
- * Try to simplify and make smaller.
- */
-
-/* XXX: logic for handling character ranges is now incorrect, it will accept
- * e.g. [\d-z] whereas it should croak from it? SMJS accepts this too, though.
- *
- * Needs a read through and a lot of additional tests.
- */
-
-DUK_LOCAL
-void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx,
- duk_re_range_callback gen_range,
- void *userdata,
- const duk_uint16_t *ranges,
- duk_small_int_t num) {
- const duk_uint16_t *ranges_end;
-
- DUK_UNREF(lex_ctx);
-
- ranges_end = ranges + num;
- while (ranges < ranges_end) {
- /* mark range 'direct', bypass canonicalization (see Wiki) */
- gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1);
- ranges += 2;
- }
-}
-
-DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) {
- duk_codepoint_t start = -1;
- duk_codepoint_t ch;
- duk_codepoint_t x;
- duk_bool_t dash = 0;
-
- DUK_DD(DUK_DDPRINT("parsing regexp ranges"));
-
- for (;;) {
- x = DUK__L0();
- DUK__ADVANCECHARS(lex_ctx, 1);
-
- ch = -1; /* not strictly necessary, but avoids "uninitialized variable" warnings */
- DUK_UNREF(ch);
-
- if (x < 0) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "eof in character class");
- } else if (x == ']') {
- DUK_ASSERT(!dash); /* lookup should prevent this */
- if (start >= 0) {
- gen_range(userdata, start, start, 0);
- }
- break;
- } else if (x == '-') {
- if (start >= 0 && !dash && DUK__L0() != ']') {
- /* '-' as a range indicator */
- dash = 1;
- continue;
- } else {
- /* '-' verbatim */
- ch = x;
- }
- } else if (x == '\\') {
- /*
- * The escapes are same as outside a character class, except that \b has a
- * different meaning, and \B and backreferences are prohibited (see E5
- * Section 15.10.2.19). However, it's difficult to share code because we
- * handle e.g. "\n" very differently: here we generate a single character
- * range for it.
- */
-
- x = DUK__L0();
- DUK__ADVANCECHARS(lex_ctx, 1);
-
- if (x == 'b') {
- /* Note: '\b' in char class is different than outside (assertion),
- * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part()
- * check below.
- */
- ch = 0x0008;
- } else if (x == 'f') {
- ch = 0x000c;
- } else if (x == 'n') {
- ch = 0x000a;
- } else if (x == 't') {
- ch = 0x0009;
- } else if (x == 'r') {
- ch = 0x000d;
- } else if (x == 'v') {
- ch = 0x000b;
- } else if (x == 'c') {
- x = DUK__L0();
- DUK__ADVANCECHARS(lex_ctx, 1);
- if ((x >= 'a' && x <= 'z') ||
- (x >= 'A' && x <= 'Z')) {
- ch = (x % 32);
- } else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- return; /* never reached, but avoids warnings of
- * potentially unused variables.
- */
- }
- } else if (x == 'x') {
- ch = duk__decode_hexesc_from_window(lex_ctx, 0);
- DUK__ADVANCECHARS(lex_ctx, 2);
- } else if (x == 'u') {
- ch = duk__decode_uniesc_from_window(lex_ctx, 0);
- DUK__ADVANCECHARS(lex_ctx, 4);
- } else if (x == 'd') {
- duk__emit_u16_direct_ranges(lex_ctx,
- gen_range,
- userdata,
- duk_unicode_re_ranges_digit,
- sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
- ch = -1;
- } else if (x == 'D') {
- duk__emit_u16_direct_ranges(lex_ctx,
- gen_range,
- userdata,
- duk_unicode_re_ranges_not_digit,
- sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t));
- ch = -1;
- } else if (x == 's') {
- duk__emit_u16_direct_ranges(lex_ctx,
- gen_range,
- userdata,
- duk_unicode_re_ranges_white,
- sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
- ch = -1;
- } else if (x == 'S') {
- duk__emit_u16_direct_ranges(lex_ctx,
- gen_range,
- userdata,
- duk_unicode_re_ranges_not_white,
- sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t));
- ch = -1;
- } else if (x == 'w') {
- duk__emit_u16_direct_ranges(lex_ctx,
- gen_range,
- userdata,
- duk_unicode_re_ranges_wordchar,
- sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
- ch = -1;
- } else if (x == 'W') {
- duk__emit_u16_direct_ranges(lex_ctx,
- gen_range,
- userdata,
- duk_unicode_re_ranges_not_wordchar,
- sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t));
- ch = -1;
- } else if (DUK__ISDIGIT(x)) {
- /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */
- if (x == '0' && !DUK__ISDIGIT(DUK__L0())) {
- ch = 0x0000;
- } else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- }
- } else if (!duk_unicode_is_identifier_part(x)
-#if defined(DUK_USE_NONSTD_REGEXP_DOLLAR_ESCAPE)
- || x == '$'
-#endif
- ) {
- /* IdentityEscape */
- ch = x;
- } else {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid regexp escape");
- }
- } else {
- /* character represents itself */
- ch = x;
- }
-
- /* ch is a literal character here or -1 if parsed entity was
- * an escape such as "\s".
- */
-
- if (ch < 0) {
- /* multi-character sets not allowed as part of ranges, see
- * E5 Section 15.10.2.15, abstract operation CharacterRange.
- */
- if (start >= 0) {
- if (dash) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid range");
- } else {
- gen_range(userdata, start, start, 0);
- start = -1;
- /* dash is already 0 */
- }
- }
- } else {
- if (start >= 0) {
- if (dash) {
- if (start > ch) {
- DUK_ERROR_SYNTAX(lex_ctx->thr, "invalid range");
- }
- gen_range(userdata, start, ch, 0);
- start = -1;
- dash = 0;
- } else {
- gen_range(userdata, start, start, 0);
- start = ch;
- /* dash is already 0 */
- }
- } else {
- start = ch;
- }
- }
- }
-
- return;
-}
-
-#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_numconv.c"
-/*
- * Number-to-string and string-to-number conversions.
- *
- * Slow path number-to-string and string-to-number conversion is based on
- * a Dragon4 variant, with fast paths for small integers. Big integer
- * arithmetic is needed for guaranteeing that the conversion is correct
- * and uses a minimum number of digits. The big number arithmetic has a
- * fixed maximum size and does not require dynamic allocations.
- *
- * See: doc/number-conversion.rst.
- */
-
-/* include removed: duk_internal.h */
-
-#define DUK__IEEE_DOUBLE_EXP_BIAS 1023
-#define DUK__IEEE_DOUBLE_EXP_MIN (-1022) /* biased exp == 0 -> denormal, exp -1022 */
-
-#define DUK__DIGITCHAR(x) duk_lc_digits[(x)]
-
-/*
- * Tables generated with src/gennumdigits.py.
- *
- * duk__str2num_digits_for_radix indicates, for each radix, how many input
- * digits should be considered significant for string-to-number conversion.
- * The input is also padded to this many digits to give the Dragon4
- * conversion enough (apparent) precision to work with.
- *
- * duk__str2num_exp_limits indicates, for each radix, the radix-specific
- * minimum/maximum exponent values (for a Dragon4 integer mantissa)
- * below and above which the number is guaranteed to underflow to zero
- * or overflow to Infinity. This allows parsing to keep bigint values
- * bounded.
- */
-
-DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[] = {
- 69, 44, 35, 30, 27, 25, 23, 22, 20, 20, /* 2 to 11 */
- 20, 19, 19, 18, 18, 17, 17, 17, 16, 16, /* 12 to 21 */
- 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, /* 22 to 31 */
- 14, 14, 14, 14, 14 /* 31 to 36 */
-};
-
-typedef struct {
- duk_int16_t upper;
- duk_int16_t lower;
-} duk__exp_limits;
-
-DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = {
- { 957, -1147 }, { 605, -725 }, { 479, -575 }, { 414, -496 },
- { 372, -446 }, { 342, -411 }, { 321, -384 }, { 304, -364 },
- { 291, -346 }, { 279, -334 }, { 268, -323 }, { 260, -312 },
- { 252, -304 }, { 247, -296 }, { 240, -289 }, { 236, -283 },
- { 231, -278 }, { 227, -273 }, { 223, -267 }, { 220, -263 },
- { 216, -260 }, { 213, -256 }, { 210, -253 }, { 208, -249 },
- { 205, -246 }, { 203, -244 }, { 201, -241 }, { 198, -239 },
- { 196, -237 }, { 195, -234 }, { 193, -232 }, { 191, -230 },
- { 190, -228 }, { 188, -226 }, { 187, -225 },
-};
-
-/*
- * Limited functionality bigint implementation.
- *
- * Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits,
- * with the caller responsible for ensuring this is never exceeded. No memory
- * allocation (except stack) is needed for bigint computation. Operations
- * have been tailored for number conversion needs.
- *
- * Argument order is "assignment order", i.e. target first, then arguments:
- * x <- y * z --> duk__bi_mul(x, y, z);
- */
-
-/* This upper value has been experimentally determined; debug build will check
- * bigint size with assertions.
- */
-#define DUK__BI_MAX_PARTS 37 /* 37x32 = 1184 bits */
-
-#ifdef DUK_USE_DDDPRINT
-#define DUK__BI_PRINT(name,x) duk__bi_print((name),(x))
-#else
-#define DUK__BI_PRINT(name,x)
-#endif
-
-/* Current size is about 152 bytes. */
-typedef struct {
- duk_small_int_t n;
- duk_uint32_t v[DUK__BI_MAX_PARTS]; /* low to high */
-} duk__bigint;
-
-#ifdef DUK_USE_DDDPRINT
-DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) {
- /* Overestimate required size; debug code so not critical to be tight. */
- char buf[DUK__BI_MAX_PARTS * 9 + 64];
- char *p = buf;
- duk_small_int_t i;
-
- /* No NUL term checks in this debug code. */
- p += DUK_SPRINTF(p, "%p n=%ld", (void *) x, (long) x->n);
- if (x->n == 0) {
- p += DUK_SPRINTF(p, " 0");
- }
- for (i = x->n - 1; i >= 0; i--) {
- p += DUK_SPRINTF(p, " %08lx", (unsigned long) x->v[i]);
- }
-
- DUK_DDD(DUK_DDDPRINT("%s: %s", (const char *) name, (const char *) buf));
-}
-#endif
-
-#ifdef DUK_USE_ASSERTIONS
-DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) {
- return (duk_small_int_t)
- ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ &&
- ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ );
-}
-#endif
-
-DUK_LOCAL void duk__bi_normalize(duk__bigint *x) {
- duk_small_int_t i;
-
- for (i = x->n - 1; i >= 0; i--) {
- if (x->v[i] != 0) {
- break;
- }
- }
-
- /* Note: if 'x' is zero, x->n becomes 0 here */
- x->n = i + 1;
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-
-/* x <- y */
-DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
- duk_small_int_t n;
-
- n = y->n;
- x->n = n;
- if (n == 0) {
- return;
- }
- DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * n));
-}
-
-DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
- if (v == 0U) {
- x->n = 0;
- } else {
- x->n = 1;
- x->v[0] = v;
- }
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-
-/* Return value: <0 <=> x < y
- * 0 <=> x == y
- * >0 <=> x > y
- */
-DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) {
- duk_small_int_t i, nx, ny;
- duk_uint32_t tx, ty;
-
- DUK_ASSERT(duk__bi_is_valid(x));
- DUK_ASSERT(duk__bi_is_valid(y));
-
- nx = x->n;
- ny = y->n;
- if (nx > ny) {
- goto ret_gt;
- }
- if (nx < ny) {
- goto ret_lt;
- }
- for (i = nx - 1; i >= 0; i--) {
- tx = x->v[i];
- ty = y->v[i];
-
- if (tx > ty) {
- goto ret_gt;
- }
- if (tx < ty) {
- goto ret_lt;
- }
- }
-
- return 0;
-
- ret_gt:
- return 1;
-
- ret_lt:
- return -1;
-}
-
-/* x <- y + z */
-#ifdef DUK_USE_64BIT_OPS
-DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
- duk_uint64_t tmp;
- duk_small_int_t i, ny, nz;
-
- DUK_ASSERT(duk__bi_is_valid(y));
- DUK_ASSERT(duk__bi_is_valid(z));
-
- if (z->n > y->n) {
- duk__bigint *t;
- t = y; y = z; z = t;
- }
- DUK_ASSERT(y->n >= z->n);
-
- ny = y->n; nz = z->n;
- tmp = 0U;
- for (i = 0; i < ny; i++) {
- DUK_ASSERT(i < DUK__BI_MAX_PARTS);
- tmp += y->v[i];
- if (i < nz) {
- tmp += z->v[i];
- }
- x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
- tmp = tmp >> 32;
- }
- if (tmp != 0U) {
- DUK_ASSERT(i < DUK__BI_MAX_PARTS);
- x->v[i++] = (duk_uint32_t) tmp;
- }
- x->n = i;
- DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
-
- /* no need to normalize */
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-#else /* DUK_USE_64BIT_OPS */
-DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
- duk_uint32_t carry, tmp1, tmp2;
- duk_small_int_t i, ny, nz;
-
- DUK_ASSERT(duk__bi_is_valid(y));
- DUK_ASSERT(duk__bi_is_valid(z));
-
- if (z->n > y->n) {
- duk__bigint *t;
- t = y; y = z; z = t;
- }
- DUK_ASSERT(y->n >= z->n);
-
- ny = y->n; nz = z->n;
- carry = 0U;
- for (i = 0; i < ny; i++) {
- /* Carry is detected based on wrapping which relies on exact 32-bit
- * types.
- */
- DUK_ASSERT(i < DUK__BI_MAX_PARTS);
- tmp1 = y->v[i];
- tmp2 = tmp1;
- if (i < nz) {
- tmp2 += z->v[i];
- }
-
- /* Careful with carry condition:
- * - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678)
- * - If carry added: 0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678)
- */
- if (carry) {
- tmp2++;
- carry = (tmp2 <= tmp1 ? 1U : 0U);
- } else {
- carry = (tmp2 < tmp1 ? 1U : 0U);
- }
-
- x->v[i] = tmp2;
- }
- if (carry) {
- DUK_ASSERT(i < DUK__BI_MAX_PARTS);
- DUK_ASSERT(carry == 1U);
- x->v[i++] = carry;
- }
- x->n = i;
- DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
-
- /* no need to normalize */
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-#endif /* DUK_USE_64BIT_OPS */
-
-/* x <- y + z */
-DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
- duk__bigint tmp;
-
- DUK_ASSERT(duk__bi_is_valid(y));
-
- /* XXX: this could be optimized; there is only one call site now though */
- duk__bi_set_small(&tmp, z);
- duk__bi_add(x, y, &tmp);
-
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-
-#if 0 /* unused */
-/* x <- x + y, use t as temp */
-DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
- duk__bi_add(t, x, y);
- duk__bi_copy(x, t);
-}
-#endif
-
-/* x <- y - z, require x >= y => z >= 0, i.e. y >= z */
-#ifdef DUK_USE_64BIT_OPS
-DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
- duk_small_int_t i, ny, nz;
- duk_uint32_t ty, tz;
- duk_int64_t tmp;
-
- DUK_ASSERT(duk__bi_is_valid(y));
- DUK_ASSERT(duk__bi_is_valid(z));
- DUK_ASSERT(duk__bi_compare(y, z) >= 0);
- DUK_ASSERT(y->n >= z->n);
-
- ny = y->n; nz = z->n;
- tmp = 0;
- for (i = 0; i < ny; i++) {
- ty = y->v[i];
- if (i < nz) {
- tz = z->v[i];
- } else {
- tz = 0;
- }
- tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp;
- x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
- tmp = tmp >> 32; /* 0 or -1 */
- }
- DUK_ASSERT(tmp == 0);
-
- x->n = i;
- duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-#else
-DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
- duk_small_int_t i, ny, nz;
- duk_uint32_t tmp1, tmp2, borrow;
-
- DUK_ASSERT(duk__bi_is_valid(y));
- DUK_ASSERT(duk__bi_is_valid(z));
- DUK_ASSERT(duk__bi_compare(y, z) >= 0);
- DUK_ASSERT(y->n >= z->n);
-
- ny = y->n; nz = z->n;
- borrow = 0U;
- for (i = 0; i < ny; i++) {
- /* Borrow is detected based on wrapping which relies on exact 32-bit
- * types.
- */
- tmp1 = y->v[i];
- tmp2 = tmp1;
- if (i < nz) {
- tmp2 -= z->v[i];
- }
-
- /* Careful with borrow condition:
- * - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678)
- * - If borrow subtracted: 0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678)
- */
- if (borrow) {
- tmp2--;
- borrow = (tmp2 >= tmp1 ? 1U : 0U);
- } else {
- borrow = (tmp2 > tmp1 ? 1U : 0U);
- }
-
- x->v[i] = tmp2;
- }
- DUK_ASSERT(borrow == 0U);
-
- x->n = i;
- duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-#endif
-
-#if 0 /* unused */
-/* x <- y - z */
-DUK_LOCAL void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
- duk__bigint tmp;
-
- DUK_ASSERT(duk__bi_is_valid(y));
-
- /* XXX: this could be optimized */
- duk__bi_set_small(&tmp, z);
- duk__bi_sub(x, y, &tmp);
-
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-#endif
-
-/* x <- x - y, use t as temp */
-DUK_LOCAL void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
- duk__bi_sub(t, x, y);
- duk__bi_copy(x, t);
-}
-
-/* x <- y * z */
-DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
- duk_small_int_t i, j, nx, nz;
-
- DUK_ASSERT(duk__bi_is_valid(y));
- DUK_ASSERT(duk__bi_is_valid(z));
-
- nx = y->n + z->n; /* max possible */
- DUK_ASSERT(nx <= DUK__BI_MAX_PARTS);
-
- if (nx == 0) {
- /* Both inputs are zero; cases where only one is zero can go
- * through main algorithm.
- */
- x->n = 0;
- return;
- }
-
- DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * nx));
- x->n = nx;
-
- nz = z->n;
- for (i = 0; i < y->n; i++) {
-#ifdef DUK_USE_64BIT_OPS
- duk_uint64_t tmp = 0U;
- for (j = 0; j < nz; j++) {
- tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j];
- x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL);
- tmp = tmp >> 32;
- }
- if (tmp > 0) {
- DUK_ASSERT(i + j < nx);
- DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
- DUK_ASSERT(x->v[i+j] == 0U);
- x->v[i+j] = (duk_uint32_t) tmp;
- }
-#else
- /*
- * Multiply + add + carry for 32-bit components using only 16x16->32
- * multiplies and carry detection based on unsigned overflow.
- *
- * 1st mult, 32-bit: (A*2^16 + B)
- * 2nd mult, 32-bit: (C*2^16 + D)
- * 3rd add, 32-bit: E
- * 4th add, 32-bit: F
- *
- * (AC*2^16 + B) * (C*2^16 + D) + E + F
- * = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F
- * = AC*2^32 + (AD + BC)*2^16 + (BD + E + F)
- * = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F)
- */
- duk_uint32_t a, b, c, d, e, f;
- duk_uint32_t r, s, t;
-
- a = y->v[i]; b = a & 0xffffUL; a = a >> 16;
-
- f = 0;
- for (j = 0; j < nz; j++) {
- c = z->v[j]; d = c & 0xffffUL; c = c >> 16;
- e = x->v[i+j];
-
- /* build result as: (r << 32) + s: start with (BD + E + F) */
- r = 0;
- s = b * d;
-
- /* add E */
- t = s + e;
- if (t < s) { r++; } /* carry */
- s = t;
-
- /* add F */
- t = s + f;
- if (t < s) { r++; } /* carry */
- s = t;
-
- /* add BC*2^16 */
- t = b * c;
- r += (t >> 16);
- t = s + ((t & 0xffffUL) << 16);
- if (t < s) { r++; } /* carry */
- s = t;
-
- /* add AD*2^16 */
- t = a * d;
- r += (t >> 16);
- t = s + ((t & 0xffffUL) << 16);
- if (t < s) { r++; } /* carry */
- s = t;
-
- /* add AC*2^32 */
- t = a * c;
- r += t;
-
- DUK_DDD(DUK_DDDPRINT("ab=%08lx cd=%08lx ef=%08lx -> rs=%08lx %08lx",
- (unsigned long) y->v[i], (unsigned long) z->v[j],
- (unsigned long) x->v[i+j], (unsigned long) r,
- (unsigned long) s));
-
- x->v[i+j] = s;
- f = r;
- }
- if (f > 0U) {
- DUK_ASSERT(i + j < nx);
- DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
- DUK_ASSERT(x->v[i+j] == 0U);
- x->v[i+j] = (duk_uint32_t) f;
- }
-#endif /* DUK_USE_64BIT_OPS */
- }
-
- duk__bi_normalize(x);
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-
-/* x <- y * z */
-DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
- duk__bigint tmp;
-
- DUK_ASSERT(duk__bi_is_valid(y));
-
- /* XXX: this could be optimized */
- duk__bi_set_small(&tmp, z);
- duk__bi_mul(x, y, &tmp);
-
- DUK_ASSERT(duk__bi_is_valid(x));
-}
-
-/* x <- x * y, use t as temp */
-DUK_LOCAL void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
- duk__bi_mul(t, x, y);
- duk__bi_copy(x, t);
-}
-
-/* x <- x * y, use t as temp */
-DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) {
- duk__bi_mul_small(t, x, y);
- duk__bi_copy(x, t);
-}
-
-DUK_LOCAL int duk__bi_is_even(duk__bigint *x) {
- DUK_ASSERT(duk__bi_is_valid(x));
- return (x->n == 0) || ((x->v[0] & 0x01) == 0);
-}
-
-DUK_LOCAL int duk__bi_is_zero(duk__bigint *x) {
- DUK_ASSERT(duk__bi_is_valid(x));
- return (x->n == 0); /* this is the case for normalized numbers */
-}
-
-/* Bigint is 2^52. Used to detect normalized IEEE double mantissa values
- * which are at the lowest edge (next floating point value downwards has
- * a different exponent). The lowest mantissa has the form:
- *
- * 1000........000 (52 zeroes; only "hidden bit" is set)
- */
-DUK_LOCAL duk_small_int_t duk__bi_is_2to52(duk__bigint *x) {
- DUK_ASSERT(duk__bi_is_valid(x));
- return (duk_small_int_t)
- (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32)));
-}
-
-/* x <- (1<<y) */
-DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
- duk_small_int_t n, r;
-
- n = (y / 32) + 1;
- DUK_ASSERT(n > 0);
- r = y % 32;
- DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * n);
- x->n = n;
- x->v[n - 1] = (((duk_uint32_t) 1) << r);
-}
-
-/* x <- b^y; use t1 and t2 as temps */
-DUK_LOCAL void duk__bi_exp_small(duk__bigint *x, duk_small_int_t b, duk_small_int_t y, duk__bigint *t1, duk__bigint *t2) {
- /* Fast path the binary case */
-
- DUK_ASSERT(x != t1 && x != t2 && t1 != t2); /* distinct bignums, easy mistake to make */
- DUK_ASSERT(b >= 0);
- DUK_ASSERT(y >= 0);
-
- if (b == 2) {
- duk__bi_twoexp(x, y);
- return;
- }
-
- /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */
-
- DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y));
-
- duk__bi_set_small(x, 1);
- duk__bi_set_small(t1, b);
- for (;;) {
- /* Loop structure ensures that we don't compute t1^2 unnecessarily
- * on the final round, as that might create a bignum exceeding the
- * current DUK__BI_MAX_PARTS limit.
- */
- if (y & 0x01) {
- duk__bi_mul_copy(x, t1, t2);
- }
- y = y >> 1;
- if (y == 0) {
- break;
- }
- duk__bi_mul_copy(t1, t1, t2);
- }
-
- DUK__BI_PRINT("exp_small result", x);
-}
-
-/*
- * A Dragon4 number-to-string variant, based on:
- *
- * Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers
- * Accurately"
- *
- * Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers
- * Quickly and Accurately"
- *
- * The current algorithm is based on Figure 1 of the Burger-Dybvig paper,
- * i.e. the base implementation without logarithm estimation speedups
- * (these would increase code footprint considerably). Fixed-format output
- * does not follow the suggestions in the paper; instead, we generate an
- * extra digit and round-with-carry.
- *
- * The same algorithm is used for number parsing (with b=10 and B=2)
- * by generating one extra digit and doing rounding manually.
- *
- * See doc/number-conversion.rst for limitations.
- */
-
-/* Maximum number of digits generated. */
-#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + spare */
-
-/* Maximum number of characters in formatted value. */
-#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + spare */
-
-/* Number and (minimum) size of bigints in the nc_ctx structure. */
-#define DUK__NUMCONV_CTX_NUM_BIGINTS 7
-#define DUK__NUMCONV_CTX_BIGINTS_SIZE (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS)
-
-typedef struct {
- /* Currently about 7*152 = 1064 bytes. The space for these
- * duk__bigints is used also as a temporary buffer for generating
- * the final string. This is a bit awkard; a union would be
- * more correct.
- */
- duk__bigint f, r, s, mp, mm, t1, t2;
-
- duk_small_int_t is_s2n; /* if 1, doing a string-to-number; else doing a number-to-string */
- duk_small_int_t is_fixed; /* if 1, doing a fixed format output (not free format) */
- duk_small_int_t req_digits; /* requested number of output digits; 0 = free-format */
- duk_small_int_t abs_pos; /* digit position is absolute, not relative */
- duk_small_int_t e; /* exponent for 'f' */
- duk_small_int_t b; /* input radix */
- duk_small_int_t B; /* output radix */
- duk_small_int_t k; /* see algorithm */
- duk_small_int_t low_ok; /* see algorithm */
- duk_small_int_t high_ok; /* see algorithm */
- duk_small_int_t unequal_gaps; /* m+ != m- (very rarely) */
-
- /* Buffer used for generated digits, values are in the range [0,B-1]. */
- duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS];
- duk_small_int_t count; /* digit count */
-} duk__numconv_stringify_ctx;
-
-/* Note: computes with 'idx' in assertions, so caller beware.
- * 'idx' is preincremented, i.e. '1' on first call, because it
- * is more convenient for the caller.
- */
-#define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x) do { \
- DUK_ASSERT((preinc_idx) - 1 >= 0); \
- DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \
- ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \
- } while (0)
-
-DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) {
- duk_uint8_t *p;
- duk_size_t len;
- duk_small_int_t dig;
- duk_small_int_t t;
-
- DUK_ASSERT(radix >= 2 && radix <= 36);
-
- /* A 32-bit unsigned integer formats to at most 32 digits (the
- * worst case happens with radix == 2). Output the digits backwards,
- * and use a memmove() to get them in the right place.
- */
-
- p = buf + 32;
- for (;;) {
- t = x / radix;
- dig = x - t * radix;
- x = t;
-
- DUK_ASSERT(dig >= 0 && dig < 36);
- *(--p) = DUK__DIGITCHAR(dig);
-
- if (x == 0) {
- break;
- }
- }
- len = (duk_size_t) ((buf + 32) - p);
-
- DUK_MEMMOVE((void *) buf, (const void *) p, (size_t) len);
-
- return len;
-}
-
-DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
- duk_small_int_t lowest_mantissa;
-
-#if 1
- /* Assume IEEE round-to-even, so that shorter encoding can be used
- * when round-to-even would produce correct result. By removing
- * this check (and having low_ok == high_ok == 0) the results would
- * still be accurate but in some cases longer than necessary.
- */
- if (duk__bi_is_even(&nc_ctx->f)) {
- DUK_DDD(DUK_DDDPRINT("f is even"));
- nc_ctx->low_ok = 1;
- nc_ctx->high_ok = 1;
- } else {
- DUK_DDD(DUK_DDDPRINT("f is odd"));
- nc_ctx->low_ok = 0;
- nc_ctx->high_ok = 0;
- }
-#else
- /* Note: not honoring round-to-even should work but now generates incorrect
- * results. For instance, 1e23 serializes to "a000...", i.e. the first digit
- * equals the radix (10). Scaling stops one step too early in this case.
- * Don't know why this is the case, but since this code path is unused, it
- * doesn't matter.
- */
- nc_ctx->low_ok = 0;
- nc_ctx->high_ok = 0;
-#endif
-
- /* For string-to-number, pretend we never have the lowest mantissa as there
- * is no natural "precision" for inputs. Having lowest_mantissa == 0, we'll
- * fall into the base cases for both e >= 0 and e < 0.
- */
- if (nc_ctx->is_s2n) {
- lowest_mantissa = 0;
- } else {
- lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f);
- }
-
- nc_ctx->unequal_gaps = 0;
- if (nc_ctx->e >= 0) {
- /* exponent non-negative (and thus not minimum exponent) */
-
- if (lowest_mantissa) {
- /* (>= e 0) AND (= f (expt b (- p 1)))
- *
- * be <- (expt b e) == b^e
- * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1)
- * r <- (* f be1 2) == 2 * f * b^(e+1) [if b==2 -> f * b^(e+2)]
- * s <- (* b 2) [if b==2 -> 4]
- * m+ <- be1 == b^(e+1)
- * m- <- be == b^e
- * k <- 0
- * B <- B
- * low_ok <- round
- * high_ok <- round
- */
-
- DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
- "lowest mantissa value for this exponent -> "
- "unequal gaps"));
-
- duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
- duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, nc_ctx->b); /* mp <- b^(e+1) */
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
- duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
- duk__bi_set_small(&nc_ctx->s, nc_ctx->b * 2); /* s <- 2 * b */
- nc_ctx->unequal_gaps = 1;
- } else {
- /* (>= e 0) AND (not (= f (expt b (- p 1))))
- *
- * be <- (expt b e) == b^e
- * r <- (* f be 2) == 2 * f * b^e [if b==2 -> f * b^(e+1)]
- * s <- 2
- * m+ <- be == b^e
- * m- <- be == b^e
- * k <- 0
- * B <- B
- * low_ok <- round
- * high_ok <- round
- */
-
- DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
- "not lowest mantissa for this exponent -> "
- "equal gaps"));
-
- duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
- duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm); /* mp <- b^e */
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
- duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^e */
- duk__bi_set_small(&nc_ctx->s, 2); /* s <- 2 */
- }
- } else {
- /* When doing string-to-number, lowest_mantissa is always 0 so
- * the exponent check, while incorrect, won't matter.
- */
- if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ &&
- lowest_mantissa /* lowest mantissa for this exponent*/) {
- /* r <- (* f b 2) [if b==2 -> (* f 4)]
- * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2 [if b==2 -> b^(2-e)]
- * m+ <- b == 2
- * m- <- 1
- * k <- 0
- * B <- B
- * low_ok <- round
- * high_ok <- round
- */
-
- DUK_DDD(DUK_DDDPRINT("negative exponent; not minimum exponent and "
- "lowest mantissa for this exponent -> "
- "unequal gaps"));
-
- duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, nc_ctx->b * 2); /* r <- (2 * b) * f */
- duk__bi_exp_small(&nc_ctx->t1, nc_ctx->b, 1 - nc_ctx->e, &nc_ctx->s, &nc_ctx->t2); /* NB: use 's' as temp on purpose */
- duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */
- duk__bi_set_small(&nc_ctx->mp, 2);
- duk__bi_set_small(&nc_ctx->mm, 1);
- nc_ctx->unequal_gaps = 1;
- } else {
- /* r <- (* f 2)
- * s <- (* (expt b (- e)) 2) == b^(-e) * 2 [if b==2 -> b^(1-e)]
- * m+ <- 1
- * m- <- 1
- * k <- 0
- * B <- B
- * low_ok <- round
- * high_ok <- round
- */
-
- DUK_DDD(DUK_DDDPRINT("negative exponent; minimum exponent or not "
- "lowest mantissa for this exponent -> "
- "equal gaps"));
-
- duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2); /* r <- 2 * f */
- duk__bi_exp_small(&nc_ctx->t1, nc_ctx->b, -nc_ctx->e, &nc_ctx->s, &nc_ctx->t2); /* NB: use 's' as temp on purpose */
- duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(-e) * 2 */
- duk__bi_set_small(&nc_ctx->mp, 1);
- duk__bi_set_small(&nc_ctx->mm, 1);
- }
- }
-}
-
-DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
- duk_small_int_t k = 0;
-
- /* This is essentially the 'scale' algorithm, with recursion removed.
- * Note that 'k' is either correct immediately, or will move in one
- * direction in the loop. There's no need to do the low/high checks
- * on every round (like the Scheme algorithm does).
- *
- * The scheme algorithm finds 'k' and updates 's' simultaneously,
- * while the logical algorithm finds 'k' with 's' having its initial
- * value, after which 's' is updated separately (see the Burger-Dybvig
- * paper, Section 3.1, steps 2 and 3).
- *
- * The case where m+ == m- (almost always) is optimized for, because
- * it reduces the bigint operations considerably and almost always
- * applies. The scale loop only needs to work with m+, so this works.
- */
-
- /* XXX: this algorithm could be optimized quite a lot by using e.g.
- * a logarithm based estimator for 'k' and performing B^n multiplication
- * using a lookup table or using some bit-representation based exp
- * algorithm. Currently we just loop, with significant performance
- * impact for very large and very small numbers.
- */
-
- DUK_DDD(DUK_DDDPRINT("scale: B=%ld, low_ok=%ld, high_ok=%ld",
- (long) nc_ctx->B, (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
- DUK__BI_PRINT("r(init)", &nc_ctx->r);
- DUK__BI_PRINT("s(init)", &nc_ctx->s);
- DUK__BI_PRINT("mp(init)", &nc_ctx->mp);
- DUK__BI_PRINT("mm(init)", &nc_ctx->mm);
-
- for (;;) {
- DUK_DDD(DUK_DDDPRINT("scale loop (inc k), k=%ld", (long) k));
- DUK__BI_PRINT("r", &nc_ctx->r);
- DUK__BI_PRINT("s", &nc_ctx->s);
- DUK__BI_PRINT("m+", &nc_ctx->mp);
- DUK__BI_PRINT("m-", &nc_ctx->mm);
-
- duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
- if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) {
- DUK_DDD(DUK_DDDPRINT("k is too low"));
- /* r <- r
- * s <- (* s B)
- * m+ <- m+
- * m- <- m-
- * k <- (+ k 1)
- */
-
- duk__bi_mul_small_copy(&nc_ctx->s, nc_ctx->B, &nc_ctx->t1);
- k++;
- } else {
- break;
- }
- }
-
- /* k > 0 -> k was too low, and cannot be too high */
- if (k > 0) {
- goto skip_dec_k;
- }
-
- for (;;) {
- DUK_DDD(DUK_DDDPRINT("scale loop (dec k), k=%ld", (long) k));
- DUK__BI_PRINT("r", &nc_ctx->r);
- DUK__BI_PRINT("s", &nc_ctx->s);
- DUK__BI_PRINT("m+", &nc_ctx->mp);
- DUK__BI_PRINT("m-", &nc_ctx->mm);
-
- duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
- duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, nc_ctx->B); /* t2 = (* (+ r m+) B) */
- if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
- DUK_DDD(DUK_DDDPRINT("k is too high"));
- /* r <- (* r B)
- * s <- s
- * m+ <- (* m+ B)
- * m- <- (* m- B)
- * k <- (- k 1)
- */
- duk__bi_mul_small_copy(&nc_ctx->r, nc_ctx->B, &nc_ctx->t1);
- duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t1);
- if (nc_ctx->unequal_gaps) {
- DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too"));
- duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t1);
- }
- k--;
- } else {
- break;
- }
- }
-
- skip_dec_k:
-
- if (!nc_ctx->unequal_gaps) {
- DUK_DDD(DUK_DDDPRINT("equal gaps, copy m- from m+"));
- duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp); /* mm <- mp */
- }
- nc_ctx->k = k;
-
- DUK_DDD(DUK_DDDPRINT("final k: %ld", (long) k));
- DUK__BI_PRINT("r(final)", &nc_ctx->r);
- DUK__BI_PRINT("s(final)", &nc_ctx->s);
- DUK__BI_PRINT("mp(final)", &nc_ctx->mp);
- DUK__BI_PRINT("mm(final)", &nc_ctx->mm);
-}
-
-DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
- duk_small_int_t tc1, tc2; /* terminating conditions */
- duk_small_int_t d; /* current digit */
- duk_small_int_t count = 0; /* digit count */
-
- /*
- * Digit generation loop.
- *
- * Different termination conditions:
- *
- * 1. Free format output. Terminate when shortest accurate
- * representation found.
- *
- * 2. Fixed format output, with specific number of digits.
- * Ignore termination conditions, terminate when digits
- * generated. Caller requests an extra digit and rounds.
- *
- * 3. Fixed format output, with a specific absolute cut-off
- * position (e.g. 10 digits after decimal point). Note
- * that we always generate at least one digit, even if
- * the digit is below the cut-off point already.
- */
-
- for (;;) {
- DUK_DDD(DUK_DDDPRINT("generate loop, count=%ld, k=%ld, B=%ld, low_ok=%ld, high_ok=%ld",
- (long) count, (long) nc_ctx->k, (long) nc_ctx->B,
- (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
- DUK__BI_PRINT("r", &nc_ctx->r);
- DUK__BI_PRINT("s", &nc_ctx->s);
- DUK__BI_PRINT("m+", &nc_ctx->mp);
- DUK__BI_PRINT("m-", &nc_ctx->mm);
-
- /* (quotient-remainder (* r B) s) using a dummy subtraction loop */
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, nc_ctx->B); /* t1 <- (* r B) */
- d = 0;
- for (;;) {
- if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
- break;
- }
- duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2); /* t1 <- t1 - s */
- d++;
- }
- duk__bi_copy(&nc_ctx->r, &nc_ctx->t1); /* r <- (remainder (* r B) s) */
- /* d <- (quotient (* r B) s) (in range 0...B-1) */
- DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d));
- DUK__BI_PRINT("r(rem)", &nc_ctx->r);
-
- duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
- duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
- DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
- DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
-
- /* Terminating conditions. For fixed width output, we just ignore the
- * terminating conditions (and pretend that tc1 == tc2 == false). The
- * the current shortcut for fixed-format output is to generate a few
- * extra digits and use rounding (with carry) to finish the output.
- */
-
- if (nc_ctx->is_fixed == 0) {
- /* free-form */
- tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1));
-
- duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 <- (+ r m+) */
- tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1));
-
- DUK_DDD(DUK_DDDPRINT("tc1=%ld, tc2=%ld", (long) tc1, (long) tc2));
- } else {
- /* fixed-format */
- tc1 = 0;
- tc2 = 0;
- }
-
- /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call
- * on purpose, which is taken into account by the macro.
- */
- count++;
-
- if (tc1) {
- if (tc2) {
- /* tc1 = true, tc2 = true */
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2);
- if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { /* (< (* r 2) s) */
- DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %ld (k=%ld)",
- (long) d, (long) nc_ctx->k));
- DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
- } else {
- DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %ld (k=%ld)",
- (long) (d + 1), (long) nc_ctx->k));
- DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
- }
- break;
- } else {
- /* tc1 = true, tc2 = false */
- DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=false: output d --> %ld (k=%ld)",
- (long) d, (long) nc_ctx->k));
- DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
- break;
- }
- } else {
- if (tc2) {
- /* tc1 = false, tc2 = true */
- DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %ld (k=%ld)",
- (long) (d + 1), (long) nc_ctx->k));
- DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
- break;
- } else {
- /* tc1 = false, tc2 = false */
- DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=false: output d --> %ld (k=%ld)",
- (long) d, (long) nc_ctx->k));
- DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
-
- /* r <- r (updated above: r <- (remainder (* r B) s)
- * s <- s
- * m+ <- m+ (updated above: m+ <- (* m+ B)
- * m- <- m- (updated above: m- <- (* m- B)
- * B, low_ok, high_ok are fixed
- */
-
- /* fall through and continue for-loop */
- }
- }
-
- /* fixed-format termination conditions */
- if (nc_ctx->is_fixed) {
- if (nc_ctx->abs_pos) {
- int pos = nc_ctx->k - count + 1; /* count is already incremented, take into account */
- DUK_DDD(DUK_DDDPRINT("fixed format, absolute: abs pos=%ld, k=%ld, count=%ld, req=%ld",
- (long) pos, (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
- if (pos <= nc_ctx->req_digits) {
- DUK_DDD(DUK_DDDPRINT("digit position reached req_digits, end generate loop"));
- break;
- }
- } else {
- DUK_DDD(DUK_DDDPRINT("fixed format, relative: k=%ld, count=%ld, req=%ld",
- (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
- if (count >= nc_ctx->req_digits) {
- DUK_DDD(DUK_DDDPRINT("digit count reached req_digits, end generate loop"));
- break;
- }
- }
- }
- } /* for */
-
- nc_ctx->count = count;
-
- DUK_DDD(DUK_DDDPRINT("generate finished"));
-
-#ifdef DUK_USE_DDDPRINT
- {
- duk_uint8_t buf[2048];
- duk_small_int_t i, t;
- DUK_MEMZERO(buf, sizeof(buf));
- for (i = 0; i < nc_ctx->count; i++) {
- t = nc_ctx->digits[i];
- if (t < 0 || t > 36) {
- buf[i] = (duk_uint8_t) '?';
- } else {
- buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t);
- }
- }
- DUK_DDD(DUK_DDDPRINT("-> generated digits; k=%ld, digits='%s'",
- (long) nc_ctx->k, (const char *) buf));
- }
-#endif
-}
-
-/* Round up digits to a given position. If position is out-of-bounds,
- * does nothing. If carry propagates over the first digit, a '1' is
- * prepended to digits and 'k' will be updated. Return value indicates
- * whether carry propagated over the first digit.
- *
- * Note that nc_ctx->count is NOT updated based on the rounding position
- * (it is updated only if carry overflows over the first digit and an
- * extra digit is prepended).
- */
-DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) {
- duk_small_int_t t;
- duk_uint8_t *p;
- duk_uint8_t roundup_limit;
- duk_small_int_t ret = 0;
-
- /*
- * round_idx points to the digit which is considered for rounding; the
- * digit to its left is the final digit of the rounded value. If round_idx
- * is zero, rounding will be performed; the result will either be an empty
- * rounded value or if carry happens a '1' digit is generated.
- */
-
- if (round_idx >= nc_ctx->count) {
- DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld >= %ld (count)) -> no rounding",
- (long) round_idx, (long) nc_ctx->count));
- return 0;
- } else if (round_idx < 0) {
- DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld < 0) -> no rounding",
- (long) round_idx));
- return 0;
- }
-
- /*
- * Round-up limit.
- *
- * For even values, divides evenly, e.g. 10 -> roundup_limit=5.
- *
- * For odd values, rounds up, e.g. 3 -> roundup_limit=2.
- * If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up.
- */
- roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2);
-
- p = &nc_ctx->digits[round_idx];
- if (*p >= roundup_limit) {
- DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry required"));
- /* carry */
- for (;;) {
- *p = 0;
- if (p == &nc_ctx->digits[0]) {
- DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
- DUK_MEMMOVE((void *) (&nc_ctx->digits[1]),
- (const void *) (&nc_ctx->digits[0]),
- (size_t) (sizeof(char) * nc_ctx->count));
- nc_ctx->digits[0] = 1; /* don't increase 'count' */
- nc_ctx->k++; /* position of highest digit changed */
- nc_ctx->count++; /* number of digits changed */
- ret = 1;
- break;
- }
-
- DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry: B=%ld, roundup_limit=%ld, p=%p, digits=%p",
- (long) nc_ctx->B, (long) roundup_limit, (void *) p, (void *) nc_ctx->digits));
- p--;
- t = *p;
- DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
- if (++t < nc_ctx->B) {
- DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
- *p = (duk_uint8_t) t;
- break;
- }
-
- DUK_DDD(DUK_DDDPRINT("wraps, carry to next digit"));
- }
- }
-
- return ret;
-}
-
-#define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */
-
-DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
- duk_context *ctx,
- duk_small_int_t radix,
- duk_small_int_t digits,
- duk_small_uint_t flags,
- duk_small_int_t neg) {
- duk_small_int_t k;
- duk_small_int_t pos, pos_end;
- duk_small_int_t expt;
- duk_small_int_t dig;
- duk_uint8_t *q;
- duk_uint8_t *buf;
-
- /*
- * The string conversion here incorporates all the necessary Ecmascript
- * semantics without attempting to be generic. nc_ctx->digits contains
- * nc_ctx->count digits (>= 1), with the topmost digit's 'position'
- * indicated by nc_ctx->k as follows:
- *
- * digits="123" count=3 k=0 --> 0.123
- * digits="123" count=3 k=1 --> 1.23
- * digits="123" count=3 k=5 --> 12300
- * digits="123" count=3 k=-1 --> 0.0123
- *
- * Note that the identifier names used for format selection are different
- * in Burger-Dybvig paper and Ecmascript specification (quite confusingly
- * so, because e.g. 'k' has a totally different meaning in each). See
- * documentation for discussion.
- *
- * Ecmascript doesn't specify any specific behavior for format selection
- * (e.g. when to use exponent notation) for non-base-10 numbers.
- *
- * The bigint space in the context is reused for string output, as there
- * is more than enough space for that (>1kB at the moment), and we avoid
- * allocating even more stack.
- */
-
- DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH);
- DUK_ASSERT(nc_ctx->count >= 1);
-
- k = nc_ctx->k;
- buf = (duk_uint8_t *) &nc_ctx->f; /* XXX: union would be more correct */
- q = buf;
-
- /* Exponent handling: if exponent format is used, record exponent value and
- * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23").
- *
- * toFixed() prevents exponent use; otherwise apply a set of criteria to
- * match the other API calls (toString(), toPrecision, etc).
- */
-
- expt = DUK__NO_EXP;
- if (!nc_ctx->abs_pos /* toFixed() */) {
- if ((flags & DUK_N2S_FLAG_FORCE_EXP) || /* exponential notation forced */
- ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) && /* fixed precision and zero padding would be required */
- (k - digits >= 1)) || /* (e.g. k=3, digits=2 -> "12X") */
- ((k > 21 || k <= -6) && (radix == 10))) { /* toString() conditions */
- DUK_DDD(DUK_DDDPRINT("use exponential notation: k=%ld -> expt=%ld",
- (long) k, (long) (k - 1)));
- expt = k - 1; /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */
- k = 1; /* generate mantissa with a single leading whole number digit */
- }
- }
-
- if (neg) {
- *q++ = '-';
- }
-
- /* Start position (inclusive) and end position (exclusive) */
- pos = (k >= 1 ? k : 1);
- if (nc_ctx->is_fixed) {
- if (nc_ctx->abs_pos) {
- /* toFixed() */
- pos_end = -digits;
- } else {
- pos_end = k - digits;
- }
- } else {
- pos_end = k - nc_ctx->count;
- }
- if (pos_end > 0) {
- pos_end = 0;
- }
-
- DUK_DDD(DUK_DDDPRINT("expt=%ld, k=%ld, count=%ld, pos=%ld, pos_end=%ld, is_fixed=%ld, "
- "digits=%ld, abs_pos=%ld",
- (long) expt, (long) k, (long) nc_ctx->count, (long) pos, (long) pos_end,
- (long) nc_ctx->is_fixed, (long) digits, (long) nc_ctx->abs_pos));
-
- /* Digit generation */
- while (pos > pos_end) {
- DUK_DDD(DUK_DDDPRINT("digit generation: pos=%ld, pos_end=%ld",
- (long) pos, (long) pos_end));
- if (pos == 0) {
- *q++ = (duk_uint8_t) '.';
- }
- if (pos > k) {
- *q++ = (duk_uint8_t) '0';
- } else if (pos <= k - nc_ctx->count) {
- *q++ = (duk_uint8_t) '0';
- } else {
- dig = nc_ctx->digits[k - pos];
- DUK_ASSERT(dig >= 0 && dig < nc_ctx->B);
- *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig);
- }
-
- pos--;
- }
- DUK_ASSERT(pos <= 1);
-
- /* Exponent */
- if (expt != DUK__NO_EXP) {
- /*
- * Exponent notation for non-base-10 numbers isn't specified in Ecmascript
- * specification, as it never explicitly turns up: non-decimal numbers can
- * only be formatted with Number.prototype.toString([radix]) and for that,
- * behavior is not explicitly specified.
- *
- * Logical choices include formatting the exponent as decimal (e.g. binary
- * 100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101).
- * The Dragon4 algorithm (in the original paper) prints the exponent value
- * in the target radix B. However, for radix values 15 and above, the
- * exponent separator 'e' is no longer easily parseable. Consider, for
- * instance, the number "1.faecee+1c".
- */
-
- duk_size_t len;
- char expt_sign;
-
- *q++ = 'e';
- if (expt >= 0) {
- expt_sign = '+';
- } else {
- expt_sign = '-';
- expt = -expt;
- }
- *q++ = (duk_uint8_t) expt_sign;
- len = duk__dragon4_format_uint32(q, (duk_uint32_t) expt, radix);
- q += len;
- }
-
- duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
-}
-
-/*
- * Conversion helpers
- */
-
-DUK_LOCAL void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) {
- duk_double_union u;
- duk_uint32_t tmp;
- duk_small_int_t expt;
-
- /*
- * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
- * A B C D E F G H
- *
- * s sign bit
- * eee... exponent field
- * fff... fraction
- *
- * ieee value = 1.ffff... * 2^(e - 1023) (normal)
- * = 0.ffff... * 2^(-1022) (denormal)
- *
- * algorithm v = f * b^e
- */
-
- DUK_DBLUNION_SET_DOUBLE(&u, x);
-
- nc_ctx->f.n = 2;
-
- tmp = DUK_DBLUNION_GET_LOW32(&u);
- nc_ctx->f.v[0] = tmp;
- tmp = DUK_DBLUNION_GET_HIGH32(&u);
- nc_ctx->f.v[1] = tmp & 0x000fffffUL;
- expt = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL);
-
- if (expt == 0) {
- /* denormal */
- expt = DUK__IEEE_DOUBLE_EXP_MIN - 52;
- duk__bi_normalize(&nc_ctx->f);
- } else {
- /* normal: implicit leading 1-bit */
- nc_ctx->f.v[1] |= 0x00100000UL;
- expt = expt - DUK__IEEE_DOUBLE_EXP_BIAS - 52;
- DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); /* true, because v[1] has at least one bit set */
- }
-
- DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));
-
- nc_ctx->e = expt;
-}
-
-DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) {
- duk_double_union u;
- duk_small_int_t expt;
- duk_small_int_t i;
- duk_small_int_t bitstart;
- duk_small_int_t bitround;
- duk_small_int_t bitidx;
- duk_small_int_t skip_round;
- duk_uint32_t t, v;
-
- DUK_ASSERT(nc_ctx->count == 53 + 1);
-
- /* Sometimes this assert is not true right now; it will be true after
- * rounding. See: test-bug-numconv-mantissa-assert.js.
- */
- DUK_ASSERT_DISABLE(nc_ctx->digits[0] == 1); /* zero handled by caller */
-
- /* Should not be required because the code below always sets both high
- * and low parts, but at least gcc-4.4.5 fails to deduce this correctly
- * (perhaps because the low part is set (seemingly) conditionally in a
- * loop), so this is here to avoid the bogus warning.
- */
- DUK_MEMZERO((void *) &u, sizeof(u));
-
- /*
- * Figure out how generated digits match up with the mantissa,
- * and then perform rounding. If mantissa overflows, need to
- * recompute the exponent (it is bumped and may overflow to
- * infinity).
- *
- * For normal numbers the leading '1' is hidden and ignored,
- * and the last bit is used for rounding:
- *
- * rounding pt
- * <--------52------->|
- * 1 x x x x ... x x x x|y ==> x x x x ... x x x x
- *
- * For denormals, the leading '1' is included in the number,
- * and the rounding point is different:
- *
- * rounding pt
- * <--52 or less--->|
- * 1 x x x x ... x x|x x y ==> 0 0 ... 1 x x ... x x
- *
- * The largest denormals will have a mantissa beginning with
- * a '1' (the explicit leading bit); smaller denormals will
- * have leading zero bits.
- *
- * If the exponent would become too high, the result becomes
- * Infinity. If the exponent is so small that the entire
- * mantissa becomes zero, the result becomes zero.
- *
- * Note: the Dragon4 'k' is off-by-one with respect to the IEEE
- * exponent. For instance, k==0 indicates that the leading '1'
- * digit is at the first binary fraction position (0.1xxx...);
- * the corresponding IEEE exponent would be -1.
- */
-
- skip_round = 0;
-
- recheck_exp:
-
- expt = nc_ctx->k - 1; /* IEEE exp without bias */
- if (expt > 1023) {
- /* Infinity */
- bitstart = -255; /* needed for inf: causes mantissa to become zero,
- * and rounding to be skipped.
- */
- expt = 2047;
- } else if (expt >= -1022) {
- /* normal */
- bitstart = 1; /* skip leading digit */
- expt += DUK__IEEE_DOUBLE_EXP_BIAS;
- DUK_ASSERT(expt >= 1 && expt <= 2046);
- } else {
- /* denormal or zero */
- bitstart = 1023 + expt; /* expt==-1023 -> bitstart=0 (leading 1);
- * expt==-1024 -> bitstart=-1 (one left of leading 1), etc
- */
- expt = 0;
- }
- bitround = bitstart + 52;
-
- DUK_DDD(DUK_DDDPRINT("ieee expt=%ld, bitstart=%ld, bitround=%ld",
- (long) expt, (long) bitstart, (long) bitround));
-
- if (!skip_round) {
- if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) {
- /* Corner case: see test-numconv-parse-mant-carry.js. We could
- * just bump the exponent and update bitstart, but it's more robust
- * to recompute (but avoid rounding twice).
- */
- DUK_DDD(DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent"));
- skip_round = 1;
- goto recheck_exp;
- }
- }
-
- /*
- * Create mantissa
- */
-
- t = 0;
- for (i = 0; i < 52; i++) {
- bitidx = bitstart + 52 - 1 - i;
- if (bitidx >= nc_ctx->count) {
- v = 0;
- } else if (bitidx < 0) {
- v = 0;
- } else {
- v = nc_ctx->digits[bitidx];
- }
- DUK_ASSERT(v == 0 || v == 1);
- t += v << (i % 32);
- if (i == 31) {
- /* low 32 bits is complete */
- DUK_DBLUNION_SET_LOW32(&u, t);
- t = 0;
- }
- }
- /* t has high mantissa */
-
- DUK_DDD(DUK_DDDPRINT("mantissa is complete: %08lx %08lx",
- (unsigned long) t,
- (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
-
- DUK_ASSERT(expt >= 0 && expt <= 0x7ffL);
- t += expt << 20;
-#if 0 /* caller handles sign change */
- if (negative) {
- t |= 0x80000000U;
- }
-#endif
- DUK_DBLUNION_SET_HIGH32(&u, t);
-
- DUK_DDD(DUK_DDDPRINT("number is complete: %08lx %08lx",
- (unsigned long) DUK_DBLUNION_GET_HIGH32(&u),
- (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
-
- *x = DUK_DBLUNION_GET_DOUBLE(&u);
-}
-
-/*
- * Exposed number-to-string API
- *
- * Input: [ number ]
- * Output: [ string ]
- */
-
-DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
- duk_double_t x;
- duk_small_int_t c;
- duk_small_int_t neg;
- duk_uint32_t uval;
- duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
- duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
-
- x = (duk_double_t) duk_require_number(ctx, -1);
- duk_pop(ctx);
-
- /*
- * Handle special cases (NaN, infinity, zero).
- */
-
- c = (duk_small_int_t) DUK_FPCLASSIFY(x);
- if (DUK_SIGNBIT((double) x)) {
- x = -x;
- neg = 1;
- } else {
- neg = 0;
- }
-
- /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */
- DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
-
- if (c == DUK_FP_NAN) {
- duk_push_hstring_stridx(ctx, DUK_STRIDX_NAN);
- return;
- } else if (c == DUK_FP_INFINITE) {
- if (neg) {
- /* -Infinity */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_INFINITY);
- } else {
- /* Infinity */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_INFINITY);
- }
- return;
- } else if (c == DUK_FP_ZERO) {
- /* We can't shortcut zero here if it goes through special formatting
- * (such as forced exponential notation).
- */
- ;
- }
-
- /*
- * Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1])
- * specially, as they're very likely for embedded programs. This
- * is now done for all radix values. We must be careful not to use
- * the fast path when special formatting (e.g. forced exponential)
- * is in force.
- *
- * XXX: could save space by supporting radix 10 only and using
- * sprintf "%lu" for the fast path and for exponent formatting.
- */
-
- uval = (unsigned int) x;
- if (((double) uval) == x && /* integer number in range */
- flags == 0) { /* no special formatting */
- /* use bigint area as a temp */
- duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f);
- duk_uint8_t *p = buf;
-
- DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1); /* max size: radix=2 + sign */
- if (neg && uval != 0) {
- /* no negative sign for zero */
- *p++ = (duk_uint8_t) '-';
- }
- p += duk__dragon4_format_uint32(p, uval, radix);
- duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
- return;
- }
-
- /*
- * Dragon4 setup.
- *
- * Convert double from IEEE representation for conversion;
- * normal finite values have an implicit leading 1-bit. The
- * slow path algorithm doesn't handle zero, so zero is special
- * cased here but still creates a valid nc_ctx, and goes
- * through normal formatting in case special formatting has
- * been requested (e.g. forced exponential format: 0 -> "0e+0").
- */
-
- /* Would be nice to bulk clear the allocation, but the context
- * is 1-2 kilobytes and nothing should rely on it being zeroed.
- */
-#if 0
- DUK_MEMZERO((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */
-#endif
-
- nc_ctx->is_s2n = 0;
- nc_ctx->b = 2;
- nc_ctx->B = radix;
- nc_ctx->abs_pos = 0;
- if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
- nc_ctx->is_fixed = 1;
- if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
- /* absolute req_digits; e.g. digits = 1 -> last digit is 0,
- * but add an extra digit for rounding.
- */
- nc_ctx->abs_pos = 1;
- nc_ctx->req_digits = (-digits + 1) - 1;
- } else {
- nc_ctx->req_digits = digits + 1;
- }
- } else {
- nc_ctx->is_fixed = 0;
- nc_ctx->req_digits = 0;
- }
-
- if (c == DUK_FP_ZERO) {
- /* Zero special case: fake requested number of zero digits; ensure
- * no sign bit is printed. Relative and absolute fixed format
- * require separate handling.
- */
- duk_small_int_t count;
- if (nc_ctx->is_fixed) {
- if (nc_ctx->abs_pos) {
- count = digits + 2; /* lead zero + 'digits' fractions + 1 for rounding */
- } else {
- count = digits + 1; /* + 1 for rounding */
- }
- } else {
- count = 1;
- }
- DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
- DUK_ASSERT(count >= 1);
- DUK_MEMZERO((void *) nc_ctx->digits, count);
- nc_ctx->count = count;
- nc_ctx->k = 1; /* 0.000... */
- neg = 0;
- goto zero_skip;
- }
-
- duk__dragon4_double_to_ctx(nc_ctx, x); /* -> sets 'f' and 'e' */
- DUK__BI_PRINT("f", &nc_ctx->f);
- DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
-
- /*
- * Dragon4 slow path digit generation.
- */
-
- duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
-
- DUK_DDD(DUK_DDDPRINT("after prepare:"));
- DUK__BI_PRINT("r", &nc_ctx->r);
- DUK__BI_PRINT("s", &nc_ctx->s);
- DUK__BI_PRINT("mp", &nc_ctx->mp);
- DUK__BI_PRINT("mm", &nc_ctx->mm);
-
- duk__dragon4_scale(nc_ctx);
-
- DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
- DUK__BI_PRINT("r", &nc_ctx->r);
- DUK__BI_PRINT("s", &nc_ctx->s);
- DUK__BI_PRINT("mp", &nc_ctx->mp);
- DUK__BI_PRINT("mm", &nc_ctx->mm);
-
- duk__dragon4_generate(nc_ctx);
-
- /*
- * Convert and push final string.
- */
-
- zero_skip:
-
- if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
- /* Perform fixed-format rounding. */
- duk_small_int_t roundpos;
- if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
- /* 'roundpos' is relative to nc_ctx->k and increases to the right
- * (opposite of how 'k' changes).
- */
- roundpos = -digits; /* absolute position for digit considered for rounding */
- roundpos = nc_ctx->k - roundpos;
- } else {
- roundpos = digits;
- }
- DUK_DDD(DUK_DDDPRINT("rounding: k=%ld, count=%ld, digits=%ld, roundpos=%ld",
- (long) nc_ctx->k, (long) nc_ctx->count, (long) digits, (long) roundpos));
- (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos);
-
- /* Note: 'count' is currently not adjusted by rounding (i.e. the
- * digits are not "chopped off". That shouldn't matter because
- * the digit position (absolute or relative) is passed on to the
- * convert-and-push function.
- */
- }
-
- duk__dragon4_convert_and_push(nc_ctx, ctx, radix, digits, flags, neg);
-}
-
-/*
- * Exposed string-to-number API
- *
- * Input: [ string ]
- * Output: [ number ]
- *
- * If number parsing fails, a NaN is pushed as the result. If number parsing
- * fails due to an internal error, an InternalError is thrown.
- */
-
-DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags) {
- duk_hthread *thr = (duk_hthread *) ctx;
- duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
- duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
- duk_double_t res;
- duk_hstring *h_str;
- duk_small_int_t expt;
- duk_small_int_t expt_neg;
- duk_small_int_t expt_adj;
- duk_small_int_t neg;
- duk_small_int_t dig;
- duk_small_int_t dig_whole;
- duk_small_int_t dig_lzero;
- duk_small_int_t dig_frac;
- duk_small_int_t dig_expt;
- duk_small_int_t dig_prec;
- const duk__exp_limits *explim;
- const duk_uint8_t *p;
- duk_small_int_t ch;
-
- /* This seems to waste a lot of stack frame entries, but good compilers
- * will compute these as needed below. Some of these initial flags are
- * also modified in the code below, so they can't all be removed.
- */
- duk_small_int_t trim_white = (flags & DUK_S2N_FLAG_TRIM_WHITE);
- duk_small_int_t allow_expt = (flags & DUK_S2N_FLAG_ALLOW_EXP);
- duk_small_int_t allow_garbage = (flags & DUK_S2N_FLAG_ALLOW_GARBAGE);
- duk_small_int_t allow_plus = (flags & DUK_S2N_FLAG_ALLOW_PLUS);
- duk_small_int_t allow_minus = (flags & DUK_S2N_FLAG_ALLOW_MINUS);
- duk_small_int_t allow_infinity = (flags & DUK_S2N_FLAG_ALLOW_INF);
- duk_small_int_t allow_frac = (flags & DUK_S2N_FLAG_ALLOW_FRAC);
- duk_small_int_t allow_naked_frac = (flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC);
- duk_small_int_t allow_empty_frac = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC);
- duk_small_int_t allow_empty = (flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
- duk_small_int_t allow_leading_zero = (flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO);
- duk_small_int_t allow_auto_hex_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT);
- duk_small_int_t allow_auto_oct_int = (flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT);
-
- DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
- (duk_tval *) duk_get_tval(ctx, -1),
- (long) radix, (unsigned long) flags));
-
- DUK_ASSERT(radix >= 2 && radix <= 36);
- DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix));
-
- /*
- * Preliminaries: trim, sign, Infinity check
- *
- * We rely on the interned string having a NUL terminator, which will
- * cause a parse failure wherever it is encountered. As a result, we
- * don't need separate pointer checks.
- *
- * There is no special parsing for 'NaN' in the specification although
- * 'Infinity' (with an optional sign) is allowed in some contexts.
- * Some contexts allow plus/minus sign, while others only allow the
- * minus sign (like JSON.parse()).
- *
- * Automatic hex number detection (leading '0x' or '0X') and octal
- * number detection (leading '0' followed by at least one octal digit)
- * is done here too.
- */
-
- if (trim_white) {
- /* Leading / trailing whitespace is sometimes accepted and
- * sometimes not. After white space trimming, all valid input
- * characters are pure ASCII.
- */
- duk_trim(ctx, -1);
- }
- h_str = duk_require_hstring(ctx, -1);
- DUK_ASSERT(h_str != NULL);
- p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
-
- neg = 0;
- ch = *p;
- if (ch == (duk_small_int_t) '+') {
- if (!allow_plus) {
- DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed"));
- goto parse_fail;
- }
- p++;
- } else if (ch == (duk_small_int_t) '-') {
- if (!allow_minus) {
- DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed"));
- goto parse_fail;
- }
- p++;
- neg = 1;
- }
-
- ch = *p;
- if (allow_infinity && ch == (duk_small_int_t) 'I') {
- /* Don't check for Infinity unless the context allows it.
- * 'Infinity' is a valid integer literal in e.g. base-36:
- *
- * parseInt('Infinity', 36)
- * 1461559270678
- */
-
- const duk_uint8_t *q;
-
- /* borrow literal Infinity from builtin string */
- q = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(DUK_HTHREAD_STRING_INFINITY(thr));
- if (DUK_STRNCMP((const char *) p, (const char *) q, 8) == 0) {
- if (!allow_garbage && (p[8] != (duk_uint8_t) 0)) {
- DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
- goto parse_fail;
- } else {
- res = DUK_DOUBLE_INFINITY;
- goto negcheck_and_ret;
- }
- }
- }
- if (ch == (duk_small_int_t) '0') {
- duk_small_int_t detect_radix = 0;
- ch = p[1];
- if (allow_auto_hex_int && (ch == (duk_small_int_t) 'x' || ch == (duk_small_int_t) 'X')) {
- DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent"));
- detect_radix = 16;
- allow_empty = 0; /* interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
- p += 2;
- } else if (allow_auto_oct_int && (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
- DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent"));
- detect_radix = 8;
- allow_empty = 1; /* interpret e.g. '09' as '0', not NaN */
- p += 1;
- }
- if (detect_radix > 0) {
- radix = detect_radix;
- allow_expt = 0;
- allow_frac = 0;
- allow_naked_frac = 0;
- allow_empty_frac = 0;
- allow_leading_zero = 1; /* allow e.g. '0x0009' and '00077' */
- }
- }
-
- /*
- * Scan number and setup for Dragon4.
- *
- * The fast path case is detected during setup: an integer which
- * can be converted without rounding, no net exponent. The fast
- * path could be implemented as a separate scan, but may not really
- * be worth it: the multiplications for building 'f' are not
- * expensive when 'f' is small.
- *
- * The significand ('f') must contain enough bits of (apparent)
- * accuracy, so that Dragon4 will generate enough binary output digits.
- * For decimal numbers, this means generating a 20-digit significand,
- * which should yield enough practical accuracy to parse IEEE doubles.
- * In fact, the Ecmascript specification explicitly allows an
- * implementation to treat digits beyond 20 as zeroes (and even
- * to round the 20th digit upwards). For non-decimal numbers, the
- * appropriate number of digits has been precomputed for comparable
- * accuracy.
- *
- * Digit counts:
- *
- * [ dig_lzero ]
- * |
- * .+-..---[ dig_prec ]----.
- * | || |
- * 0000123.456789012345678901234567890e+123456
- * | | | | | |
- * `--+--' `------[ dig_frac ]-------' `-+--'
- * | |
- * [ dig_whole ] [ dig_expt ]
- *
- * dig_frac and dig_expt are -1 if not present
- * dig_lzero is only computed for whole number part
- *
- * Parsing state
- *
- * Parsing whole part dig_frac < 0 AND dig_expt < 0
- * Parsing fraction part dig_frac >= 0 AND dig_expt < 0
- * Parsing exponent part dig_expt >= 0 (dig_frac may be < 0 or >= 0)
- *
- * Note: in case we hit an implementation limit (like exponent range),
- * we should throw an error, NOT return NaN or Infinity. Even with
- * very large exponent (or significand) values the final result may be
- * finite, so NaN/Infinity would be incorrect.
- */
-
- duk__bi_set_small(&nc_ctx->f, 0);
- dig_prec = 0;
- dig_lzero = 0;
- dig_whole = 0;
- dig_frac = -1;
- dig_expt = -1;
- expt = 0;
- expt_adj = 0; /* essentially tracks digit position of lowest 'f' digit */
- expt_neg = 0;
- for (;;) {
- ch = *p++;
-
- DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, "
- "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld",
- (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
- (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac,
- (long) dig_expt, (long) dig_lzero, (long) dig_prec));
- DUK__BI_PRINT("f", &nc_ctx->f);
-
- /* Most common cases first. */
- if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
- dig = (int) ch - '0' + 0;
- } else if (ch == (duk_small_int_t) '.') {
- /* A leading digit is not required in some cases, e.g. accept ".123".
- * In other cases (JSON.parse()) a leading digit is required. This
- * is checked for after the loop.
- */
- if (dig_frac >= 0 || dig_expt >= 0) {
- if (allow_garbage) {
- DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)"));
- break;
- } else {
- DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed"));
- goto parse_fail;
- }
- }
-
- if (!allow_frac) {
- /* Some contexts don't allow fractions at all; this can't be a
- * post-check because the state ('f' and expt) would be incorrect.
- */
- if (allow_garbage) {
- DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)"));
- break;
- } else {
- DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed"));
- }
- }
-
- DUK_DDD(DUK_DDDPRINT("start fraction part"));
- dig_frac = 0;
- continue;
- } else if (ch == (duk_small_int_t) 0) {
- DUK_DDD(DUK_DDDPRINT("NUL termination"));
- break;
- } else if (allow_expt && dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
- /* Note: we don't parse back exponent notation for anything else
- * than radix 10, so this is not an ambiguous check (e.g. hex
- * exponent values may have 'e' either as a significand digit
- * or as an exponent separator).
- *
- * If the exponent separator occurs twice, 'e' will be interpreted
- * as a digit (= 14) and will be rejected as an invalid decimal
- * digit.
- */
-
- DUK_DDD(DUK_DDDPRINT("start exponent part"));
-
- /* Exponent without a sign or with a +/- sign is accepted
- * by all call sites (even JSON.parse()).
- */
- ch = *p;
- if (ch == (duk_small_int_t) '-') {
- expt_neg = 1;
- p++;
- } else if (ch == (duk_small_int_t) '+') {
- p++;
- }
- dig_expt = 0;
- continue;
- } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') {
- dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a);
- } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') {
- dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a);
- } else {
- dig = 255; /* triggers garbage digit check below */
- }
- DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
-
- if (dig >= radix) {
- if (allow_garbage) {
- DUK_DDD(DUK_DDDPRINT("garbage termination"));
- break;
- } else {
- DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit"));
- goto parse_fail;
- }
- }
-
- if (dig_expt < 0) {
- /* whole or fraction digit */
-
- if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
- /* significant from precision perspective */
-
- duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f);
- if (f_zero && dig == 0) {
- /* Leading zero is not counted towards precision digits; not
- * in the integer part, nor in the fraction part.
- */
- if (dig_frac < 0) {
- dig_lzero++;
- }
- } else {
- /* XXX: join these ops (multiply-accumulate), but only if
- * code footprint decreases.
- */
- duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, radix);
- duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, dig);
- dig_prec++;
- }
- } else {
- /* Ignore digits beyond a radix-specific limit, but note them
- * in expt_adj.
- */
- expt_adj++;
- }
-
- if (dig_frac >= 0) {
- dig_frac++;
- expt_adj--;
- } else {
- dig_whole++;
- }
- } else {
- /* exponent digit */
-
- expt = expt * radix + dig;
- if (expt > DUK_S2N_MAX_EXPONENT) {
- /* impose a reasonable exponent limit, so that exp
- * doesn't need to get tracked using a bigint.
- */
- DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large"));
- goto parse_explimit_error;
- }
- dig_expt++;
- }
- }
-
- /* Leading zero. */
-
- if (dig_lzero > 0 && dig_whole > 1) {
- if (!allow_leading_zero) {
- DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part"));
- goto parse_fail;
- }
- }
-
- /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */
-
- if (dig_whole == 0) {
- if (dig_frac == 0) {
- /* "." is not accepted in any format */
- DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits"));
- goto parse_fail;
- } else if (dig_frac > 0) {
- /* ".123" */
- if (!allow_naked_frac) {
- DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without "
- "leading integer digit(s)"));
- goto parse_fail;
- }
- } else {
- /* empty ("") is allowed in some formats (e.g. Number(''), as zero */
- if (!allow_empty) {
- DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)"));
- goto parse_fail;
- }
- }
- } else {
- if (dig_frac == 0) {
- /* "123." is allowed in some formats */
- if (!allow_empty_frac) {
- DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions"));
- goto parse_fail;
- }
- } else if (dig_frac > 0) {
- /* "123.456" */
- ;
- } else {
- /* "123" */
- ;
- }
- }
-
- /* Exponent without digits (e.g. "1e" or "1e+"). If trailing garbage is
- * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0).
- */
-
- if (dig_expt == 0) {
- if (!allow_garbage) {
- DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent"));
- goto parse_fail;
- }
- DUK_ASSERT(expt == 0);
- }
-
- if (expt_neg) {
- expt = -expt;
- }
- DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld",
- (long) expt, (long) expt_adj, (long) (expt + expt_adj)));
- expt += expt_adj;
-
- /* Fast path check. */
-
- if (nc_ctx->f.n <= 1 && /* 32-bit value */
- expt == 0 /* no net exponent */) {
- /* Fast path is triggered for no exponent and also for balanced exponent
- * and fraction parts, e.g. for "1.23e2" == "123". Remember to respect
- * zero sign.
- */
-
- /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */
- DUK_DDD(DUK_DDDPRINT("fast path number parse"));
- if (nc_ctx->f.n == 1) {
- res = (double) nc_ctx->f.v[0];
- } else {
- res = 0.0;
- }
- goto negcheck_and_ret;
- }
-
- /* Significand ('f') padding. */
-
- while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
- /* Pad significand with "virtual" zero digits so that Dragon4 will
- * have enough (apparent) precision to work with.
- */
- DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
- duk__bi_mul_small_copy(&nc_ctx->f, radix, &nc_ctx->t1);
- DUK__BI_PRINT("f", &nc_ctx->f);
- expt--;
- dig_prec++;
- }
-
- DUK_DDD(DUK_DDDPRINT("final exponent: %ld", (long) expt));
-
- /* Detect zero special case. */
-
- if (nc_ctx->f.n == 0) {
- /* This may happen even after the fast path check, if exponent is
- * not balanced (e.g. "0e1"). Remember to respect zero sign.
- */
- DUK_DDD(DUK_DDDPRINT("significand is zero"));
- res = 0.0;
- goto negcheck_and_ret;
- }
-
-
- /* Quick reject of too large or too small exponents. This check
- * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity)
- * so zero check must be above.
- */
-
- explim = &duk__str2num_exp_limits[radix - 2];
- if (expt > explim->upper) {
- DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite"));
- res = (duk_double_t) DUK_DOUBLE_INFINITY;
- goto negcheck_and_ret;
- } else if (expt < explim->lower) {
- DUK_DDD(DUK_DDDPRINT("exponent too small -> zero"));
- res = (duk_double_t) 0.0;
- goto negcheck_and_ret;
- }
-
- nc_ctx->is_s2n = 1;
- nc_ctx->e = expt;
- nc_ctx->b = radix;
- nc_ctx->B = 2;
- nc_ctx->is_fixed = 1;
- nc_ctx->abs_pos = 0;
- nc_ctx->req_digits = 53 + 1;
-
- DUK__BI_PRINT("f", &nc_ctx->f);
- DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
-
- /*
- * Dragon4 slow path (binary) digit generation.
- * An extra digit is generated for rounding.
- */
-
- duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
-
- DUK_DDD(DUK_DDDPRINT("after prepare:"));
- DUK__BI_PRINT("r", &nc_ctx->r);
- DUK__BI_PRINT("s", &nc_ctx->s);
- DUK__BI_PRINT("mp", &nc_ctx->mp);
- DUK__BI_PRINT("mm", &nc_ctx->mm);
-
- duk__dragon4_scale(nc_ctx);
-
- DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
- DUK__BI_PRINT("r", &nc_ctx->r);
- DUK__BI_PRINT("s", &nc_ctx->s);
- DUK__BI_PRINT("mp", &nc_ctx->mp);
- DUK__BI_PRINT("mm", &nc_ctx->mm);
-
- duk__dragon4_generate(nc_ctx);
-
- DUK_ASSERT(nc_ctx->count == 53 + 1);
-
- /*
- * Convert binary digits into an IEEE double. Need to handle
- * denormals and rounding correctly.
- */
-
- duk__dragon4_ctx_to_double(nc_ctx, &res);
- goto negcheck_and_ret;
-
- negcheck_and_ret:
- if (neg) {
- res = -res;
- }
- duk_pop(ctx);
- duk_push_number(ctx, (double) res);
- DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
- return;
-
- parse_fail:
- DUK_DDD(DUK_DDDPRINT("parse failed"));
- duk_pop(ctx);
- duk_push_nan(ctx);
- return;
-
- parse_explimit_error:
- DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value"));
- DUK_ERROR_RANGE(thr, "exponent too large");
- return;
-}
-#line 1 "duk_regexp_compiler.c"
-/*
- * Regexp compilation.
- *
- * See doc/regexp.rst for a discussion of the compilation approach and
- * current limitations.
- *
- * Regexp bytecode assumes jumps can be expressed with signed 32-bit
- * integers. Consequently the bytecode size must not exceed 0x7fffffffL.
- * The implementation casts duk_size_t (buffer size) to duk_(u)int32_t
- * in many places. Although this could be changed, the bytecode format
- * limit would still prevent regexps exceeding the signed 32-bit limit
- * from working.
- *
- * XXX: The implementation does not prevent bytecode from exceeding the
- * maximum supported size. This could be done by limiting the maximum
- * input string size (assuming an upper bound can be computed for number
- * of bytecode bytes emitted per input byte) or checking buffer maximum
- * size when emitting bytecode (slower).
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_REGEXP_SUPPORT
-
-/*
- * Helper macros
- */
-
-#define DUK__RE_INITIAL_BUFSIZE 64
-
-#undef DUK__RE_BUFLEN
-#define DUK__RE_BUFLEN(re_ctx) \
- DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw)
-
-/*
- * Disjunction struct: result of parsing a disjunction
- */
-
-typedef struct {
- /* Number of characters that the atom matches (e.g. 3 for 'abc'),
- * -1 if atom is complex and number of matched characters either
- * varies or is not known.
- */
- duk_int32_t charlen;
-
-#if 0
- /* These are not needed to implement quantifier capture handling,
- * but might be needed at some point.
- */
-
- /* re_ctx->captures at start and end of atom parsing.
- * Since 'captures' indicates highest capture number emitted
- * so far in a DUK_REOP_SAVE, the captures numbers saved by
- * the atom are: ]start_captures,end_captures].
- */
- duk_uint32_t start_captures;
- duk_uint32_t end_captures;
-#endif
-} duk__re_disjunction_info;
-
-/*
- * Encoding helpers
- *
- * Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit
- * even though the buffer operations will use duk_size_t.
- */
-
-/* XXX: the insert helpers should ensure that the bytecode result is not
- * larger than expected (or at least assert for it). Many things in the
- * bytecode, like skip offsets, won't work correctly if the bytecode is
- * larger than say 2G.
- */
-
-DUK_LOCAL duk_uint32_t duk__encode_i32(duk_int32_t x) {
- if (x < 0) {
- return ((duk_uint32_t) (-x)) * 2 + 1;
- } else {
- return ((duk_uint32_t) x) * 2;
- }
-}
-
-/* XXX: return type should probably be duk_size_t, or explicit checks are needed for
- * maximum size.
- */
-DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) {
- duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
- duk_small_int_t len;
-
- len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
- DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, len);
- return (duk_uint32_t) len;
-}
-
-DUK_LOCAL duk_uint32_t duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
- duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
- duk_small_int_t len;
-
- len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
- DUK_BW_WRITE_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, buf, len);
- return (duk_uint32_t) len;
-}
-
-DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) {
- return duk__insert_u32(re_ctx, offset, duk__encode_i32(x));
-}
-
-#if 0 /* unused */
-DUK_LOCAL duk_uint32_t duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
- return duk__append_u32(re_ctx, duk__encode_i32(x));
-}
-#endif
-
-/* special helper for emitting u16 lists (used for character ranges for built-in char classes) */
-DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) {
- /* Call sites don't need the result length so it's not accumulated. */
- while (count > 0) {
- (void) duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
- count--;
- }
-}
-
-DUK_LOCAL void duk__insert_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t data_offset, duk_uint32_t data_length) {
- DUK_BW_INSERT_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, offset, data_offset, data_length);
-}
-
-DUK_LOCAL void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
- DUK_BW_WRITE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
-}
-
-DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
- DUK_BW_REMOVE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
-}
-
-/*
- * Insert a jump offset at 'offset' to complete an instruction
- * (the jump offset is always the last component of an instruction).
- * The 'skip' argument must be computed relative to 'offset',
- * -without- taking into account the skip field being inserted.
- *
- * ... A B C ins X Y Z ... (ins may be a JUMP, SPLIT1/SPLIT2, etc)
- * => ... A B C ins SKIP X Y Z
- *
- * Computing the final (adjusted) skip value, which is relative to the
- * first byte of the next instruction, is a bit tricky because of the
- * variable length UTF-8 encoding. See doc/regexp.rst for discussion.
- */
-DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) {
- duk_small_int_t len;
-
- /* XXX: solve into closed form (smaller code) */
-
- if (skip < 0) {
- /* two encoding attempts suffices */
- len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip));
- len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len));
- DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len); /* no change */
- skip -= (duk_int32_t) len;
- }
- return duk__insert_i32(re_ctx, offset, skip);
-}
-
-DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) {
- return (duk_uint32_t) duk__insert_jump_offset(re_ctx, (duk_uint32_t) DUK__RE_BUFLEN(re_ctx), skip);
-}
-
-/*
- * duk_re_range_callback for generating character class ranges.
- *
- * When ignoreCase is false, the range is simply emitted as is.
- * We don't, for instance, eliminate duplicates or overlapping
- * ranges in a character class.
- *
- * When ignoreCase is true, the range needs to be normalized through
- * canonicalization. Unfortunately a canonicalized version of a
- * continuous range is not necessarily continuous (e.g. [x-{] is
- * continuous but [X-{] is not). The current algorithm creates the
- * canonicalized range(s) space efficiently at the cost of compile
- * time execution time (see doc/regexp.rst for discussion).
- *
- * Note that the ctx->nranges is a context-wide temporary value
- * (this is OK because there cannot be multiple character classes
- * being parsed simultaneously).
- */
-
-DUK_LOCAL void duk__generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
- duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
-
- DUK_DD(DUK_DDPRINT("duk__generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
- (void *) re_ctx, (long) r1, (long) r2, (long) direct));
-
- if (!direct && (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE)) {
- /*
- * Canonicalize a range, generating result ranges as necessary.
- * Needs to exhaustively scan the entire range (at most 65536
- * code points). If 'direct' is set, caller (lexer) has ensured
- * that the range is already canonicalization compatible (this
- * is used to avoid unnecessary canonicalization of built-in
- * ranges like \W, which are not affected by canonicalization).
- *
- * NOTE: here is one place where we don't want to support chars
- * outside the BMP, because the exhaustive search would be
- * massively larger.
- */
-
- duk_codepoint_t i;
- duk_codepoint_t t;
- duk_codepoint_t r_start, r_end;
-
- r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
- r_end = r_start;
- for (i = r1 + 1; i <= r2; i++) {
- t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
- if (t == r_end + 1) {
- r_end = t;
- } else {
- DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
- duk__append_u32(re_ctx, (duk_uint32_t) r_start);
- duk__append_u32(re_ctx, (duk_uint32_t) r_end);
- re_ctx->nranges++;
- r_start = t;
- r_end = t;
- }
- }
- DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
- duk__append_u32(re_ctx, (duk_uint32_t) r_start);
- duk__append_u32(re_ctx, (duk_uint32_t) r_end);
- re_ctx->nranges++;
- } else {
- DUK_DD(DUK_DDPRINT("direct, emit range: [%ld,%ld]", (long) r1, (long) r2));
- duk__append_u32(re_ctx, (duk_uint32_t) r1);
- duk__append_u32(re_ctx, (duk_uint32_t) r2);
- re_ctx->nranges++;
- }
-}
-
-/*
- * Parse regexp Disjunction. Most of regexp compilation happens here.
- *
- * Handles Disjunction, Alternative, and Term productions directly without
- * recursion. The only constructs requiring recursion are positive/negative
- * lookaheads, capturing parentheses, and non-capturing parentheses.
- *
- * The function determines whether the entire disjunction is a 'simple atom'
- * (see doc/regexp.rst discussion on 'simple quantifiers') and if so,
- * returns the atom character length which is needed by the caller to keep
- * track of its own atom character length. A disjunction with more than one
- * alternative is never considered a simple atom (although in some cases
- * that might be the case).
- *
- * Return value: simple atom character length or < 0 if not a simple atom.
- * Appends the bytecode for the disjunction matcher to the end of the temp
- * buffer.
- *
- * Regexp top level structure is:
- *
- * Disjunction = Term*
- * | Term* | Disjunction
- *
- * Term = Assertion
- * | Atom
- * | Atom Quantifier
- *
- * An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/).
- *
- * Notes:
- *
- * * Tracking of the 'simple-ness' of the current atom vs. the entire
- * disjunction are separate matters. For instance, the disjunction
- * may be complex, but individual atoms may be simple. Furthermore,
- * simple quantifiers are used whenever possible, even if the
- * disjunction as a whole is complex.
- *
- * * The estimate of whether an atom is simple is conservative now,
- * and it would be possible to expand it. For instance, captures
- * cause the disjunction to be marked complex, even though captures
- * -can- be handled by simple quantifiers with some minor modifications.
- *
- * * Disjunction 'tainting' as 'complex' is handled at the end of the
- * main for loop collectively for atoms. Assertions, quantifiers,
- * and '|' tokens need to taint the result manually if necessary.
- * Assertions cannot add to result char length, only atoms (and
- * quantifiers) can; currently quantifiers will taint the result
- * as complex though.
- */
-
-DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) {
- duk_int32_t atom_start_offset = -1; /* negative -> no atom matched on previous round */
- duk_int32_t atom_char_length = 0; /* negative -> complex atom */
- duk_uint32_t atom_start_captures = re_ctx->captures; /* value of re_ctx->captures at start of atom */
- duk_int32_t unpatched_disjunction_split = -1;
- duk_int32_t unpatched_disjunction_jump = -1;
- duk_uint32_t entry_offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
- duk_int32_t res_charlen = 0; /* -1 if disjunction is complex, char length if simple */
- duk__re_disjunction_info tmp_disj;
-
- DUK_ASSERT(out_atom_info != NULL);
-
- if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
- DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT);
- }
- re_ctx->recursion_depth++;
-
-#if 0
- out_atom_info->start_captures = re_ctx->captures;
-#endif
-
- for (;;) {
- /* atom_char_length, atom_start_offset, atom_start_offset reflect the
- * atom matched on the previous loop. If a quantifier is encountered
- * on this loop, these are needed to handle the quantifier correctly.
- * new_atom_char_length etc are for the atom parsed on this round;
- * they're written to atom_char_length etc at the end of the round.
- */
- duk_int32_t new_atom_char_length; /* char length of the atom parsed in this loop */
- duk_int32_t new_atom_start_offset; /* bytecode start offset of the atom parsed in this loop
- * (allows quantifiers to copy the atom bytecode)
- */
- duk_uint32_t new_atom_start_captures; /* re_ctx->captures at the start of the atom parsed in this loop */
-
- duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token);
-
- DUK_DD(DUK_DDPRINT("re token: %ld (num=%ld, char=%c)",
- (long) re_ctx->curr_token.t,
- (long) re_ctx->curr_token.num,
- (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ?
- (int) re_ctx->curr_token.num : (int) '?'));
-
- /* set by atom case clauses */
- new_atom_start_offset = -1;
- new_atom_char_length = -1;
- new_atom_start_captures = re_ctx->captures;
-
- switch (re_ctx->curr_token.t) {
- case DUK_RETOK_DISJUNCTION: {
- /*
- * The handling here is a bit tricky. If a previous '|' has been processed,
- * we have a pending split1 and a pending jump (for a previous match). These
- * need to be back-patched carefully. See docs for a detailed example.
- */
-
- /* patch pending jump and split */
- if (unpatched_disjunction_jump >= 0) {
- duk_uint32_t offset;
-
- DUK_ASSERT(unpatched_disjunction_split >= 0);
- offset = unpatched_disjunction_jump;
- offset += duk__insert_jump_offset(re_ctx,
- offset,
- (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
- /* offset is now target of the pending split (right after jump) */
- duk__insert_jump_offset(re_ctx,
- unpatched_disjunction_split,
- offset - unpatched_disjunction_split);
- }
-
- /* add a new pending split to the beginning of the entire disjunction */
- (void) duk__insert_u32(re_ctx,
- entry_offset,
- DUK_REOP_SPLIT1); /* prefer direct execution */
- unpatched_disjunction_split = entry_offset + 1; /* +1 for opcode */
-
- /* add a new pending match jump for latest finished alternative */
- duk__append_u32(re_ctx, DUK_REOP_JUMP);
- unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
-
- /* 'taint' result as complex */
- res_charlen = -1;
- break;
- }
- case DUK_RETOK_QUANTIFIER: {
- if (atom_start_offset < 0) {
- DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM);
- }
- if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) {
- DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES);
- }
- if (atom_char_length >= 0) {
- /*
- * Simple atom
- *
- * If atom_char_length is zero, we'll have unbounded execution time for e.g.
- * /()*x/.exec('x'). We can't just skip the match because it might have some
- * side effects (for instance, if we allowed captures in simple atoms, the
- * capture needs to happen). The simple solution below is to force the
- * quantifier to match at most once, since the additional matches have no effect.
- *
- * With a simple atom there can be no capture groups, so no captures need
- * to be reset.
- */
- duk_int32_t atom_code_length;
- duk_uint32_t offset;
- duk_uint32_t qmin, qmax;
-
- qmin = re_ctx->curr_token.qmin;
- qmax = re_ctx->curr_token.qmax;
- if (atom_char_length == 0) {
- /* qmin and qmax will be 0 or 1 */
- if (qmin > 1) {
- qmin = 1;
- }
- if (qmax > 1) {
- qmax = 1;
- }
- }
-
- duk__append_u32(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */
- atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - atom_start_offset);
-
- offset = atom_start_offset;
- if (re_ctx->curr_token.greedy) {
- offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
- offset += duk__insert_u32(re_ctx, offset, qmin);
- offset += duk__insert_u32(re_ctx, offset, qmax);
- offset += duk__insert_u32(re_ctx, offset, atom_char_length);
- offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
- } else {
- offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
- offset += duk__insert_u32(re_ctx, offset, qmin);
- offset += duk__insert_u32(re_ctx, offset, qmax);
- offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
- }
- DUK_UNREF(offset); /* silence scan-build warning */
- } else {
- /*
- * Complex atom
- *
- * The original code is used as a template, and removed at the end
- * (this differs from the handling of simple quantifiers).
- *
- * NOTE: there is no current solution for empty atoms in complex
- * quantifiers. This would need some sort of a 'progress' instruction.
- *
- * XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies?
- */
- duk_int32_t atom_code_length;
- duk_uint32_t atom_copies;
- duk_uint32_t tmp_qmin, tmp_qmax;
-
- /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */
- atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ?
- re_ctx->curr_token.qmin : re_ctx->curr_token.qmax;
- if (atom_copies > DUK_RE_MAX_ATOM_COPIES) {
- DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES);
- }
-
- /* wipe the capture range made by the atom (if any) */
- DUK_ASSERT(atom_start_captures <= re_ctx->captures);
- if (atom_start_captures != re_ctx->captures) {
- DUK_ASSERT(atom_start_captures < re_ctx->captures);
- DUK_DDD(DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%ld,%ld]",
- (long) atom_start_captures, (long) re_ctx->captures));
-
- /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
- duk__insert_u32(re_ctx, atom_start_offset, (re_ctx->captures - atom_start_captures) * 2);
- duk__insert_u32(re_ctx, atom_start_offset, (atom_start_captures + 1) * 2);
- duk__insert_u32(re_ctx, atom_start_offset, DUK_REOP_WIPERANGE);
- } else {
- DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld",
- (long) atom_start_captures));
- }
-
- atom_code_length = (duk_int32_t) DUK__RE_BUFLEN(re_ctx) - atom_start_offset;
-
- /* insert the required matches (qmin) by copying the atom */
- tmp_qmin = re_ctx->curr_token.qmin;
- tmp_qmax = re_ctx->curr_token.qmax;
- while (tmp_qmin > 0) {
- duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
- tmp_qmin--;
- if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
- tmp_qmax--;
- }
- }
- DUK_ASSERT(tmp_qmin == 0);
-
- /* insert code for matching the remainder - infinite or finite */
- if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) {
- /* reuse last emitted atom for remaining 'infinite' quantifier */
-
- if (re_ctx->curr_token.qmin == 0) {
- /* Special case: original qmin was zero so there is nothing
- * to repeat. Emit an atom copy but jump over it here.
- */
- duk__append_u32(re_ctx, DUK_REOP_JUMP);
- duk__append_jump_offset(re_ctx, atom_code_length);
- duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
- }
- if (re_ctx->curr_token.greedy) {
- duk__append_u32(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */
- } else {
- duk__append_u32(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */
- }
- duk__append_jump_offset(re_ctx, -atom_code_length - 1); /* -1 for opcode */
- } else {
- /*
- * The remaining matches are emitted as sequence of SPLITs and atom
- * copies; the SPLITs skip the remaining copies and match the sequel.
- * This sequence needs to be emitted starting from the last copy
- * because the SPLITs are variable length due to the variable length
- * skip offset. This causes a lot of memory copying now.
- *
- * Example structure (greedy, match maximum # atoms):
- *
- * SPLIT1 LSEQ
- * (atom)
- * SPLIT1 LSEQ ; <- the byte length of this instruction is needed
- * (atom) ; to encode the above SPLIT1 correctly
- * ...
- * LSEQ:
- */
- duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
- while (tmp_qmax > 0) {
- duk__insert_slice(re_ctx, offset, atom_start_offset, atom_code_length);
- if (re_ctx->curr_token.greedy) {
- duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */
- } else {
- duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2); /* prefer jump */
- }
- duk__insert_jump_offset(re_ctx,
- offset + 1, /* +1 for opcode */
- (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
- tmp_qmax--;
- }
- }
-
- /* remove the original 'template' atom */
- duk__remove_slice(re_ctx, atom_start_offset, atom_code_length);
- }
-
- /* 'taint' result as complex */
- res_charlen = -1;
- break;
- }
- case DUK_RETOK_ASSERT_START: {
- duk__append_u32(re_ctx, DUK_REOP_ASSERT_START);
- break;
- }
- case DUK_RETOK_ASSERT_END: {
- duk__append_u32(re_ctx, DUK_REOP_ASSERT_END);
- break;
- }
- case DUK_RETOK_ASSERT_WORD_BOUNDARY: {
- duk__append_u32(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
- break;
- }
- case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: {
- duk__append_u32(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
- break;
- }
- case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD:
- case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: {
- duk_uint32_t offset;
- duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ?
- DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG;
-
- offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
- duk__parse_disjunction(re_ctx, 0, &tmp_disj);
- duk__append_u32(re_ctx, DUK_REOP_MATCH);
-
- (void) duk__insert_u32(re_ctx, offset, opcode);
- (void) duk__insert_jump_offset(re_ctx,
- offset + 1, /* +1 for opcode */
- (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
-
- /* 'taint' result as complex -- this is conservative,
- * as lookaheads do not backtrack.
- */
- res_charlen = -1;
- break;
- }
- case DUK_RETOK_ATOM_PERIOD: {
- new_atom_char_length = 1;
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx, DUK_REOP_PERIOD);
- break;
- }
- case DUK_RETOK_ATOM_CHAR: {
- /* Note: successive characters could be joined into string matches
- * but this is not trivial (consider e.g. '/xyz+/); see docs for
- * more discussion.
- */
- duk_uint32_t ch;
-
- new_atom_char_length = 1;
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx, DUK_REOP_CHAR);
- ch = re_ctx->curr_token.num;
- if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
- ch = duk_unicode_re_canonicalize_char(re_ctx->thr, ch);
- }
- duk__append_u32(re_ctx, ch);
- break;
- }
- case DUK_RETOK_ATOM_DIGIT:
- case DUK_RETOK_ATOM_NOT_DIGIT: {
- new_atom_char_length = 1;
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx,
- (re_ctx->curr_token.t == DUK_RETOK_ATOM_DIGIT) ?
- DUK_REOP_RANGES : DUK_REOP_INVRANGES);
- duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)));
- duk__append_u16_list(re_ctx, duk_unicode_re_ranges_digit, sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
- break;
- }
- case DUK_RETOK_ATOM_WHITE:
- case DUK_RETOK_ATOM_NOT_WHITE: {
- new_atom_char_length = 1;
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx,
- (re_ctx->curr_token.t == DUK_RETOK_ATOM_WHITE) ?
- DUK_REOP_RANGES : DUK_REOP_INVRANGES);
- duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)));
- duk__append_u16_list(re_ctx, duk_unicode_re_ranges_white, sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
- break;
- }
- case DUK_RETOK_ATOM_WORD_CHAR:
- case DUK_RETOK_ATOM_NOT_WORD_CHAR: {
- new_atom_char_length = 1;
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx,
- (re_ctx->curr_token.t == DUK_RETOK_ATOM_WORD_CHAR) ?
- DUK_REOP_RANGES : DUK_REOP_INVRANGES);
- duk__append_u32(re_ctx, sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t)));
- duk__append_u16_list(re_ctx, duk_unicode_re_ranges_wordchar, sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
- break;
- }
- case DUK_RETOK_ATOM_BACKREFERENCE: {
- duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num;
- if (backref > re_ctx->highest_backref) {
- re_ctx->highest_backref = backref;
- }
- new_atom_char_length = -1; /* mark as complex */
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx, DUK_REOP_BACKREFERENCE);
- duk__append_u32(re_ctx, backref);
- break;
- }
- case DUK_RETOK_ATOM_START_CAPTURE_GROUP: {
- duk_uint32_t cap;
-
- new_atom_char_length = -1; /* mark as complex (capture handling) */
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- cap = ++re_ctx->captures;
- duk__append_u32(re_ctx, DUK_REOP_SAVE);
- duk__append_u32(re_ctx, cap * 2);
- duk__parse_disjunction(re_ctx, 0, &tmp_disj); /* retval (sub-atom char length) unused, tainted as complex above */
- duk__append_u32(re_ctx, DUK_REOP_SAVE);
- duk__append_u32(re_ctx, cap * 2 + 1);
- break;
- }
- case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: {
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__parse_disjunction(re_ctx, 0, &tmp_disj);
- new_atom_char_length = tmp_disj.charlen;
- break;
- }
- case DUK_RETOK_ATOM_START_CHARCLASS:
- case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: {
- /*
- * Range parsing is done with a special lexer function which calls
- * us for every range parsed. This is different from how rest of
- * the parsing works, but avoids a heavy, arbitrary size intermediate
- * value type to hold the ranges.
- *
- * Another complication is the handling of character ranges when
- * case insensitive matching is used (see docs for discussion).
- * The range handler callback given to the lexer takes care of this
- * as well.
- *
- * Note that duplicate ranges are not eliminated when parsing character
- * classes, so that canonicalization of
- *
- * [0-9a-fA-Fx-{]
- *
- * creates the result (note the duplicate ranges):
- *
- * [0-9A-FA-FX-Z{-{]
- *
- * where [x-{] is split as a result of canonicalization. The duplicate
- * ranges are not a semantics issue: they work correctly.
- */
-
- duk_uint32_t offset;
-
- DUK_DD(DUK_DDPRINT("character class"));
-
- /* insert ranges instruction, range count patched in later */
- new_atom_char_length = 1;
- new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
- duk__append_u32(re_ctx,
- (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
- DUK_REOP_RANGES : DUK_REOP_INVRANGES);
- offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); /* patch in range count later */
-
- /* parse ranges until character class ends */
- re_ctx->nranges = 0; /* note: ctx-wide temporary */
- duk_lexer_parse_re_ranges(&re_ctx->lex, duk__generate_ranges, (void *) re_ctx);
-
- /* insert range count */
- duk__insert_u32(re_ctx, offset, re_ctx->nranges);
- break;
- }
- case DUK_RETOK_ATOM_END_GROUP: {
- if (expect_eof) {
- DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN);
- }
- goto done;
- }
- case DUK_RETOK_EOF: {
- if (!expect_eof) {
- DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN);
- }
- goto done;
- }
- default: {
- DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN);
- }
- }
-
- /* a complex (new) atom taints the result */
- if (new_atom_start_offset >= 0) {
- if (new_atom_char_length < 0) {
- res_charlen = -1;
- } else if (res_charlen >= 0) {
- /* only advance if not tainted */
- res_charlen += new_atom_char_length;
- }
- }
-
- /* record previous atom info in case next token is a quantifier */
- atom_start_offset = new_atom_start_offset;
- atom_char_length = new_atom_char_length;
- atom_start_captures = new_atom_start_captures;
- }
-
- done:
-
- /* finish up pending jump and split for last alternative */
- if (unpatched_disjunction_jump >= 0) {
- duk_uint32_t offset;
-
- DUK_ASSERT(unpatched_disjunction_split >= 0);
- offset = unpatched_disjunction_jump;
- offset += duk__insert_jump_offset(re_ctx,
- offset,
- (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
- /* offset is now target of the pending split (right after jump) */
- duk__insert_jump_offset(re_ctx,
- unpatched_disjunction_split,
- offset - unpatched_disjunction_split);
- }
-
-#if 0
- out_atom_info->end_captures = re_ctx->captures;
-#endif
- out_atom_info->charlen = res_charlen;
- DUK_DDD(DUK_DDDPRINT("parse disjunction finished: charlen=%ld",
- (long) out_atom_info->charlen));
-
- re_ctx->recursion_depth--;
-}
-
-/*
- * Flags parsing (see E5 Section 15.10.4.1).
- */
-
-DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) {
- const duk_uint8_t *p;
- const duk_uint8_t *p_end;
- duk_uint32_t flags = 0;
-
- p = DUK_HSTRING_GET_DATA(h);
- p_end = p + DUK_HSTRING_GET_BYTELEN(h);
-
- /* Note: can be safely scanned as bytes (undecoded) */
-
- while (p < p_end) {
- duk_uint8_t c = *p++;
- switch ((int) c) {
- case (int) 'g': {
- if (flags & DUK_RE_FLAG_GLOBAL) {
- goto error;
- }
- flags |= DUK_RE_FLAG_GLOBAL;
- break;
- }
- case (int) 'i': {
- if (flags & DUK_RE_FLAG_IGNORE_CASE) {
- goto error;
- }
- flags |= DUK_RE_FLAG_IGNORE_CASE;
- break;
- }
- case (int) 'm': {
- if (flags & DUK_RE_FLAG_MULTILINE) {
- goto error;
- }
- flags |= DUK_RE_FLAG_MULTILINE;
- break;
- }
- default: {
- goto error;
- }
- }
- }
-
- return flags;
-
- error:
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS);
- return 0; /* never here */
-}
-
-/*
- * Create escaped RegExp source (E5 Section 15.10.3).
- *
- * The current approach is to special case the empty RegExp
- * ('' -> '(?:)') and otherwise replace unescaped '/' characters
- * with '\/' regardless of where they occur in the regexp.
- *
- * Note that normalization does not seem to be necessary for
- * RegExp literals (e.g. '/foo/') because to be acceptable as
- * a RegExp literal, the text between forward slashes must
- * already match the escaping requirements (e.g. must not contain
- * unescaped forward slashes or be empty). Escaping IS needed
- * for expressions like 'new Regexp("...", "")' however.
- * Currently, we re-escape in either case.
- *
- * Also note that we process the source here in UTF-8 encoded
- * form. This is correct, because any non-ASCII characters are
- * passed through without change.
- */
-
-DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
- duk_context *ctx = (duk_context *) thr;
- duk_hstring *h;
- const duk_uint8_t *p;
- duk_bufwriter_ctx bw_alloc;
- duk_bufwriter_ctx *bw;
- duk_uint8_t *q;
- duk_size_t i, n;
- duk_uint_fast8_t c_prev, c;
-
- h = duk_get_hstring(ctx, idx_pattern);
- DUK_ASSERT(h != NULL);
- p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
- n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
-
- if (n == 0) {
- /* return '(?:)' */
- duk_push_hstring_stridx(ctx, DUK_STRIDX_ESCAPED_EMPTY_REGEXP);
- return;
- }
-
- bw = &bw_alloc;
- DUK_BW_INIT_PUSHBUF(thr, bw, n);
- q = DUK_BW_GET_PTR(thr, bw);
-
- c_prev = (duk_uint_fast8_t) 0;
-
- for (i = 0; i < n; i++) {
- c = p[i];
-
- q = DUK_BW_ENSURE_RAW(thr, bw, 2, q);
-
- if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') {
- /* Unescaped '/' ANYWHERE in the regexp (in disjunction,
- * inside a character class, ...) => same escape works.
- */
- *q++ = DUK_ASC_BACKSLASH;
- }
- *q++ = (duk_uint8_t) c;
-
- c_prev = c;
- }
-
- DUK_BW_SETPTR_AND_COMPACT(thr, bw, q);
- duk_to_string(ctx, -1); /* -> [ ... escaped_source ] */
-}
-
-/*
- * Exposed regexp compilation primitive.
- *
- * Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the
- * actual parsing. Handles generation of the compiled regexp header and the
- * "boilerplate" capture of the matching substring (save 0 and 1). Also does some
- * global level regexp checks after recursive compilation has finished.
- *
- * An escaped version of the regexp source, suitable for use as a RegExp instance
- * 'source' property (see E5 Section 15.10.3), is also left on the stack.
- *
- * Input stack: [ pattern flags ]
- * Output stack: [ bytecode escaped_source ] (both as strings)
- */
-
-DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_re_compiler_ctx re_ctx;
- duk_lexer_point lex_point;
- duk_hstring *h_pattern;
- duk_hstring *h_flags;
- duk__re_disjunction_info ign_disj;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
-
- /*
- * Args validation
- */
-
- /* TypeError if fails */
- h_pattern = duk_require_hstring(ctx, -2);
- h_flags = duk_require_hstring(ctx, -1);
-
- /*
- * Create normalized 'source' property (E5 Section 15.10.3).
- */
-
- /* [ ... pattern flags ] */
-
- duk__create_escaped_source(thr, -2);
-
- /* [ ... pattern flags escaped_source ] */
-
- /*
- * Init compilation context
- */
-
- /* [ ... pattern flags escaped_source buffer ] */
-
- DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
- DUK_LEXER_INITCTX(&re_ctx.lex); /* duplicate zeroing, expect for (possible) NULL inits */
- re_ctx.thr = thr;
- re_ctx.lex.thr = thr;
- re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern);
- re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern);
- re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT;
- re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT;
- re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags);
-
- DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE);
-
- DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld",
- (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit));
-
- /*
- * Init lexer
- */
-
- lex_point.offset = 0; /* expensive init, just want to fill window */
- lex_point.line = 1;
- DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point);
-
- /*
- * Compilation
- */
-
- DUK_DD(DUK_DDPRINT("starting regexp compilation"));
-
- duk__append_u32(&re_ctx, DUK_REOP_SAVE);
- duk__append_u32(&re_ctx, 0);
- duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
- duk__append_u32(&re_ctx, DUK_REOP_SAVE);
- duk__append_u32(&re_ctx, 1);
- duk__append_u32(&re_ctx, DUK_REOP_MATCH);
-
- /*
- * Check for invalid backreferences; note that it is NOT an error
- * to back-reference a capture group which has not yet been introduced
- * in the pattern (as in /\1(foo)/); in fact, the backreference will
- * always match! It IS an error to back-reference a capture group
- * which will never be introduced in the pattern. Thus, we can check
- * for such references only after parsing is complete.
- */
-
- if (re_ctx.highest_backref > re_ctx.captures) {
- DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS);
- }
-
- /*
- * Emit compiled regexp header: flags, ncaptures
- * (insertion order inverted on purpose)
- */
-
- duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2);
- duk__insert_u32(&re_ctx, 0, re_ctx.re_flags);
-
- /* [ ... pattern flags escaped_source buffer ] */
-
- DUK_BW_COMPACT(thr, &re_ctx.bw);
- duk_to_string(ctx, -1); /* coerce to string */
-
- /* [ ... pattern flags escaped_source bytecode ] */
-
- /*
- * Finalize stack
- */
-
- duk_remove(ctx, -4); /* -> [ ... flags escaped_source bytecode ] */
- duk_remove(ctx, -3); /* -> [ ... escaped_source bytecode ] */
-
- DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
- (duk_tval *) duk_get_tval(ctx, -1), (duk_tval *) duk_get_tval(ctx, -2)));
-}
-
-/*
- * Create a RegExp instance (E5 Section 15.10.7).
- *
- * Note: the output stack left by duk_regexp_compile() is directly compatible
- * with the input here.
- *
- * Input stack: [ escaped_source bytecode ] (both as strings)
- * Output stack: [ RegExp ]
- */
-
-DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
- duk_context *ctx = (duk_context *) thr;
- duk_hobject *h;
- duk_hstring *h_bc;
- duk_small_int_t re_flags;
-
- /* [ ... escape_source bytecode ] */
-
- h_bc = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_bc != NULL);
- DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(h_bc) >= 1); /* always at least the header */
- DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h_bc) >= 1);
- DUK_ASSERT((duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0] < 0x80); /* flags always encodes to 1 byte */
- re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0];
-
- /* [ ... escaped_source bytecode ] */
-
- duk_push_object(ctx);
- h = duk_get_hobject(ctx, -1);
- DUK_ASSERT(h != NULL);
- duk_insert(ctx, -3);
-
- /* [ ... regexp_object escaped_source bytecode ] */
-
- DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
- DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
-
- duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
-
- /* [ ... regexp_object escaped_source ] */
-
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_SOURCE, DUK_PROPDESC_FLAGS_NONE);
-
- /* [ ... regexp_object ] */
-
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_GLOBAL));
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_GLOBAL, DUK_PROPDESC_FLAGS_NONE);
-
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_IGNORE_CASE, DUK_PROPDESC_FLAGS_NONE);
-
- duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_MULTILINE));
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_MULTILINE, DUK_PROPDESC_FLAGS_NONE);
-
- duk_push_int(ctx, 0);
- duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
-
- /* [ ... regexp_object ] */
-}
-
-#undef DUK__RE_BUFLEN
-
-#else /* DUK_USE_REGEXP_SUPPORT */
-
-/* regexp support disabled */
-
-#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_regexp_executor.c"
-/*
- * Regexp executor.
- *
- * Safety: the Ecmascript executor should prevent user from reading and
- * replacing regexp bytecode. Even so, the executor must validate all
- * memory accesses etc. When an invalid access is detected (e.g. a 'save'
- * opcode to invalid, unallocated index) it should fail with an internal
- * error but not cause a segmentation fault.
- *
- * Notes:
- *
- * - Backtrack counts are limited to unsigned 32 bits but should
- * technically be duk_size_t for strings longer than 4G chars.
- * This also requires a regexp bytecode change.
- */
-
-/* include removed: duk_internal.h */
-
-#ifdef DUK_USE_REGEXP_SUPPORT
-
-/*
- * Helpers for UTF-8 handling
- *
- * For bytecode readers the duk_uint32_t and duk_int32_t types are correct
- * because they're used for more than just codepoints.
- */
-
-DUK_LOCAL duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
- return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
-}
-
-DUK_LOCAL duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
- duk_uint32_t t;
-
- /* signed integer encoding needed to work with UTF-8 */
- t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
- if (t & 1) {
- return -((duk_int32_t) (t >> 1));
- } else {
- return (duk_int32_t) (t >> 1);
- }
-}
-
-DUK_LOCAL const duk_uint8_t *duk__utf8_backtrack(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) {
- const duk_uint8_t *p;
-
- /* Note: allow backtracking from p == ptr_end */
- p = *ptr;
- if (p < ptr_start || p > ptr_end) {
- goto fail;
- }
-
- while (count > 0) {
- for (;;) {
- p--;
- if (p < ptr_start) {
- goto fail;
- }
- if ((*p & 0xc0) != 0x80) {
- /* utf-8 continuation bytes have the form 10xx xxxx */
- break;
- }
- }
- count--;
- }
- *ptr = p;
- return p;
-
- fail:
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- return NULL; /* never here */
-}
-
-DUK_LOCAL const duk_uint8_t *duk__utf8_advance(duk_hthread *thr, const duk_uint8_t **ptr, const duk_uint8_t *ptr_start, const duk_uint8_t *ptr_end, duk_uint_fast32_t count) {
- const duk_uint8_t *p;
-
- p = *ptr;
- if (p < ptr_start || p >= ptr_end) {
- goto fail;
- }
-
- while (count > 0) {
- for (;;) {
- p++;
-
- /* Note: if encoding ends by hitting end of input, we don't check that
- * the encoding is valid, we just assume it is.
- */
- if (p >= ptr_end || ((*p & 0xc0) != 0x80)) {
- /* utf-8 continuation bytes have the form 10xx xxxx */
- break;
- }
- }
- count--;
- }
-
- *ptr = p;
- return p;
-
- fail:
- DUK_ERROR_INTERNAL_DEFMSG(thr);
- return NULL; /* never here */
-}
-
-/*
- * Helpers for dealing with the input string
- */
-
-/* Get a (possibly canonicalized) input character from current sp. The input
- * itself is never modified, and captures always record non-canonicalized
- * characters even in case-insensitive matching.
- */
-DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) {
- duk_codepoint_t res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
- if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
- res = duk_unicode_re_canonicalize_char(re_ctx->thr, res);
- }
- return res;
-}
-
-DUK_LOCAL const duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp, duk_uint_fast32_t count) {
- return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count);
-}
-
-/* Backtrack utf-8 input and return a (possibly canonicalized) input character. */
-DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *sp) {
- /* note: caller 'sp' is intentionally not updated here */
- (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1);
- return duk__inp_get_cp(re_ctx, &sp);
-}
-
-/*
- * Regexp recursive matching function.
- *
- * Returns 'sp' on successful match (points to character after last matched one),
- * NULL otherwise.
- *
- * The C recursion depth limit check is only performed in this function, this
- * suffices because the function is present in all true recursion required by
- * regexp execution.
- */
-
-DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) {
- if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
- DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT);
- }
- re_ctx->recursion_depth++;
-
- for (;;) {
- duk_small_int_t op;
-
- if (re_ctx->steps_count >= re_ctx->steps_limit) {
- DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT);
- }
- re_ctx->steps_count++;
-
- op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc);
-
- DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld",
- (long) re_ctx->recursion_depth,
- (long) re_ctx->steps_count,
- (long) (pc - re_ctx->bytecode),
- (long) (sp - re_ctx->input),
- (long) op));
-
- switch (op) {
- case DUK_REOP_MATCH: {
- goto match;
- }
- case DUK_REOP_CHAR: {
- /*
- * Byte-based matching would be possible for case-sensitive
- * matching but not for case-insensitive matching. So, we
- * match by decoding the input and bytecode character normally.
- *
- * Bytecode characters are assumed to be already canonicalized.
- * Input characters are canonicalized automatically by
- * duk__inp_get_cp() if necessary.
- *
- * There is no opcode for matching multiple characters. The
- * regexp compiler has trouble joining strings efficiently
- * during compilation. See doc/regexp.rst for more discussion.
- */
- duk_codepoint_t c1, c2;
-
- c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
- DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) ||
- c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1)); /* canonicalized by compiler */
- if (sp >= re_ctx->input_end) {
- goto fail;
- }
- c2 = duk__inp_get_cp(re_ctx, &sp);
- DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld", (long) c1, (long) c2));
- if (c1 != c2) {
- goto fail;
- }
- break;
- }
- case DUK_REOP_PERIOD: {
- duk_codepoint_t c;
-
- if (sp >= re_ctx->input_end) {
- goto fail;
- }
- c = duk__inp_get_cp(re_ctx, &sp);
- if (duk_unicode_is_line_terminator(c)) {
- /* E5 Sections 15.10.2.8, 7.3 */
- goto fail;
- }
- break;
- }
- case DUK_REOP_RANGES:
- case DUK_REOP_INVRANGES: {
- duk_uint32_t n;
- duk_codepoint_t c;
- duk_small_int_t match;
-
- n = duk__bc_get_u32(re_ctx, &pc);
- if (sp >= re_ctx->input_end) {
- goto fail;
- }
- c = duk__inp_get_cp(re_ctx, &sp);
-
- match = 0;
- while (n) {
- duk_codepoint_t r1, r2;
- r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
- r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
- DUK_DDD(DUK_DDDPRINT("matching ranges/invranges, n=%ld, r1=%ld, r2=%ld, c=%ld",
- (long) n, (long) r1, (long) r2, (long) c));
- if (c >= r1 && c <= r2) {
- /* Note: don't bail out early, we must read all the ranges from
- * bytecode. Another option is to skip them efficiently after
- * breaking out of here. Prefer smallest code.
- */
- match = 1;
- }
- n--;
- }
-
- if (op == DUK_REOP_RANGES) {
- if (!match) {
- goto fail;
- }
- } else {
- DUK_ASSERT(op == DUK_REOP_INVRANGES);
- if (match) {
- goto fail;
- }
- }
- break;
- }
- case DUK_REOP_ASSERT_START: {
- duk_codepoint_t c;
-
- if (sp <= re_ctx->input) {
- break;
- }
- if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
- goto fail;
- }
- c = duk__inp_get_prev_cp(re_ctx, sp);
- if (duk_unicode_is_line_terminator(c)) {
- /* E5 Sections 15.10.2.8, 7.3 */
- break;
- }
- goto fail;
- }
- case DUK_REOP_ASSERT_END: {
- duk_codepoint_t c;
- const duk_uint8_t *tmp_sp;
-
- if (sp >= re_ctx->input_end) {
- break;
- }
- if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
- goto fail;
- }
- tmp_sp = sp;
- c = duk__inp_get_cp(re_ctx, &tmp_sp);
- if (duk_unicode_is_line_terminator(c)) {
- /* E5 Sections 15.10.2.8, 7.3 */
- break;
- }
- goto fail;
- }
- case DUK_REOP_ASSERT_WORD_BOUNDARY:
- case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: {
- /*
- * E5 Section 15.10.2.6. The previous and current character
- * should -not- be canonicalized as they are now. However,
- * canonicalization does not affect the result of IsWordChar()
- * (which depends on Unicode characters never canonicalizing
- * into ASCII characters) so this does not matter.
- */
- duk_small_int_t w1, w2;
-
- if (sp <= re_ctx->input) {
- w1 = 0; /* not a wordchar */
- } else {
- duk_codepoint_t c;
- c = duk__inp_get_prev_cp(re_ctx, sp);
- w1 = duk_unicode_re_is_wordchar(c);
- }
- if (sp >= re_ctx->input_end) {
- w2 = 0; /* not a wordchar */
- } else {
- const duk_uint8_t *tmp_sp = sp; /* dummy so sp won't get updated */
- duk_codepoint_t c;
- c = duk__inp_get_cp(re_ctx, &tmp_sp);
- w2 = duk_unicode_re_is_wordchar(c);
- }
-
- if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) {
- if (w1 == w2) {
- goto fail;
- }
- } else {
- DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
- if (w1 != w2) {
- goto fail;
- }
- }
- break;
- }
- case DUK_REOP_JUMP: {
- duk_int32_t skip;
-
- skip = duk__bc_get_i32(re_ctx, &pc);
- pc += skip;
- break;
- }
- case DUK_REOP_SPLIT1: {
- /* split1: prefer direct execution (no jump) */
- const duk_uint8_t *sub_sp;
- duk_int32_t skip;
-
- skip = duk__bc_get_i32(re_ctx, &pc);
- sub_sp = duk__match_regexp(re_ctx, pc, sp);
- if (sub_sp) {
- sp = sub_sp;
- goto match;
- }
- pc += skip;
- break;
- }
- case DUK_REOP_SPLIT2: {
- /* split2: prefer jump execution (not direct) */
- const duk_uint8_t *sub_sp;
- duk_int32_t skip;
-
- skip = duk__bc_get_i32(re_ctx, &pc);
- sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
- if (sub_sp) {
- sp = sub_sp;
- goto match;
- }
- break;
- }
- case DUK_REOP_SQMINIMAL: {
- duk_uint32_t q, qmin, qmax;
- duk_int32_t skip;
- const duk_uint8_t *sub_sp;
-
- qmin = duk__bc_get_u32(re_ctx, &pc);
- qmax = duk__bc_get_u32(re_ctx, &pc);
- skip = duk__bc_get_i32(re_ctx, &pc);
- DUK_DDD(DUK_DDDPRINT("minimal quantifier, qmin=%lu, qmax=%lu, skip=%ld",
- (unsigned long) qmin, (unsigned long) qmax, (long) skip));
-
- q = 0;
- while (q <= qmax) {
- if (q >= qmin) {
- sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
- if (sub_sp) {
- sp = sub_sp;
- goto match;
- }
- }
- sub_sp = duk__match_regexp(re_ctx, pc, sp);
- if (!sub_sp) {
- break;
- }
- sp = sub_sp;
- q++;
- }
- goto fail;
- }
- case DUK_REOP_SQGREEDY: {
- duk_uint32_t q, qmin, qmax, atomlen;
- duk_int32_t skip;
- const duk_uint8_t *sub_sp;
-
- qmin = duk__bc_get_u32(re_ctx, &pc);
- qmax = duk__bc_get_u32(re_ctx, &pc);
- atomlen = duk__bc_get_u32(re_ctx, &pc);
- skip = duk__bc_get_i32(re_ctx, &pc);
- DUK_DDD(DUK_DDDPRINT("greedy quantifier, qmin=%lu, qmax=%lu, atomlen=%lu, skip=%ld",
- (unsigned long) qmin, (unsigned long) qmax, (unsigned long) atomlen, (long) skip));
-
- q = 0;
- while (q < qmax) {
- sub_sp = duk__match_regexp(re_ctx, pc, sp);
- if (!sub_sp) {
- break;
- }
- sp = sub_sp;
- q++;
- }
- while (q >= qmin) {
- sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
- if (sub_sp) {
- sp = sub_sp;
- goto match;
- }
- if (q == qmin) {
- break;
- }
-
- /* Note: if atom were to contain e.g. captures, we would need to
- * re-match the atom to get correct captures. Simply quantifiers
- * do not allow captures in their atom now, so this is not an issue.
- */
-
- DUK_DDD(DUK_DDDPRINT("greedy quantifier, backtrack %ld characters (atomlen)",
- (long) atomlen));
- sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen);
- q--;
- }
- goto fail;
- }
- case DUK_REOP_SAVE: {
- duk_uint32_t idx;
- const duk_uint8_t *old;
- const duk_uint8_t *sub_sp;
-
- idx = duk__bc_get_u32(re_ctx, &pc);
- if (idx >= re_ctx->nsaved) {
- /* idx is unsigned, < 0 check is not necessary */
- DUK_D(DUK_DPRINT("internal error, regexp save index insane: idx=%ld", (long) idx));
- goto internal_error;
- }
- old = re_ctx->saved[idx];
- re_ctx->saved[idx] = sp;
- sub_sp = duk__match_regexp(re_ctx, pc, sp);
- if (sub_sp) {
- sp = sub_sp;
- goto match;
- }
- re_ctx->saved[idx] = old;
- goto fail;
- }
- case DUK_REOP_WIPERANGE: {
- /* Wipe capture range and save old values for backtracking.
- *
- * XXX: this typically happens with a relatively small idx_count.
- * It might be useful to handle cases where the count is small
- * (say <= 8) by saving the values in stack instead. This would
- * reduce memory churn and improve performance, at the cost of a
- * slightly higher code footprint.
- */
- duk_uint32_t idx_start, idx_count;
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- duk_uint32_t idx_end, idx;
-#endif
- duk_uint8_t **range_save;
- const duk_uint8_t *sub_sp;
-
- idx_start = duk__bc_get_u32(re_ctx, &pc);
- idx_count = duk__bc_get_u32(re_ctx, &pc);
- DUK_DDD(DUK_DDDPRINT("wipe saved range: start=%ld, count=%ld -> [%ld,%ld] (captures [%ld,%ld])",
- (long) idx_start, (long) idx_count,
- (long) idx_start, (long) (idx_start + idx_count - 1),
- (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
- if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) {
- /* idx is unsigned, < 0 check is not necessary */
- DUK_D(DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%ld, idx_count=%ld",
- (long) idx_start, (long) idx_count));
- goto internal_error;
- }
- DUK_ASSERT(idx_count > 0);
-
- duk_require_stack((duk_context *) re_ctx->thr, 1);
- range_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
- sizeof(duk_uint8_t *) * idx_count);
- DUK_ASSERT(range_save != NULL);
- DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- idx_end = idx_start + idx_count;
- for (idx = idx_start; idx < idx_end; idx++) {
- re_ctx->saved[idx] = NULL;
- }
-#else
- DUK_MEMZERO((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count);
-#endif
-
- sub_sp = duk__match_regexp(re_ctx, pc, sp);
- if (sub_sp) {
- /* match: keep wiped/resaved values */
- DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
- (long) idx_start, (long) (idx_start + idx_count - 1),
- (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
- duk_pop((duk_context *) re_ctx->thr);
- sp = sub_sp;
- goto match;
- }
-
- /* fail: restore saves */
- DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
- (long) idx_start, (long) (idx_start + idx_count - 1),
- (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
- DUK_MEMCPY((void *) (re_ctx->saved + idx_start),
- (const void *) range_save,
- sizeof(duk_uint8_t *) * idx_count);
- duk_pop((duk_context *) re_ctx->thr);
- goto fail;
- }
- case DUK_REOP_LOOKPOS:
- case DUK_REOP_LOOKNEG: {
- /*
- * Needs a save of multiple saved[] entries depending on what range
- * may be overwritten. Because the regexp parser does no such analysis,
- * we currently save the entire saved array here. Lookaheads are thus
- * a bit expensive. Note that the saved array is not needed for just
- * the lookahead sub-match, but for the matching of the entire sequel.
- *
- * The temporary save buffer is pushed on to the valstack to handle
- * errors correctly. Each lookahead causes a C recursion and pushes
- * more stuff on the value stack. If the C recursion limit is less
- * than the value stack spare, there is no need to check the stack.
- * We do so regardless, just in case.
- */
-
- duk_int32_t skip;
- duk_uint8_t **full_save;
- const duk_uint8_t *sub_sp;
-
- DUK_ASSERT(re_ctx->nsaved > 0);
-
- duk_require_stack((duk_context *) re_ctx->thr, 1);
- full_save = (duk_uint8_t **) duk_push_fixed_buffer((duk_context *) re_ctx->thr,
- sizeof(duk_uint8_t *) * re_ctx->nsaved);
- DUK_ASSERT(full_save != NULL);
- DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
-
- skip = duk__bc_get_i32(re_ctx, &pc);
- sub_sp = duk__match_regexp(re_ctx, pc, sp);
- if (op == DUK_REOP_LOOKPOS) {
- if (!sub_sp) {
- goto lookahead_fail;
- }
- } else {
- if (sub_sp) {
- goto lookahead_fail;
- }
- }
- sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
- if (sub_sp) {
- /* match: keep saves */
- duk_pop((duk_context *) re_ctx->thr);
- sp = sub_sp;
- goto match;
- }
-
- /* fall through */
-
- lookahead_fail:
- /* fail: restore saves */
- DUK_MEMCPY((void *) re_ctx->saved,
- (const void *) full_save,
- sizeof(duk_uint8_t *) * re_ctx->nsaved);
- duk_pop((duk_context *) re_ctx->thr);
- goto fail;
- }
- case DUK_REOP_BACKREFERENCE: {
- /*
- * Byte matching for back-references would be OK in case-
- * sensitive matching. In case-insensitive matching we need
- * to canonicalize characters, so back-reference matching needs
- * to be done with codepoints instead. So, we just decode
- * everything normally here, too.
- *
- * Note: back-reference index which is 0 or higher than
- * NCapturingParens (= number of capturing parens in the
- * -entire- regexp) is a compile time error. However, a
- * backreference referring to a valid capture which has
- * not matched anything always succeeds! See E5 Section
- * 15.10.2.9, step 5, sub-step 3.
- */
- duk_uint32_t idx;
- const duk_uint8_t *p;
-
- idx = duk__bc_get_u32(re_ctx, &pc);
- idx = idx << 1; /* backref n -> saved indices [n*2, n*2+1] */
- if (idx < 2 || idx + 1 >= re_ctx->nsaved) {
- /* regexp compiler should catch these */
- DUK_D(DUK_DPRINT("internal error, backreference index insane"));
- goto internal_error;
- }
- if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) {
- /* capture is 'undefined', always matches! */
- DUK_DDD(DUK_DDDPRINT("backreference: saved[%ld,%ld] not complete, always match",
- (long) idx, (long) (idx + 1)));
- break;
- }
- DUK_DDD(DUK_DDDPRINT("backreference: match saved[%ld,%ld]", (long) idx, (long) (idx + 1)));
-
- p = re_ctx->saved[idx];
- while (p < re_ctx->saved[idx+1]) {
- duk_codepoint_t c1, c2;
-
- /* Note: not necessary to check p against re_ctx->input_end:
- * the memory access is checked by duk__inp_get_cp(), while
- * valid compiled regexps cannot write a saved[] entry
- * which points to outside the string.
- */
- if (sp >= re_ctx->input_end) {
- goto fail;
- }
- c1 = duk__inp_get_cp(re_ctx, &p);
- c2 = duk__inp_get_cp(re_ctx, &sp);
- if (c1 != c2) {
- goto fail;
- }
- }
- break;
- }
- default: {
- DUK_D(DUK_DPRINT("internal error, regexp opcode error: %ld", (long) op));
- goto internal_error;
- }
- }
- }
-
- match:
- re_ctx->recursion_depth--;
- return sp;
-
- fail:
- re_ctx->recursion_depth--;
- return NULL;
-
- internal_error:
- DUK_ERROR_INTERNAL_DEFMSG(re_ctx->thr);
- return NULL; /* never here */
-}
-
-/*
- * Exposed matcher function which provides the semantics of RegExp.prototype.exec().
- *
- * RegExp.prototype.test() has the same semantics as exec() but does not return the
- * result object (which contains the matching string and capture groups). Currently
- * there is no separate test() helper, so a temporary result object is created and
- * discarded if test() is needed. This is intentional, to save code space.
- *
- * Input stack: [ ... re_obj input ]
- * Output stack: [ ... result ]
- */
-
-DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
- duk_context *ctx = (duk_context *) thr;
- duk_re_matcher_ctx re_ctx;
- duk_hobject *h_regexp;
- duk_hstring *h_bytecode;
- duk_hstring *h_input;
- const duk_uint8_t *pc;
- const duk_uint8_t *sp;
- duk_small_int_t match = 0;
- duk_small_int_t global;
- duk_uint_fast32_t i;
- double d;
- duk_uint32_t char_offset;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(ctx != NULL);
-
- DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T",
- (duk_tval *) duk_get_tval(ctx, -2),
- (duk_tval *) duk_get_tval(ctx, -1)));
-
- /*
- * Regexp instance check, bytecode check, input coercion.
- *
- * See E5 Section 15.10.6.
- */
-
- /* TypeError if wrong; class check, see E5 Section 15.10.6 */
- h_regexp = duk_require_hobject_with_class(ctx, -2, DUK_HOBJECT_CLASS_REGEXP);
- DUK_ASSERT(h_regexp != NULL);
- DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
- DUK_UNREF(h_regexp);
-
- duk_to_string(ctx, -1);
- h_input = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_input != NULL);
-
- duk_get_prop_stridx(ctx, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
- h_bytecode = duk_require_hstring(ctx, -1); /* no regexp instance should exist without a non-configurable bytecode property */
- DUK_ASSERT(h_bytecode != NULL);
-
- /*
- * Basic context initialization.
- *
- * Some init values are read from the bytecode header
- * whose format is (UTF-8 codepoints):
- *
- * uint flags
- * uint nsaved (even, 2n+2 where n = num captures)
- */
-
- /* [ ... re_obj input bc ] */
-
- DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
-
- re_ctx.thr = thr;
- re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
- re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input);
- re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
- re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode);
- re_ctx.saved = NULL;
- re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT;
- re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT;
-
- /* read header */
- pc = re_ctx.bytecode;
- re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc);
- re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc);
- re_ctx.bytecode = pc;
-
- DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */
- global = (duk_small_int_t) (force_global | (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
-
- DUK_ASSERT(re_ctx.nsaved >= 2);
- DUK_ASSERT((re_ctx.nsaved % 2) == 0);
-
- duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved);
- re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(ctx, -1, NULL);
- DUK_ASSERT(re_ctx.saved != NULL);
-
- /* [ ... re_obj input bc saved_buf ] */
-
- /* buffer is automatically zeroed */
-#ifdef DUK_USE_EXPLICIT_NULL_INIT
- for (i = 0; i < re_ctx.nsaved; i++) {
- re_ctx.saved[i] = (duk_uint8_t *) NULL;
- }
-#endif
-
- DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld",
- (unsigned long) re_ctx.re_flags, (long) re_ctx.nsaved, (long) re_ctx.recursion_limit,
- (long) re_ctx.steps_limit));
-
- /*
- * Get starting character offset for match, and initialize 'sp' based on it.
- *
- * Note: lastIndex is non-configurable so it must be present (we check the
- * internal class of the object above, so we know it is). User code can set
- * its value to an arbitrary (garbage) value though; E5 requires that lastIndex
- * be coerced to a number before using. The code below works even if the
- * property is missing: the value will then be coerced to zero.
- *
- * Note: lastIndex may be outside Uint32 range even after ToInteger() coercion.
- * For instance, ToInteger(+Infinity) = +Infinity. We track the match offset
- * as an integer, but pre-check it to be inside the 32-bit range before the loop.
- * If not, the check in E5 Section 15.10.6.2, step 9.a applies.
- */
-
- /* XXX: lastIndex handling produces a lot of asm */
-
- /* [ ... re_obj input bc saved_buf ] */
-
- duk_get_prop_stridx(ctx, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
- (void) duk_to_int(ctx, -1); /* ToInteger(lastIndex) */
- d = duk_get_number(ctx, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
- duk_pop(ctx);
-
- if (global) {
- if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
- /* match fail */
- char_offset = 0; /* not really necessary */
- DUK_ASSERT(match == 0);
- goto match_over;
- }
- char_offset = (duk_uint32_t) d;
- } else {
- /* lastIndex must be ignored for non-global regexps, but get the
- * value for (theoretical) side effects. No side effects can
- * really occur, because lastIndex is a normal property and is
- * always non-configurable for RegExp instances.
- */
- char_offset = (duk_uint32_t) 0;
- }
-
- sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset);
-
- /*
- * Match loop.
- *
- * Try matching at different offsets until match found or input exhausted.
- */
-
- /* [ ... re_obj input bc saved_buf ] */
-
- DUK_ASSERT(match == 0);
-
- for (;;) {
- /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */
- DUK_ASSERT_DISABLE(char_offset >= 0);
- DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
-
- /* Note: ctx.steps is intentionally not reset, it applies to the entire unanchored match */
- DUK_ASSERT(re_ctx.recursion_depth == 0);
-
- DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
- (long) char_offset, (const void *) sp,
- (const void *) re_ctx.input, (const void *) re_ctx.input_end));
-
- /*
- * Note:
- *
- * - duk__match_regexp() is required not to longjmp() in ordinary "non-match"
- * conditions; a longjmp() will terminate the entire matching process.
- *
- * - Clearing saved[] is not necessary because backtracking does it
- *
- * - Backtracking also rewinds ctx.recursion back to zero, unless an
- * internal/limit error occurs (which causes a longjmp())
- *
- * - If we supported anchored matches, we would break out here
- * unconditionally; however, Ecmascript regexps don't have anchored
- * matches. It might make sense to implement a fast bail-out if
- * the regexp begins with '^' and sp is not 0: currently we'll just
- * run through the entire input string, trivially failing the match
- * at every non-zero offset.
- */
-
- if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) {
- DUK_DDD(DUK_DDDPRINT("match at offset %ld", (long) char_offset));
- match = 1;
- break;
- }
-
- /* advance by one character (code point) and one char_offset */
- char_offset++;
- if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) {
- /*
- * Note:
- *
- * - Intentionally attempt (empty) match at char_offset == k_input->clen
- *
- * - Negative char_offsets have been eliminated and char_offset is duk_uint32_t
- * -> no need or use for a negative check
- */
-
- DUK_DDD(DUK_DDDPRINT("no match after trying all sp offsets"));
- break;
- }
-
- /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */
- (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1);
- }
-
- match_over:
-
- /*
- * Matching complete, create result array or return a 'null'. Update lastIndex
- * if necessary. See E5 Section 15.10.6.2.
- *
- * Because lastIndex is a character (not byte) offset, we need the character
- * length of the match which we conveniently get as a side effect of interning
- * the matching substring (0th index of result array).
- *
- * saved[0] start pointer (~ byte offset) of current match
- * saved[1] end pointer (~ byte offset) of current match (exclusive)
- * char_offset start character offset of current match (-> .index of result)
- * char_end_offset end character offset (computed below)
- */
-
- /* [ ... re_obj input bc saved_buf ] */
-
- if (match) {
-#ifdef DUK_USE_ASSERTIONS
- duk_hobject *h_res;
-#endif
- duk_uint32_t char_end_offset = 0;
-
- DUK_DDD(DUK_DDDPRINT("regexp matches at char_offset %ld", (long) char_offset));
-
- DUK_ASSERT(re_ctx.nsaved >= 2); /* must have start and end */
- DUK_ASSERT((re_ctx.nsaved % 2) == 0); /* and even number */
-
- /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken
- * advantage of now. The array is not compacted either, as regexp match
- * objects are usually short lived.
- */
-
- duk_push_array(ctx);
-
-#ifdef DUK_USE_ASSERTIONS
- h_res = duk_require_hobject(ctx, -1);
- DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
- DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res));
- DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
-#endif
-
- /* [ ... re_obj input bc saved_buf res_obj ] */
-
- duk_push_u32(ctx, char_offset);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INDEX);
-
- duk_dup(ctx, -4);
- duk_xdef_prop_stridx_wec(ctx, -2, DUK_STRIDX_INPUT);
-
- for (i = 0; i < re_ctx.nsaved; i += 2) {
- /* Captures which are undefined have NULL pointers and are returned
- * as 'undefined'. The same is done when saved[] pointers are insane
- * (this should, of course, never happen in practice).
- */
- if (re_ctx.saved[i] && re_ctx.saved[i+1] && re_ctx.saved[i+1] >= re_ctx.saved[i]) {
- duk_hstring *h_saved;
-
- duk_push_lstring(ctx,
- (const char *) re_ctx.saved[i],
- (duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
- h_saved = duk_get_hstring(ctx, -1);
- DUK_ASSERT(h_saved != NULL);
-
- if (i == 0) {
- /* Assumes that saved[0] and saved[1] are always
- * set by regexp bytecode (if not, char_end_offset
- * will be zero). Also assumes clen reflects the
- * correct char length.
- */
- char_end_offset = char_offset + DUK_HSTRING_GET_CHARLEN(h_saved);
- }
- } else {
- duk_push_undefined(ctx);
- }
-
- /* [ ... re_obj input bc saved_buf res_obj val ] */
- duk_put_prop_index(ctx, -2, i / 2);
- }
-
- /* [ ... re_obj input bc saved_buf res_obj ] */
-
- /* NB: 'length' property is automatically updated by the array setup loop */
-
- if (global) {
- /* global regexp: lastIndex updated on match */
- duk_push_u32(ctx, char_end_offset);
- duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
- } else {
- /* non-global regexp: lastIndex never updated on match */
- ;
- }
- } else {
- /*
- * No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless
- * of 'global' flag of the RegExp. In particular, if lastIndex is invalid
- * initially, it is reset to zero.
- */
-
- DUK_DDD(DUK_DDDPRINT("regexp does not match"));
-
- duk_push_null(ctx);
-
- /* [ ... re_obj input bc saved_buf res_obj ] */
-
- duk_push_int(ctx, 0);
- duk_put_prop_stridx(ctx, -6, DUK_STRIDX_LAST_INDEX);
- }
-
- /* [ ... re_obj input bc saved_buf res_obj ] */
-
- duk_insert(ctx, -5);
-
- /* [ ... res_obj re_obj input bc saved_buf ] */
-
- duk_pop_n(ctx, 4);
-
- /* [ ... res_obj ] */
-
- /* XXX: these last tricks are unnecessary if the function is made
- * a genuine native function.
- */
-}
-
-DUK_INTERNAL void duk_regexp_match(duk_hthread *thr) {
- duk__regexp_match_helper(thr, 0 /*force_global*/);
-}
-
-/* This variant is needed by String.prototype.split(); it needs to perform
- * global-style matching on a cloned RegExp which is potentially non-global.
- */
-DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
- duk__regexp_match_helper(thr, 1 /*force_global*/);
-}
-
-#else /* DUK_USE_REGEXP_SUPPORT */
-
-/* regexp support disabled */
-
-#endif /* DUK_USE_REGEXP_SUPPORT */
-#line 1 "duk_selftest.c"
-/*
- * Self tests to ensure execution environment is sane. Intended to catch
- * compiler/platform problems which cannot be detected at compile time.
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_SELF_TESTS)
-
-/*
- * Unions and structs for self tests
- */
-
-typedef union {
- double d;
- duk_uint8_t c[8];
-} duk__test_double_union;
-
-#define DUK__DBLUNION_CMP_TRUE(a,b) do { \
- if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares false (expected true)"); \
- } \
- } while (0)
-
-#define DUK__DBLUNION_CMP_FALSE(a,b) do { \
- if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double union compares true (expected false)"); \
- } \
- } while (0)
-
-typedef union {
- duk_uint32_t i;
- duk_uint8_t c[8];
-} duk__test_u32_union;
-
-/*
- * Various sanity checks for typing
- */
-
-DUK_LOCAL void duk__selftest_types(void) {
- if (!(sizeof(duk_int8_t) == 1 &&
- sizeof(duk_uint8_t) == 1 &&
- sizeof(duk_int16_t) == 2 &&
- sizeof(duk_uint16_t) == 2 &&
- sizeof(duk_int32_t) == 4 &&
- sizeof(duk_uint32_t) == 4)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int{8,16,32}_t size");
- }
-#if defined(DUK_USE_64BIT_OPS)
- if (!(sizeof(duk_int64_t) == 8 &&
- sizeof(duk_uint64_t) == 8)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_(u)int64_t size");
- }
-#endif
-
- if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) {
- /* Some internal code now assumes that all duk_uint_t values
- * can be expressed with a duk_size_t.
- */
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_size_t is smaller than duk_uint_t");
- }
- if (!(sizeof(duk_int_t) >= 4)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_int_t is not 32 bits");
- }
-}
-
-/*
- * Packed tval sanity
- */
-
-DUK_LOCAL void duk__selftest_packed_tval(void) {
-#if defined(DUK_USE_PACKED_TVAL)
- if (sizeof(void *) > 4) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: packed duk_tval in use but sizeof(void *) > 4");
- }
-#endif
-}
-
-/*
- * Two's complement arithmetic.
- */
-
-DUK_LOCAL void duk__selftest_twos_complement(void) {
- volatile int test;
- test = -1;
-
- /* Note that byte order doesn't affect this test: all bytes in
- * 'test' will be 0xFF for two's complement.
- */
- if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: two's complement arithmetic");
- }
-}
-
-/*
- * Byte order. Important to self check, because on some exotic platforms
- * there is no actual detection but rather assumption based on platform
- * defines.
- */
-
-DUK_LOCAL void duk__selftest_byte_order(void) {
- duk__test_u32_union u1;
- duk__test_double_union u2;
-
- /*
- * >>> struct.pack('>d', 102030405060).encode('hex')
- * '4237c17c6dc40000'
- */
-#if defined(DUK_USE_INTEGER_LE)
- u1.c[0] = 0xef; u1.c[1] = 0xbe; u1.c[2] = 0xad; u1.c[3] = 0xde;
-#elif defined(DUK_USE_INTEGER_ME)
-#error integer mixed endian not supported now
-#elif defined(DUK_USE_INTEGER_BE)
- u1.c[0] = 0xde; u1.c[1] = 0xad; u1.c[2] = 0xbe; u1.c[3] = 0xef;
-#else
-#error unknown integer endianness
-#endif
-
-#if defined(DUK_USE_DOUBLE_LE)
- u2.c[0] = 0x00; u2.c[1] = 0x00; u2.c[2] = 0xc4; u2.c[3] = 0x6d;
- u2.c[4] = 0x7c; u2.c[5] = 0xc1; u2.c[6] = 0x37; u2.c[7] = 0x42;
-#elif defined(DUK_USE_DOUBLE_ME)
- u2.c[0] = 0x7c; u2.c[1] = 0xc1; u2.c[2] = 0x37; u2.c[3] = 0x42;
- u2.c[4] = 0x00; u2.c[5] = 0x00; u2.c[6] = 0xc4; u2.c[7] = 0x6d;
-#elif defined(DUK_USE_DOUBLE_BE)
- u2.c[0] = 0x42; u2.c[1] = 0x37; u2.c[2] = 0xc1; u2.c[3] = 0x7c;
- u2.c[4] = 0x6d; u2.c[5] = 0xc4; u2.c[6] = 0x00; u2.c[7] = 0x00;
-#else
-#error unknown double endianness
-#endif
-
- if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: duk_uint32_t byte order");
- }
-
- if (u2.d != (double) 102030405060.0) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double byte order");
- }
-}
-
-/*
- * DUK_BSWAP macros
- */
-
-DUK_LOCAL void duk__selftest_bswap_macros(void) {
- duk_uint32_t x32;
- duk_uint16_t x16;
- duk_double_union du;
- duk_double_t du_diff;
-
- x16 = 0xbeefUL;
- x16 = DUK_BSWAP16(x16);
- if (x16 != (duk_uint16_t) 0xefbeUL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP16");
- }
-
- x32 = 0xdeadbeefUL;
- x32 = DUK_BSWAP32(x32);
- if (x32 != (duk_uint32_t) 0xefbeaddeUL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_BSWAP32");
- }
-
- /* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
- * (2.008366013071895,)
- */
-
- du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22;
- du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66;
- DUK_DBLUNION_DOUBLE_NTOH(&du);
- du_diff = du.d - 2.008366013071895;
-#if 0
- DUK_FPRINTF(DUK_STDERR, "du_diff: %lg\n", (double) du_diff);
-#endif
- if (du_diff > 1e-15) {
- /* Allow very small lenience because some compilers won't parse
- * exact IEEE double constants (happened in matrix testing with
- * Linux gcc-4.8 -m32 at least).
- */
-#if 0
- DUK_FPRINTF(DUK_STDERR, "Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- (unsigned int) du.uc[0], (unsigned int) du.uc[1],
- (unsigned int) du.uc[2], (unsigned int) du.uc[3],
- (unsigned int) du.uc[4], (unsigned int) du.uc[5],
- (unsigned int) du.uc[6], (unsigned int) du.uc[7]);
-#endif
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: DUK_DBLUNION_DOUBLE_NTOH");
- }
-}
-
-/*
- * Basic double / byte union memory layout.
- */
-
-DUK_LOCAL void duk__selftest_double_union_size(void) {
- if (sizeof(duk__test_double_union) != 8) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: invalid union size");
- }
-}
-
-/*
- * Union aliasing, see misc/clang_aliasing.c.
- */
-
-DUK_LOCAL void duk__selftest_double_aliasing(void) {
- duk__test_double_union a, b;
-
- /* This testcase fails when Emscripten-generated code runs on Firefox.
- * It's not an issue because the failure should only affect packed
- * duk_tval representation, which is not used with Emscripten.
- */
-#if !defined(DUK_USE_PACKED_TVAL)
- DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
- return;
-#endif
-
- /* Test signaling NaN and alias assignment in all endianness combinations.
- */
-
- /* little endian */
- a.c[0] = 0x11; a.c[1] = 0x22; a.c[2] = 0x33; a.c[3] = 0x44;
- a.c[4] = 0x00; a.c[5] = 0x00; a.c[6] = 0xf1; a.c[7] = 0xff;
- b = a;
- DUK__DBLUNION_CMP_TRUE(&a, &b);
-
- /* big endian */
- a.c[0] = 0xff; a.c[1] = 0xf1; a.c[2] = 0x00; a.c[3] = 0x00;
- a.c[4] = 0x44; a.c[5] = 0x33; a.c[6] = 0x22; a.c[7] = 0x11;
- b = a;
- DUK__DBLUNION_CMP_TRUE(&a, &b);
-
- /* mixed endian */
- a.c[0] = 0x00; a.c[1] = 0x00; a.c[2] = 0xf1; a.c[3] = 0xff;
- a.c[4] = 0x11; a.c[5] = 0x22; a.c[6] = 0x33; a.c[7] = 0x44;
- b = a;
- DUK__DBLUNION_CMP_TRUE(&a, &b);
-}
-
-/*
- * Zero sign, see misc/tcc_zerosign2.c.
- */
-
-DUK_LOCAL void duk__selftest_double_zero_sign(void) {
- duk__test_double_union a, b;
-
- a.d = 0.0;
- b.d = -a.d;
- DUK__DBLUNION_CMP_FALSE(&a, &b);
-}
-
-/*
- * Struct size/alignment if platform requires it
- *
- * There are some compiler specific struct padding pragmas etc in use, this
- * selftest ensures they're correctly detected and used.
- */
-
-DUK_LOCAL void duk__selftest_struct_align(void) {
-#if (DUK_USE_ALIGN_BY == 4)
- if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 4");
- }
-#elif (DUK_USE_ALIGN_BY == 8)
- if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: sizeof(duk_hbuffer_fixed) not aligned to 8");
- }
-#elif (DUK_USE_ALIGN_BY == 1)
- /* no check */
-#else
-#error invalid DUK_USE_ALIGN_BY
-#endif
-}
-
-/*
- * 64-bit arithmetic
- *
- * There are some platforms/compilers where 64-bit types are available
- * but don't work correctly. Test for known cases.
- */
-
-DUK_LOCAL void duk__selftest_64bit_arithmetic(void) {
-#if defined(DUK_USE_64BIT_OPS)
- volatile duk_int64_t i;
- volatile duk_double_t d;
-
- /* Catch a double-to-int64 cast issue encountered in practice. */
- d = 2147483648.0;
- i = (duk_int64_t) d;
- if (i != 0x80000000LL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: casting 2147483648.0 to duk_int64_t failed");
- }
-#else
- /* nop */
-#endif
-}
-
-/*
- * Casting
- */
-
-DUK_LOCAL void duk__selftest_cast_double_to_small_uint(void) {
- /*
- * https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
- */
-
- duk_double_t d1, d2;
- duk_small_uint_t u;
-
- duk_double_t d1v, d2v;
- duk_small_uint_t uv;
-
- /* Test without volatiles */
-
- d1 = 1.0;
- u = (duk_small_uint_t) d1;
- d2 = (duk_double_t) u;
-
- if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
- }
-
- /* Same test with volatiles */
-
- d1v = 1.0;
- uv = (duk_small_uint_t) d1v;
- d2v = (duk_double_t) uv;
-
- if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_small_uint_t cast failed");
- }
-}
-
-DUK_LOCAL void duk__selftest_cast_double_to_uint32(void) {
- /*
- * This test fails on an exotic ARM target; double-to-uint
- * cast is incorrectly clamped to -signed- int highest value.
- *
- * https://github.com/svaarala/duktape/issues/336
- */
-
- duk_double_t dv;
- duk_uint32_t uv;
-
- dv = 3735928559.0; /* 0xdeadbeef in decimal */
- uv = (duk_uint32_t) dv;
-
- if (uv != 0xdeadbeefUL) {
- DUK_PANIC(DUK_ERR_INTERNAL_ERROR, "self test failed: double to duk_uint32_t cast failed");
- }
-}
-
-/*
- * Self test main
- */
-
-DUK_INTERNAL void duk_selftest_run_tests(void) {
- duk__selftest_types();
- duk__selftest_packed_tval();
- duk__selftest_twos_complement();
- duk__selftest_byte_order();
- duk__selftest_bswap_macros();
- duk__selftest_double_union_size();
- duk__selftest_double_aliasing();
- duk__selftest_double_zero_sign();
- duk__selftest_struct_align();
- duk__selftest_64bit_arithmetic();
- duk__selftest_cast_double_to_small_uint();
- duk__selftest_cast_double_to_uint32();
-}
-
-#undef DUK__DBLUNION_CMP_TRUE
-#undef DUK__DBLUNION_CMP_FALSE
-
-#endif /* DUK_USE_SELF_TESTS */
-/* include removed: duk_internal.h */
-#line 2 "duk_tval.c"
-
-#if defined(DUK_USE_FASTINT)
-
-/*
- * Manually optimized double-to-fastint downgrade check.
- *
- * This check has a large impact on performance, especially for fastint
- * slow paths, so must be changed carefully. The code should probably be
- * optimized for the case where the result does not fit into a fastint,
- * to minimize the penalty for "slow path code" dealing with fractions etc.
- *
- * At least on one tested soft float ARM platform double-to-int64 coercion
- * is very slow (and sometimes produces incorrect results, see self tests).
- * This algorithm combines a fastint compatibility check and extracting the
- * integer value from an IEEE double for setting the tagged fastint. For
- * other platforms a more naive approach might be better.
- *
- * See doc/fastint.rst for details.
- */
-
-DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast(duk_tval *tv, duk_double_t x) {
- duk_double_union du;
- duk_int64_t i;
- duk_small_int_t expt;
- duk_small_int_t shift;
-
- /* XXX: optimize for packed duk_tval directly? */
-
- du.d = x;
- i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du);
- expt = (duk_small_int_t) ((i >> 52) & 0x07ff);
- shift = expt - 1023;
-
- if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */
- duk_int64_t t;
-
- if (((0x000fffffffffffffLL >> shift) & i) == 0) {
- t = i | 0x0010000000000000LL; /* implicit leading one */
- t = t & 0x001fffffffffffffLL;
- t = t >> (52 - shift);
- if (i < 0) {
- t = -t;
- }
- DUK_TVAL_SET_FASTINT(tv, t);
- return;
- }
- } else if (shift == -1023) { /* exponent 0 */
- if (i >= 0 && (i & 0x000fffffffffffffLL) == 0) {
- /* Note: reject negative zero. */
- DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
- return;
- }
- } else if (shift == 47) { /* exponent 1070 */
- if (i < 0 && (i & 0x000fffffffffffffLL) == 0) {
- DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
- return;
- }
- }
-
- DUK_TVAL_SET_DOUBLE(tv, x);
- return;
-}
-
-/*
- * Manually optimized number-to-double conversion
- */
-
-#if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL)
-DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) {
- duk_double_union du;
- duk_uint64_t t;
-
- t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
- if ((t >> 48) != DUK_TAG_FASTINT) {
- return tv->d;
- } else if (t & 0x0000800000000000ULL) {
- t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */
- t = t & 0x0000ffffffffffffULL; /* negative */
- t |= 0xc330000000000000ULL;
- DUK_DBLUNION_SET_UINT64(&du, t);
- return du.d + 4503599627370496.0; /* 1 << 52 */
- } else if (t != 0) {
- t &= 0x0000ffffffffffffULL; /* positive */
- t |= 0x4330000000000000ULL;
- DUK_DBLUNION_SET_UINT64(&du, t);
- return du.d - 4503599627370496.0; /* 1 << 52 */
- } else {
- return 0.0; /* zero */
- }
-}
-#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
-
-#if 0 /* unused */
-#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
-DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) {
- duk_double_union du;
- duk_uint64_t t;
-
- DUK_ASSERT(tv->t == DUK__TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
-
- if (tv->t == DUK_TAG_FASTINT) {
- if (tv->v.fi >= 0) {
- t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
- DUK_DBLUNION_SET_UINT64(&du, t);
- return du.d - 4503599627370496.0; /* 1 << 52 */
- } else {
- t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
- DUK_DBLUNION_SET_UINT64(&du, t);
- return du.d + 4503599627370496.0; /* 1 << 52 */
- }
- } else {
- return tv->v.d;
- }
-}
-#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
-#endif /* 0 */
-
-#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
-DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) {
- duk_double_union du;
- duk_uint64_t t;
-
- DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
-
- if (tv->v.fi >= 0) {
- t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
- DUK_DBLUNION_SET_UINT64(&du, t);
- return du.d - 4503599627370496.0; /* 1 << 52 */
- } else {
- t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
- DUK_DBLUNION_SET_UINT64(&du, t);
- return du.d + 4503599627370496.0; /* 1 << 52 */
- }
-}
-#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
-
-#endif /* DUK_USE_FASTINT */
-#line 1 "duk_unicode_tables.c"
-/*
- * Unicode support tables automatically generated during build.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Unicode tables containing ranges of Unicode characters in a
- * packed format. These tables are used to match non-ASCII
- * characters of complex productions by resorting to a linear
- * range-by-range comparison. This is very slow, but is expected
- * to be very rare in practical Ecmascript source code, and thus
- * compactness is most important.
- *
- * The tables are matched using uni_range_match() and the format
- * is described in src/extract_chars.py.
- */
-
-#ifdef DUK_USE_SOURCE_NONBMP
-/* IdentifierStart production with ASCII excluded */
-/* duk_unicode_ids_noa[] */
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-const duk_uint8_t duk_unicode_ids_noa[791] = {
-249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
-240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
-18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
-101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
-52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
-240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
-2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
-114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
-240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
-26,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
-205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
-35,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
-180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
-146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
-79,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
-251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
-92,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
-240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
-122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
-74,35,111,25,79,78,240,63,11,242,127,0,255,224,244,255,240,0,138,143,60,
-255,240,4,11,239,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,
-47,9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,
-34,243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
-240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
-240,255,255,0,26,150,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,175,
-24,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,241,
-171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,241,91,47,10,47,3,
-33,46,61,241,79,107,243,127,37,255,223,13,79,33,242,31,15,240,63,11,242,
-127,14,63,20,87,36,241,207,142,255,226,86,83,2,241,194,20,3,240,127,156,
-240,107,240,175,184,15,1,50,34,240,191,30,240,223,117,242,107,240,107,240,
-63,127,243,159,254,42,239,37,243,223,29,255,238,68,255,226,97,248,63,83,
-255,234,145,255,227,33,255,240,2,44,95,254,18,191,255,0,52,187,31,255,0,18,
-242,244,82,243,114,19,3,19,50,178,2,98,243,18,51,114,98,240,194,50,66,4,98,
-255,224,70,63,9,47,9,47,15,47,9,47,15,47,9,47,15,47,9,47,15,47,9,39,255,
-240,1,114,143,255,0,149,201,241,191,254,242,124,252,239,255,0,46,214,255,
-225,16,0,
-};
-#else
-/* IdentifierStart production with ASCII and non-BMP excluded */
-/* duk_unicode_ids_noabmp[] */
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-const duk_uint8_t duk_unicode_ids_noabmp[611] = {
-249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,57,2,34,2,
-240,66,244,50,247,185,248,234,241,99,8,241,127,58,240,182,47,31,241,191,21,
-18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
-101,10,4,15,9,240,159,157,242,100,15,4,8,159,1,98,102,115,19,240,98,98,4,
-52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,2,130,34,
-240,98,98,18,68,15,4,15,1,31,21,115,19,240,98,98,18,68,15,16,18,47,1,15,3,
-2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,146,68,15,12,23,31,21,
-114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,15,3,31,10,86,
-240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,34,2,3,18,50,
-26,3,66,15,7,31,20,15,49,114,241,79,13,79,101,241,191,6,15,2,85,52,4,24,37,
-205,15,3,241,107,241,178,4,255,224,59,35,54,32,35,63,25,35,63,17,35,54,32,
-35,62,47,41,35,63,51,241,127,0,240,47,69,223,254,21,227,240,18,240,166,243,
-180,47,1,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,15,53,244,137,241,
-146,6,243,107,240,223,37,240,227,76,241,207,7,111,42,240,122,242,95,68,15,
-79,241,255,3,111,41,240,238,31,2,241,111,12,241,79,27,43,241,79,93,50,63,0,
-251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,15,63,37,38,32,66,38,67,53,
-92,98,38,246,96,224,240,44,245,112,80,57,32,68,112,32,32,35,42,51,100,80,
-240,63,25,255,233,107,241,242,241,242,247,87,63,3,241,107,242,106,15,2,240,
-122,98,98,98,98,98,98,98,111,66,15,254,12,146,240,184,132,52,95,70,114,47,
-74,35,111,25,79,78,240,63,11,242,127,0,255,224,244,255,240,0,138,143,60,
-255,240,4,11,239,38,255,227,127,243,95,30,63,253,79,0,177,240,111,31,240,
-47,9,159,64,241,152,63,87,51,33,240,9,244,39,34,35,47,7,240,255,36,240,15,
-34,243,5,64,240,15,12,191,7,240,191,13,143,31,240,224,242,47,25,240,146,39,
-240,111,7,64,111,32,32,65,52,48,32,240,162,241,85,53,53,166,38,248,63,19,
-240,255,255,0,26,150,223,7,95,33,255,240,0,255,143,254,2,3,242,227,245,175,
-24,109,70,2,146,194,66,2,18,18,245,207,19,255,224,93,240,79,48,63,38,241,
-171,246,100,47,119,241,111,10,127,10,207,73,69,53,53,50,0,
-};
-#endif
-
-#ifdef DUK_USE_SOURCE_NONBMP
-/* IdentifierStart production with Letter and ASCII excluded */
-/* duk_unicode_ids_m_let_noa[] */
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-const duk_uint8_t duk_unicode_ids_m_let_noa[42] = {
-255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
-249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,48,
-};
-#else
-/* IdentifierStart production with Letter, ASCII, and non-BMP excluded */
-/* duk_unicode_ids_m_let_noabmp[] */
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = {
-255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
-249,0,
-};
-#endif
-
-#ifdef DUK_USE_SOURCE_NONBMP
-/* IdentifierPart production with IdentifierStart and ASCII excluded */
-/* duk_unicode_idp_m_ids_noa[] */
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-const duk_uint8_t duk_unicode_idp_m_ids_noa[397] = {
-255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
-245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
-36,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
-57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
-240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
-242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
-34,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
-53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
-211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
-79,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
-185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
-4,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
-109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
-121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
-240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
-96,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
-240,162,251,41,241,112,255,225,177,15,254,25,105,255,228,75,34,22,63,26,37,
-15,254,75,66,242,126,241,25,240,34,241,250,255,240,10,249,228,69,151,54,
-241,3,248,98,255,228,125,242,47,255,12,23,244,254,0,
-};
-#else
-/* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */
-/* duk_unicode_idp_m_ids_noabmp[] */
-/*
- * Automatically generated by extract_chars.py, do not edit!
- */
-
-const duk_uint8_t duk_unicode_idp_m_ids_noabmp[348] = {
-255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
-245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
-36,241,210,249,99,242,130,47,2,38,177,57,240,50,242,160,38,49,50,160,177,
-57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,97,57,
-240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,240,50,
-242,198,34,35,129,193,57,240,65,242,160,38,34,35,129,193,57,240,65,242,198,
-34,35,160,177,57,240,65,243,128,85,32,39,240,65,242,240,54,215,41,244,144,
-53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,111,4,41,
-211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,241,1,243,
-79,14,160,57,241,50,57,248,16,246,139,91,185,245,47,1,129,121,242,244,242,
-185,47,13,58,121,245,132,242,31,1,201,240,56,210,241,9,105,241,237,242,47,
-4,153,121,246,130,47,5,80,80,251,255,23,240,115,255,225,0,31,35,31,5,15,
-109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,255,0,100,
-121,159,55,13,31,100,31,254,0,64,64,80,240,148,244,161,242,79,1,201,127,2,
-240,9,240,231,240,188,241,227,242,29,240,25,244,29,208,145,57,241,48,242,
-96,34,49,97,32,255,224,21,114,19,159,255,0,62,24,15,254,29,95,0,240,38,209,
-240,162,251,41,241,112,0,
-};
-#endif
-
-/*
- * Case conversion tables generated using src/extract_caseconv.py.
- */
-
-/* duk_unicode_caseconv_uc[] */
-/* duk_unicode_caseconv_lc[] */
-
-/*
- * Automatically generated by extract_caseconv.py, do not edit!
- */
-
-const duk_uint8_t duk_unicode_caseconv_uc[1288] = {
-132,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
-128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30,
-104,28,112,32,67,0,65,4,0,138,0,128,4,1,88,65,76,83,15,128,15,132,8,31,16,
-31,24,12,62,64,62,80,32,124,192,124,224,64,250,0,250,64,97,246,1,246,129,3,
-238,3,247,64,135,220,135,242,2,15,187,15,237,2,31,120,31,248,4,62,244,63,
-212,8,125,240,127,232,16,253,128,253,192,33,253,1,253,128,67,252,3,253,0,
-136,92,8,88,8,18,104,18,91,26,44,48,44,0,94,90,0,33,64,155,253,7,252,132,
-212,0,32,32,32,6,0,76,192,76,129,128,157,0,156,136,1,75,1,74,46,2,244,2,
-242,12,6,12,6,8,16,13,8,13,0,48,27,64,27,48,64,57,192,57,162,0,119,192,119,
-132,128,252,128,252,20,2,35,2,34,18,4,142,4,140,20,13,196,13,192,16,30,200,
-30,192,192,70,16,70,2,32,145,96,145,70,193,48,129,48,67,130,104,130,104,44,
-30,1,30,0,150,61,66,61,64,192,125,68,125,100,33,99,65,99,56,50,200,18,200,
-6,69,157,133,157,96,169,144,105,144,11,211,64,211,64,12,167,35,167,34,15,
-78,103,78,100,126,157,234,157,228,21,59,253,59,240,90,122,26,122,0,163,128,
-214,128,214,2,1,197,1,196,6,3,140,3,136,12,7,200,7,196,16,20,0,13,48,32,63,
-128,63,112,69,142,101,142,64,130,1,136,1,135,4,3,114,3,112,8,26,120,202,
-120,176,65,1,30,1,29,130,2,105,1,150,5,255,96,22,160,115,128,31,224,47,0,
-38,32,9,32,47,224,10,96,48,0,72,96,50,64,50,32,50,160,62,192,51,32,51,0,51,
-64,71,160,51,192,68,0,53,0,52,224,55,224,62,224,59,160,49,192,62,96,62,32,
-74,5,141,224,74,37,141,160,74,69,142,0,74,96,48,32,74,128,48,192,75,32,49,
-224,75,96,50,0,76,0,50,96,76,96,50,128,76,180,241,160,77,0,50,224,77,101,
-140,64,78,37,141,192,78,64,51,160,78,160,51,224,79,165,140,128,81,0,53,192,
-81,32,72,128,81,128,72,160,82,64,54,224,104,160,115,32,110,224,110,192,117,
-128,112,192,120,64,116,96,121,128,113,128,122,0,114,64,122,32,115,0,122,
-160,116,192,122,192,116,0,122,224,121,224,126,0,115,64,126,32,116,32,126,
-64,127,32,126,160,114,160,153,224,152,3,175,52,239,163,175,165,140,99,211,
-99,204,3,247,192,115,35,252,163,253,132,41,196,38,68,48,132,48,101,140,37,
-140,5,140,160,71,69,140,192,71,217,128,55,224,5,48,5,48,20,152,10,240,1,56,
-7,194,0,74,3,12,3,144,192,230,64,194,0,192,64,236,48,58,80,48,128,48,16,88,
-120,20,212,21,72,122,90,0,72,3,49,30,151,128,21,0,194,7,166,32,5,112,48,
-161,233,152,1,100,12,40,122,106,0,65,2,190,31,80,128,233,64,196,199,212,
-176,58,80,49,48,48,1,245,76,14,148,12,76,12,4,125,91,3,165,3,19,3,66,31,
-128,135,194,0,230,71,224,97,240,144,57,145,248,40,124,40,14,100,126,14,31,
-11,3,153,31,132,135,195,0,230,71,225,97,240,208,57,145,248,104,124,56,14,
-100,126,30,31,15,3,153,31,136,135,194,0,230,71,226,97,240,144,57,145,248,
-168,124,40,14,100,126,46,31,11,3,153,31,140,135,195,0,230,71,227,97,240,
-208,57,145,248,232,124,56,14,100,126,62,31,15,3,153,31,144,135,202,0,230,
-71,228,97,242,144,57,145,249,40,124,168,14,100,126,78,31,43,3,153,31,148,
-135,203,0,230,71,229,97,242,208,57,145,249,104,124,184,14,100,126,94,31,47,
-3,153,31,152,135,202,0,230,71,230,97,242,144,57,145,249,168,124,168,14,100,
-126,110,31,43,3,153,31,156,135,203,0,230,71,231,97,242,208,57,145,249,232,
-124,184,14,100,126,126,31,47,3,153,31,160,135,218,0,230,71,232,97,246,144,
-57,145,250,40,125,168,14,100,126,142,31,107,3,153,31,164,135,219,0,230,71,
-233,97,246,208,57,145,250,104,125,184,14,100,126,158,31,111,3,153,31,168,
-135,218,0,230,71,234,97,246,144,57,145,250,168,125,168,14,100,126,174,31,
-107,3,153,31,172,135,219,0,230,71,235,97,246,208,57,145,250,232,125,184,14,
-100,126,190,31,111,3,153,31,178,135,238,128,230,71,236,224,57,16,57,145,
-251,72,14,24,14,100,126,218,3,145,3,66,31,183,192,228,64,208,128,230,71,
-239,32,57,16,57,145,252,40,127,40,14,100,127,14,3,151,3,153,31,196,128,226,
-64,230,71,241,160,57,112,52,33,252,124,14,92,13,8,14,100,127,50,3,151,3,
-153,31,210,192,230,64,194,0,192,7,244,240,57,144,48,128,48,17,253,104,14,
-100,13,8,127,95,3,153,3,8,3,66,31,226,192,233,64,194,0,192,7,248,240,58,80,
-48,128,48,17,254,72,14,132,12,76,127,154,3,165,3,66,31,231,192,233,64,194,
-0,208,135,252,161,255,160,57,145,255,56,14,164,14,100,127,210,3,143,3,153,
-31,246,128,234,64,208,135,253,240,58,144,52,32,57,145,255,200,14,164,14,
-103,236,2,0,70,0,70,251,1,128,17,128,18,126,192,160,4,96,4,207,176,60,1,24,
-1,24,1,39,236,19,0,70,0,70,0,76,251,5,128,20,192,21,62,193,160,5,48,5,79,
-177,56,21,16,21,27,236,82,5,68,5,53,251,21,129,81,1,78,254,197,160,84,224,
-84,111,177,120,21,16,20,244,
-};
-const duk_uint8_t duk_unicode_caseconv_lc[616] = {
-144,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
-235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32,
-0,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,15,132,15,128,8,31,24,
-31,16,12,62,80,62,64,32,124,224,124,192,64,250,64,250,0,97,246,129,246,1,3,
-241,3,240,2,7,230,7,228,4,15,212,15,208,8,31,184,31,176,4,63,116,62,224,8,
-127,32,125,200,32,254,192,254,128,33,253,161,247,96,67,253,3,252,0,135,250,
-135,222,129,15,252,15,188,2,31,250,31,124,4,66,192,66,224,64,146,216,147,
-64,209,96,1,97,130,242,199,224,35,240,95,228,63,232,38,161,1,0,1,1,48,2,
-100,2,102,12,4,228,4,232,64,10,80,10,89,112,23,144,23,160,96,48,64,48,96,
-128,104,0,104,65,128,217,128,218,2,1,203,1,204,18,3,188,3,190,36,7,200,7,
-204,16,15,192,15,201,64,34,32,34,49,32,72,192,72,225,64,220,0,220,65,1,236,
-1,236,140,4,96,4,97,34,9,20,9,22,108,19,4,19,8,56,38,128,38,138,193,224,1,
-224,25,99,212,3,212,44,7,214,71,212,66,22,51,150,52,3,44,128,44,129,100,89,
-214,89,216,10,153,2,153,4,189,52,5,52,8,202,114,42,114,48,244,230,84,230,
-103,233,222,105,222,129,83,191,83,191,133,167,160,167,161,10,48,13,48,20,0,
-32,26,192,26,208,64,56,128,56,192,192,113,64,113,129,1,251,129,252,2,44,
-114,44,115,4,16,12,56,12,64,32,27,128,27,144,64,211,197,211,198,2,8,6,88,9,
-164,16,17,216,17,224,47,245,1,120,0,255,1,129,2,83,1,134,2,84,1,142,1,221,
-1,143,2,89,1,144,2,91,1,145,1,146,1,147,2,96,1,148,2,99,1,151,2,104,1,152,
-1,153,1,157,2,114,1,159,2,117,1,167,1,168,1,174,2,136,1,183,2,146,1,241,1,
-243,1,246,1,149,1,247,1,191,2,32,1,158,2,58,44,101,2,61,1,154,2,62,44,102,
-2,67,1,128,2,68,2,137,2,69,2,140,3,118,3,119,3,134,3,172,3,140,3,204,3,207,
-3,215,3,244,3,184,3,249,3,242,4,192,4,207,30,158,0,223,31,188,31,179,31,
-204,31,195,31,236,31,229,31,252,31,243,33,38,3,201,33,42,0,107,33,43,0,229,
-33,50,33,78,33,131,33,132,44,96,44,97,44,98,2,107,44,99,29,125,44,100,2,
-125,44,109,2,81,44,110,2,113,44,111,2,80,44,112,2,82,167,125,29,121,167,
-141,2,101,2,2,97,0,52,129,131,128,
-};
-
-#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
-/*
- * Automatically generated by extract_caseconv.py, do not edit!
- */
-
-const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
-0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,
-28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
-53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,
-78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70,
-71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,123,124,125,
-126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
-144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
-162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
-180,924,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
-198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
-216,217,218,219,220,221,222,223,192,193,194,195,196,197,198,199,200,201,
-202,203,204,205,206,207,208,209,210,211,212,213,214,247,216,217,218,219,
-220,221,222,376,256,256,258,258,260,260,262,262,264,264,266,266,268,268,
-270,270,272,272,274,274,276,276,278,278,280,280,282,282,284,284,286,286,
-288,288,290,290,292,292,294,294,296,296,298,298,300,300,302,302,304,305,
-306,306,308,308,310,310,312,313,313,315,315,317,317,319,319,321,321,323,
-323,325,325,327,327,329,330,330,332,332,334,334,336,336,338,338,340,340,
-342,342,344,344,346,346,348,348,350,350,352,352,354,354,356,356,358,358,
-360,360,362,362,364,364,366,366,368,368,370,370,372,372,374,374,376,377,
-377,379,379,381,381,383,579,385,386,386,388,388,390,391,391,393,394,395,
-395,397,398,399,400,401,401,403,404,502,406,407,408,408,573,411,412,413,
-544,415,416,416,418,418,420,420,422,423,423,425,426,427,428,428,430,431,
-431,433,434,435,435,437,437,439,440,440,442,443,444,444,446,503,448,449,
-450,451,452,452,452,455,455,455,458,458,458,461,461,463,463,465,465,467,
-467,469,469,471,471,473,473,475,475,398,478,478,480,480,482,482,484,484,
-486,486,488,488,490,490,492,492,494,494,496,497,497,497,500,500,502,503,
-504,504,506,506,508,508,510,510,512,512,514,514,516,516,518,518,520,520,
-522,522,524,524,526,526,528,528,530,530,532,532,534,534,536,536,538,538,
-540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556,
-558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390,
-11391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375,
-11373,11376,385,390,597,393,394,600,399,602,400,604,605,606,607,403,609,
-610,404,612,42893L,614,615,407,406,618,11362,620,621,622,412,624,11374,413,
-627,628,415,630,631,632,633,634,635,636,11364,638,639,422,641,642,425,644,
-645,646,647,430,580,433,434,581,653,654,655,656,657,439,659,660,661,662,
-663,664,665,666,667,668,669,670,671,672,673,674,675,676,677,678,679,680,
-681,682,683,684,685,686,687,688,689,690,691,692,693,694,695,696,697,698,
-699,700,701,702,703,704,705,706,707,708,709,710,711,712,713,714,715,716,
-717,718,719,720,721,722,723,724,725,726,727,728,729,730,731,732,733,734,
-735,736,737,738,739,740,741,742,743,744,745,746,747,748,749,750,751,752,
-753,754,755,756,757,758,759,760,761,762,763,764,765,766,767,768,769,770,
-771,772,773,774,775,776,777,778,779,780,781,782,783,784,785,786,787,788,
-789,790,791,792,793,794,795,796,797,798,799,800,801,802,803,804,805,806,
-807,808,809,810,811,812,813,814,815,816,817,818,819,820,821,822,823,824,
-825,826,827,828,829,830,831,832,833,834,835,836,921,838,839,840,841,842,
-843,844,845,846,847,848,849,850,851,852,853,854,855,856,857,858,859,860,
-861,862,863,864,865,866,867,868,869,870,871,872,873,874,875,876,877,878,
-879,880,880,882,882,884,885,886,886,888,889,890,1021,1022,1023,894,895,896,
-897,898,899,900,901,902,903,904,905,906,907,908,909,910,911,912,913,914,
-915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,930,931,932,
-933,934,935,936,937,938,939,902,904,905,906,944,913,914,915,916,917,918,
-919,920,921,922,923,924,925,926,927,928,929,931,931,932,933,934,935,936,
-937,938,939,908,910,911,975,914,920,978,979,980,934,928,975,984,984,986,
-986,988,988,990,990,992,992,994,994,996,996,998,998,1000,1000,1002,1002,
-1004,1004,1006,1006,922,929,1017,1011,1012,917,1014,1015,1015,1017,1018,
-1018,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,1030,1031,1032,1033,
-1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,
-1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,
-1064,1065,1066,1067,1068,1069,1070,1071,1040,1041,1042,1043,1044,1045,1046,
-1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,
-1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,1025,1026,1027,1028,
-1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1120,1120,1122,1122,
-1124,1124,1126,1126,1128,1128,1130,1130,1132,1132,1134,1134,1136,1136,1138,
-1138,1140,1140,1142,1142,1144,1144,1146,1146,1148,1148,1150,1150,1152,1152,
-1154,1155,1156,1157,1158,1159,1160,1161,1162,1162,1164,1164,1166,1166,1168,
-1168,1170,1170,1172,1172,1174,1174,1176,1176,1178,1178,1180,1180,1182,1182,
-1184,1184,1186,1186,1188,1188,1190,1190,1192,1192,1194,1194,1196,1196,1198,
-1198,1200,1200,1202,1202,1204,1204,1206,1206,1208,1208,1210,1210,1212,1212,
-1214,1214,1216,1217,1217,1219,1219,1221,1221,1223,1223,1225,1225,1227,1227,
-1229,1229,1216,1232,1232,1234,1234,1236,1236,1238,1238,1240,1240,1242,1242,
-1244,1244,1246,1246,1248,1248,1250,1250,1252,1252,1254,1254,1256,1256,1258,
-1258,1260,1260,1262,1262,1264,1264,1266,1266,1268,1268,1270,1270,1272,1272,
-1274,1274,1276,1276,1278,1278,1280,1280,1282,1282,1284,1284,1286,1286,1288,
-1288,1290,1290,1292,1292,1294,1294,1296,1296,1298,1298,1300,1300,1302,1302,
-1304,1304,1306,1306,1308,1308,1310,1310,1312,1312,1314,1314,1316,1316,1318,
-1318,1320,1321,1322,1323,1324,1325,1326,1327,1328,1329,1330,1331,1332,1333,
-1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,1346,1347,1348,
-1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,1361,1362,1363,
-1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,1375,1376,1329,1330,
-1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,1345,
-1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,1360,
-1361,1362,1363,1364,1365,1366,1415,1416,1417,1418,1419,1420,1421,1422,1423,
-1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,1435,1436,1437,1438,
-1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,1450,1451,1452,1453,
-1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,
-1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,1480,1481,1482,1483,
-1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,
-1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,
-1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1525,1526,1527,1528,
-1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,1540,1541,1542,1543,
-1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,1555,1556,1557,1558,
-1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,1570,1571,1572,1573,
-1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,
-1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1602,1603,
-1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,
-1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,1630,1631,1632,1633,
-1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,1645,1646,1647,1648,
-1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,1660,1661,1662,1663,
-1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675,1676,1677,1678,
-1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,1690,1691,1692,1693,
-1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,1705,1706,1707,1708,
-1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,1720,1721,1722,1723,
-1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,1735,1736,1737,1738,
-1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,1750,1751,1752,1753,
-1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,1765,1766,1767,1768,
-1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,
-1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,1795,1796,1797,1798,
-1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,1810,1811,1812,1813,
-1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,1825,1826,1827,1828,
-1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,1840,1841,1842,1843,
-1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,1855,1856,1857,1858,
-1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,1870,1871,1872,1873,
-1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,1885,1886,1887,1888,
-1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,1900,1901,1902,1903,
-1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,1915,1916,1917,1918,
-1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,1930,1931,1932,1933,
-1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,1945,1946,1947,1948,
-1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961,1962,1963,
-1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,1975,1976,1977,1978,
-1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,
-1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,
-2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020,2021,2022,2023,
-2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,2035,2036,2037,2038,
-2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,
-2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,2065,2066,2067,2068,
-2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,
-2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,
-2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,
-2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,
-2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,
-2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,
-2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,
-2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,
-2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,
-2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,
-2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,
-2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,
-2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,
-2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,
-2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,
-2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,
-2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,
-2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,
-2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,
-2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,
-2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,
-2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,
-2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,
-2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,
-2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,
-2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,2455,2456,2457,2458,
-2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,
-2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,
-2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,
-2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,
-2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,
-2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,
-2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,
-2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,
-2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,
-2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,
-2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623,
-2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,2635,2636,2637,2638,
-2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,2650,2651,2652,2653,
-2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,2665,2666,2667,2668,
-2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,2680,2681,2682,2683,
-2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,2695,2696,2697,2698,
-2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,2710,2711,2712,2713,
-2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,2725,2726,2727,2728,
-2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,2740,2741,2742,2743,
-2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,2755,2756,2757,2758,
-2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,2770,2771,2772,2773,
-2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,2785,2786,2787,2788,
-2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,2800,2801,2802,2803,
-2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,2815,2816,2817,2818,
-2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,2830,2831,2832,2833,
-2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,2845,2846,2847,2848,
-2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,2860,2861,2862,2863,
-2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,2875,2876,2877,2878,
-2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,2890,2891,2892,2893,
-2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,2905,2906,2907,2908,
-2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,2920,2921,2922,2923,
-2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,2935,2936,2937,2938,
-2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,2950,2951,2952,2953,
-2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,2965,2966,2967,2968,
-2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,2980,2981,2982,2983,
-2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,2995,2996,2997,2998,
-2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,
-3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,
-3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,
-3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,
-3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,
-3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,
-3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,
-3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,
-3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,
-3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,
-3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,
-3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,
-3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,
-3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,
-3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,
-3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,
-3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,
-3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,
-3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,
-3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,
-3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,
-3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,
-3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,
-3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,
-3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,
-3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,
-3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,
-3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,
-3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,
-3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,
-3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,
-3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,
-3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,
-3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,
-3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,
-3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,
-3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,
-3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,
-3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,
-3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,
-3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,
-3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,
-3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,
-3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,
-3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,
-3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,
-3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,
-3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,
-3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,
-3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,
-3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,
-3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,
-3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,
-3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,
-3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,
-3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,
-3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,
-3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,
-3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,
-3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,
-3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,
-3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,
-3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,
-3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,
-3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,
-3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,
-3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,
-4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,
-4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,
-4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,
-4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,
-4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,
-4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,
-4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,
-4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,
-4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,
-4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,
-4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,
-4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,
-4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,
-4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,
-4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,
-4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,
-4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,
-4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,
-4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,
-4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,
-4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,
-4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,
-4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,
-4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,
-4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,
-4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,
-4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,
-4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,
-4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,
-4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,
-4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,
-4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,
-4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,
-4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,
-4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,
-4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,
-4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,
-4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,
-4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,
-4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,
-4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,
-4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,
-4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,
-4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,
-4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,
-4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,
-4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,
-4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,
-4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,
-4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,
-4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,
-4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,
-4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,
-4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,
-4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,
-4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,
-4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,
-4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,
-4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,
-4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,
-4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,
-4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,
-4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,
-4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,
-4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,
-4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,4990,4991,4992,4993,
-4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,
-5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,
-5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,
-5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,
-5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,
-5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,
-5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,
-5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,5113,
-5114,5115,5116,5117,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,
-5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,
-5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,5155,5156,5157,5158,
-5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,
-5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,
-5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,5200,5201,5202,5203,
-5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,5215,5216,5217,5218,
-5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,
-5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,5248,
-5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,
-5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,
-5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,
-5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,5305,5306,5307,5308,
-5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,5322,5323,
-5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,5335,5336,5337,5338,
-5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353,
-5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,
-5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,
-5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,
-5399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409,5410,5411,5412,5413,
-5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,
-5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440,5441,5442,5443,
-5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,
-5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,
-5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488,
-5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,
-5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,
-5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,
-5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,
-5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,
-5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,
-5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,5590,5591,5592,5593,
-5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,5605,5606,5607,5608,
-5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,5620,5621,5622,5623,
-5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638,
-5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,5650,5651,5652,5653,
-5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,5665,5666,5667,5668,
-5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680,5681,5682,5683,
-5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,
-5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712,5713,
-5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728,
-5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,
-5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,
-5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,
-5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,
-5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,
-5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,
-5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831,5832,5833,
-5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847,5848,
-5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860,5861,5862,5863,
-5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,5875,5876,5877,5878,
-5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5890,5891,5892,5893,
-5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,5905,5906,5907,5908,
-5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920,5921,5922,5923,
-5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936,5937,5938,
-5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952,5953,
-5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968,
-5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,
-5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,
-5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,
-6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,
-6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,
-6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,
-6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,6070,6071,6072,6073,
-6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,6085,6086,6087,6088,
-6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,6100,6101,6102,6103,
-6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,6115,6116,6117,6118,
-6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,6130,6131,6132,6133,
-6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,6145,6146,6147,6148,
-6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,6160,6161,6162,6163,
-6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,6175,6176,6177,6178,
-6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,6190,6191,6192,6193,
-6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,6205,6206,6207,6208,
-6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,6220,6221,6222,6223,
-6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234,6235,6236,6237,6238,
-6239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249,6250,6251,6252,6253,
-6254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264,6265,6266,6267,6268,
-6269,6270,6271,6272,6273,6274,6275,6276,6277,6278,6279,6280,6281,6282,6283,
-6284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,6295,6296,6297,6298,
-6299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309,6310,6311,6312,6313,
-6314,6315,6316,6317,6318,6319,6320,6321,6322,6323,6324,6325,6326,6327,6328,
-6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,6340,6341,6342,6343,
-6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,6355,6356,6357,6358,
-6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,6370,6371,6372,6373,
-6374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384,6385,6386,6387,6388,
-6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,6400,6401,6402,6403,
-6404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414,6415,6416,6417,6418,
-6419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429,6430,6431,6432,6433,
-6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6444,6445,6446,6447,6448,
-6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,6460,6461,6462,6463,
-6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474,6475,6476,6477,6478,
-6479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,6490,6491,6492,6493,
-6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,6505,6506,6507,6508,
-6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,6520,6521,6522,6523,
-6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,6535,6536,6537,6538,
-6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,6550,6551,6552,6553,
-6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,6565,6566,6567,6568,
-6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,6580,6581,6582,6583,
-6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,6595,6596,6597,6598,
-6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,6610,6611,6612,6613,
-6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,6625,6626,6627,6628,
-6629,6630,6631,6632,6633,6634,6635,6636,6637,6638,6639,6640,6641,6642,6643,
-6644,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,6655,6656,6657,6658,
-6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,6670,6671,6672,6673,
-6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,6685,6686,6687,6688,
-6689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,6700,6701,6702,6703,
-6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,6715,6716,6717,6718,
-6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,6730,6731,6732,6733,
-6734,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,6745,6746,6747,6748,
-6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,6760,6761,6762,6763,
-6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,6775,6776,6777,6778,
-6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6789,6790,6791,6792,6793,
-6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,6805,6806,6807,6808,
-6809,6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,6820,6821,6822,6823,
-6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,6835,6836,6837,6838,
-6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,6850,6851,6852,6853,
-6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,
-6869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879,6880,6881,6882,6883,
-6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,6895,6896,6897,6898,
-6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,6910,6911,6912,6913,
-6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,6925,6926,6927,6928,
-6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,6940,6941,6942,6943,
-6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,6955,6956,6957,6958,
-6959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969,6970,6971,6972,6973,
-6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,6985,6986,6987,6988,
-6989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999,7000,7001,7002,7003,
-7004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014,7015,7016,7017,7018,
-7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,7030,7031,7032,7033,
-7034,7035,7036,7037,7038,7039,7040,7041,7042,7043,7044,7045,7046,7047,7048,
-7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,7060,7061,7062,7063,
-7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,7075,7076,7077,7078,
-7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,7090,7091,7092,7093,
-7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,7105,7106,7107,7108,
-7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,7120,7121,7122,7123,
-7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,7135,7136,7137,7138,
-7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,7150,7151,7152,7153,
-7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,7165,7166,7167,7168,
-7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,7180,7181,7182,7183,
-7184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,7195,7196,7197,7198,
-7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,7210,7211,7212,7213,
-7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,7225,7226,7227,7228,
-7229,7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,7240,7241,7242,7243,
-7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,7255,7256,7257,7258,
-7259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269,7270,7271,7272,7273,
-7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,7285,7286,7287,7288,
-7289,7290,7291,7292,7293,7294,7295,7296,7297,7298,7299,7300,7301,7302,7303,
-7304,7305,7306,7307,7308,7309,7310,7311,7312,7313,7314,7315,7316,7317,7318,
-7319,7320,7321,7322,7323,7324,7325,7326,7327,7328,7329,7330,7331,7332,7333,
-7334,7335,7336,7337,7338,7339,7340,7341,7342,7343,7344,7345,7346,7347,7348,
-7349,7350,7351,7352,7353,7354,7355,7356,7357,7358,7359,7360,7361,7362,7363,
-7364,7365,7366,7367,7368,7369,7370,7371,7372,7373,7374,7375,7376,7377,7378,
-7379,7380,7381,7382,7383,7384,7385,7386,7387,7388,7389,7390,7391,7392,7393,
-7394,7395,7396,7397,7398,7399,7400,7401,7402,7403,7404,7405,7406,7407,7408,
-7409,7410,7411,7412,7413,7414,7415,7416,7417,7418,7419,7420,7421,7422,7423,
-7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,7434,7435,7436,7437,7438,
-7439,7440,7441,7442,7443,7444,7445,7446,7447,7448,7449,7450,7451,7452,7453,
-7454,7455,7456,7457,7458,7459,7460,7461,7462,7463,7464,7465,7466,7467,7468,
-7469,7470,7471,7472,7473,7474,7475,7476,7477,7478,7479,7480,7481,7482,7483,
-7484,7485,7486,7487,7488,7489,7490,7491,7492,7493,7494,7495,7496,7497,7498,
-7499,7500,7501,7502,7503,7504,7505,7506,7507,7508,7509,7510,7511,7512,7513,
-7514,7515,7516,7517,7518,7519,7520,7521,7522,7523,7524,7525,7526,7527,7528,
-7529,7530,7531,7532,7533,7534,7535,7536,7537,7538,7539,7540,7541,7542,7543,
-7544,42877L,7546,7547,7548,11363,7550,7551,7552,7553,7554,7555,7556,7557,
-7558,7559,7560,7561,7562,7563,7564,7565,7566,7567,7568,7569,7570,7571,7572,
-7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,7583,7584,7585,7586,7587,
-7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,7598,7599,7600,7601,7602,
-7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,7613,7614,7615,7616,7617,
-7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,7628,7629,7630,7631,7632,
-7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,7643,7644,7645,7646,7647,
-7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,7658,7659,7660,7661,7662,
-7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,7673,7674,7675,7676,7677,
-7678,7679,7680,7680,7682,7682,7684,7684,7686,7686,7688,7688,7690,7690,7692,
-7692,7694,7694,7696,7696,7698,7698,7700,7700,7702,7702,7704,7704,7706,7706,
-7708,7708,7710,7710,7712,7712,7714,7714,7716,7716,7718,7718,7720,7720,7722,
-7722,7724,7724,7726,7726,7728,7728,7730,7730,7732,7732,7734,7734,7736,7736,
-7738,7738,7740,7740,7742,7742,7744,7744,7746,7746,7748,7748,7750,7750,7752,
-7752,7754,7754,7756,7756,7758,7758,7760,7760,7762,7762,7764,7764,7766,7766,
-7768,7768,7770,7770,7772,7772,7774,7774,7776,7776,7778,7778,7780,7780,7782,
-7782,7784,7784,7786,7786,7788,7788,7790,7790,7792,7792,7794,7794,7796,7796,
-7798,7798,7800,7800,7802,7802,7804,7804,7806,7806,7808,7808,7810,7810,7812,
-7812,7814,7814,7816,7816,7818,7818,7820,7820,7822,7822,7824,7824,7826,7826,
-7828,7828,7830,7831,7832,7833,7834,7776,7836,7837,7838,7839,7840,7840,7842,
-7842,7844,7844,7846,7846,7848,7848,7850,7850,7852,7852,7854,7854,7856,7856,
-7858,7858,7860,7860,7862,7862,7864,7864,7866,7866,7868,7868,7870,7870,7872,
-7872,7874,7874,7876,7876,7878,7878,7880,7880,7882,7882,7884,7884,7886,7886,
-7888,7888,7890,7890,7892,7892,7894,7894,7896,7896,7898,7898,7900,7900,7902,
-7902,7904,7904,7906,7906,7908,7908,7910,7910,7912,7912,7914,7914,7916,7916,
-7918,7918,7920,7920,7922,7922,7924,7924,7926,7926,7928,7928,7930,7930,7932,
-7932,7934,7934,7944,7945,7946,7947,7948,7949,7950,7951,7944,7945,7946,7947,
-7948,7949,7950,7951,7960,7961,7962,7963,7964,7965,7958,7959,7960,7961,7962,
-7963,7964,7965,7966,7967,7976,7977,7978,7979,7980,7981,7982,7983,7976,7977,
-7978,7979,7980,7981,7982,7983,7992,7993,7994,7995,7996,7997,7998,7999,7992,
-7993,7994,7995,7996,7997,7998,7999,8008,8009,8010,8011,8012,8013,8006,8007,
-8008,8009,8010,8011,8012,8013,8014,8015,8016,8025,8018,8027,8020,8029,8022,
-8031,8024,8025,8026,8027,8028,8029,8030,8031,8040,8041,8042,8043,8044,8045,
-8046,8047,8040,8041,8042,8043,8044,8045,8046,8047,8122,8123,8136,8137,8138,
-8139,8154,8155,8184,8185,8170,8171,8186,8187,8062,8063,8064,8065,8066,8067,
-8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,8078,8079,8080,8081,8082,
-8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,8093,8094,8095,8096,8097,
-8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,8108,8109,8110,8111,8120,
-8121,8114,8115,8116,8117,8118,8119,8120,8121,8122,8123,8124,8125,921,8127,
-8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,8138,8139,8140,8141,8142,
-8143,8152,8153,8146,8147,8148,8149,8150,8151,8152,8153,8154,8155,8156,8157,
-8158,8159,8168,8169,8162,8163,8164,8172,8166,8167,8168,8169,8170,8171,8172,
-8173,8174,8175,8176,8177,8178,8179,8180,8181,8182,8183,8184,8185,8186,8187,
-8188,8189,8190,8191,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,
-8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,8213,8214,8215,8216,8217,
-8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,8228,8229,8230,8231,8232,
-8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,8243,8244,8245,8246,8247,
-8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,8258,8259,8260,8261,8262,
-8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,8273,8274,8275,8276,8277,
-8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,8288,8289,8290,8291,8292,
-8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,8304,8305,8306,8307,
-8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,8318,8319,8320,8321,8322,
-8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,8333,8334,8335,8336,8337,
-8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,8348,8349,8350,8351,8352,
-8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,8363,8364,8365,8366,8367,
-8368,8369,8370,8371,8372,8373,8374,8375,8376,8377,8378,8379,8380,8381,8382,
-8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,8393,8394,8395,8396,8397,
-8398,8399,8400,8401,8402,8403,8404,8405,8406,8407,8408,8409,8410,8411,8412,
-8413,8414,8415,8416,8417,8418,8419,8420,8421,8422,8423,8424,8425,8426,8427,
-8428,8429,8430,8431,8432,8433,8434,8435,8436,8437,8438,8439,8440,8441,8442,
-8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,8453,8454,8455,8456,8457,
-8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,8468,8469,8470,8471,8472,
-8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,8483,8484,8485,8486,8487,
-8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,8498,8499,8500,8501,8502,
-8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,8513,8514,8515,8516,8517,
-8518,8519,8520,8521,8522,8523,8524,8525,8498,8527,8528,8529,8530,8531,8532,
-8533,8534,8535,8536,8537,8538,8539,8540,8541,8542,8543,8544,8545,8546,8547,
-8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8544,8545,8546,
-8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,8558,8559,8576,8577,
-8578,8579,8579,8581,8582,8583,8584,8585,8586,8587,8588,8589,8590,8591,8592,
-8593,8594,8595,8596,8597,8598,8599,8600,8601,8602,8603,8604,8605,8606,8607,
-8608,8609,8610,8611,8612,8613,8614,8615,8616,8617,8618,8619,8620,8621,8622,
-8623,8624,8625,8626,8627,8628,8629,8630,8631,8632,8633,8634,8635,8636,8637,
-8638,8639,8640,8641,8642,8643,8644,8645,8646,8647,8648,8649,8650,8651,8652,
-8653,8654,8655,8656,8657,8658,8659,8660,8661,8662,8663,8664,8665,8666,8667,
-8668,8669,8670,8671,8672,8673,8674,8675,8676,8677,8678,8679,8680,8681,8682,
-8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,8693,8694,8695,8696,8697,
-8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,8708,8709,8710,8711,8712,
-8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,8723,8724,8725,8726,8727,
-8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,8738,8739,8740,8741,8742,
-8743,8744,8745,8746,8747,8748,8749,8750,8751,8752,8753,8754,8755,8756,8757,
-8758,8759,8760,8761,8762,8763,8764,8765,8766,8767,8768,8769,8770,8771,8772,
-8773,8774,8775,8776,8777,8778,8779,8780,8781,8782,8783,8784,8785,8786,8787,
-8788,8789,8790,8791,8792,8793,8794,8795,8796,8797,8798,8799,8800,8801,8802,
-8803,8804,8805,8806,8807,8808,8809,8810,8811,8812,8813,8814,8815,8816,8817,
-8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,8829,8830,8831,8832,
-8833,8834,8835,8836,8837,8838,8839,8840,8841,8842,8843,8844,8845,8846,8847,
-8848,8849,8850,8851,8852,8853,8854,8855,8856,8857,8858,8859,8860,8861,8862,
-8863,8864,8865,8866,8867,8868,8869,8870,8871,8872,8873,8874,8875,8876,8877,
-8878,8879,8880,8881,8882,8883,8884,8885,8886,8887,8888,8889,8890,8891,8892,
-8893,8894,8895,8896,8897,8898,8899,8900,8901,8902,8903,8904,8905,8906,8907,
-8908,8909,8910,8911,8912,8913,8914,8915,8916,8917,8918,8919,8920,8921,8922,
-8923,8924,8925,8926,8927,8928,8929,8930,8931,8932,8933,8934,8935,8936,8937,
-8938,8939,8940,8941,8942,8943,8944,8945,8946,8947,8948,8949,8950,8951,8952,
-8953,8954,8955,8956,8957,8958,8959,8960,8961,8962,8963,8964,8965,8966,8967,
-8968,8969,8970,8971,8972,8973,8974,8975,8976,8977,8978,8979,8980,8981,8982,
-8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,8993,8994,8995,8996,8997,
-8998,8999,9000,9001,9002,9003,9004,9005,9006,9007,9008,9009,9010,9011,9012,
-9013,9014,9015,9016,9017,9018,9019,9020,9021,9022,9023,9024,9025,9026,9027,
-9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,
-9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,9053,9054,9055,9056,9057,
-9058,9059,9060,9061,9062,9063,9064,9065,9066,9067,9068,9069,9070,9071,9072,
-9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,9083,9084,9085,9086,9087,
-9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,9098,9099,9100,9101,9102,
-9103,9104,9105,9106,9107,9108,9109,9110,9111,9112,9113,9114,9115,9116,9117,
-9118,9119,9120,9121,9122,9123,9124,9125,9126,9127,9128,9129,9130,9131,9132,
-9133,9134,9135,9136,9137,9138,9139,9140,9141,9142,9143,9144,9145,9146,9147,
-9148,9149,9150,9151,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162,
-9163,9164,9165,9166,9167,9168,9169,9170,9171,9172,9173,9174,9175,9176,9177,
-9178,9179,9180,9181,9182,9183,9184,9185,9186,9187,9188,9189,9190,9191,9192,
-9193,9194,9195,9196,9197,9198,9199,9200,9201,9202,9203,9204,9205,9206,9207,
-9208,9209,9210,9211,9212,9213,9214,9215,9216,9217,9218,9219,9220,9221,9222,
-9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,
-9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,9248,9249,9250,9251,9252,
-9253,9254,9255,9256,9257,9258,9259,9260,9261,9262,9263,9264,9265,9266,9267,
-9268,9269,9270,9271,9272,9273,9274,9275,9276,9277,9278,9279,9280,9281,9282,
-9283,9284,9285,9286,9287,9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,
-9298,9299,9300,9301,9302,9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,
-9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,
-9328,9329,9330,9331,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,
-9343,9344,9345,9346,9347,9348,9349,9350,9351,9352,9353,9354,9355,9356,9357,
-9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9372,
-9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,
-9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,9398,9399,9400,9401,9402,
-9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,
-9418,9419,9420,9421,9422,9423,9398,9399,9400,9401,9402,9403,9404,9405,9406,
-9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,9417,9418,9419,9420,9421,
-9422,9423,9450,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,9461,9462,
-9463,9464,9465,9466,9467,9468,9469,9470,9471,9472,9473,9474,9475,9476,9477,
-9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492,
-9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507,
-9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522,
-9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537,
-9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550,9551,9552,
-9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,
-9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,
-9583,9584,9585,9586,9587,9588,9589,9590,9591,9592,9593,9594,9595,9596,9597,
-9598,9599,9600,9601,9602,9603,9604,9605,9606,9607,9608,9609,9610,9611,9612,
-9613,9614,9615,9616,9617,9618,9619,9620,9621,9622,9623,9624,9625,9626,9627,
-9628,9629,9630,9631,9632,9633,9634,9635,9636,9637,9638,9639,9640,9641,9642,
-9643,9644,9645,9646,9647,9648,9649,9650,9651,9652,9653,9654,9655,9656,9657,
-9658,9659,9660,9661,9662,9663,9664,9665,9666,9667,9668,9669,9670,9671,9672,
-9673,9674,9675,9676,9677,9678,9679,9680,9681,9682,9683,9684,9685,9686,9687,
-9688,9689,9690,9691,9692,9693,9694,9695,9696,9697,9698,9699,9700,9701,9702,
-9703,9704,9705,9706,9707,9708,9709,9710,9711,9712,9713,9714,9715,9716,9717,
-9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,9728,9729,9730,9731,9732,
-9733,9734,9735,9736,9737,9738,9739,9740,9741,9742,9743,9744,9745,9746,9747,
-9748,9749,9750,9751,9752,9753,9754,9755,9756,9757,9758,9759,9760,9761,9762,
-9763,9764,9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776,9777,
-9778,9779,9780,9781,9782,9783,9784,9785,9786,9787,9788,9789,9790,9791,9792,
-9793,9794,9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806,9807,
-9808,9809,9810,9811,9812,9813,9814,9815,9816,9817,9818,9819,9820,9821,9822,
-9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,9833,9834,9835,9836,9837,
-9838,9839,9840,9841,9842,9843,9844,9845,9846,9847,9848,9849,9850,9851,9852,
-9853,9854,9855,9856,9857,9858,9859,9860,9861,9862,9863,9864,9865,9866,9867,
-9868,9869,9870,9871,9872,9873,9874,9875,9876,9877,9878,9879,9880,9881,9882,
-9883,9884,9885,9886,9887,9888,9889,9890,9891,9892,9893,9894,9895,9896,9897,
-9898,9899,9900,9901,9902,9903,9904,9905,9906,9907,9908,9909,9910,9911,9912,
-9913,9914,9915,9916,9917,9918,9919,9920,9921,9922,9923,9924,9925,9926,9927,
-9928,9929,9930,9931,9932,9933,9934,9935,9936,9937,9938,9939,9940,9941,9942,
-9943,9944,9945,9946,9947,9948,9949,9950,9951,9952,9953,9954,9955,9956,9957,
-9958,9959,9960,9961,9962,9963,9964,9965,9966,9967,9968,9969,9970,9971,9972,
-9973,9974,9975,9976,9977,9978,9979,9980,9981,9982,9983,9984,9985,9986,9987,
-9988,9989,9990,9991,9992,9993,9994,9995,9996,9997,9998,9999,10000,10001,
-10002,10003,10004,10005,10006,10007,10008,10009,10010,10011,10012,10013,
-10014,10015,10016,10017,10018,10019,10020,10021,10022,10023,10024,10025,
-10026,10027,10028,10029,10030,10031,10032,10033,10034,10035,10036,10037,
-10038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,10049,
-10050,10051,10052,10053,10054,10055,10056,10057,10058,10059,10060,10061,
-10062,10063,10064,10065,10066,10067,10068,10069,10070,10071,10072,10073,
-10074,10075,10076,10077,10078,10079,10080,10081,10082,10083,10084,10085,
-10086,10087,10088,10089,10090,10091,10092,10093,10094,10095,10096,10097,
-10098,10099,10100,10101,10102,10103,10104,10105,10106,10107,10108,10109,
-10110,10111,10112,10113,10114,10115,10116,10117,10118,10119,10120,10121,
-10122,10123,10124,10125,10126,10127,10128,10129,10130,10131,10132,10133,
-10134,10135,10136,10137,10138,10139,10140,10141,10142,10143,10144,10145,
-10146,10147,10148,10149,10150,10151,10152,10153,10154,10155,10156,10157,
-10158,10159,10160,10161,10162,10163,10164,10165,10166,10167,10168,10169,
-10170,10171,10172,10173,10174,10175,10176,10177,10178,10179,10180,10181,
-10182,10183,10184,10185,10186,10187,10188,10189,10190,10191,10192,10193,
-10194,10195,10196,10197,10198,10199,10200,10201,10202,10203,10204,10205,
-10206,10207,10208,10209,10210,10211,10212,10213,10214,10215,10216,10217,
-10218,10219,10220,10221,10222,10223,10224,10225,10226,10227,10228,10229,
-10230,10231,10232,10233,10234,10235,10236,10237,10238,10239,10240,10241,
-10242,10243,10244,10245,10246,10247,10248,10249,10250,10251,10252,10253,
-10254,10255,10256,10257,10258,10259,10260,10261,10262,10263,10264,10265,
-10266,10267,10268,10269,10270,10271,10272,10273,10274,10275,10276,10277,
-10278,10279,10280,10281,10282,10283,10284,10285,10286,10287,10288,10289,
-10290,10291,10292,10293,10294,10295,10296,10297,10298,10299,10300,10301,
-10302,10303,10304,10305,10306,10307,10308,10309,10310,10311,10312,10313,
-10314,10315,10316,10317,10318,10319,10320,10321,10322,10323,10324,10325,
-10326,10327,10328,10329,10330,10331,10332,10333,10334,10335,10336,10337,
-10338,10339,10340,10341,10342,10343,10344,10345,10346,10347,10348,10349,
-10350,10351,10352,10353,10354,10355,10356,10357,10358,10359,10360,10361,
-10362,10363,10364,10365,10366,10367,10368,10369,10370,10371,10372,10373,
-10374,10375,10376,10377,10378,10379,10380,10381,10382,10383,10384,10385,
-10386,10387,10388,10389,10390,10391,10392,10393,10394,10395,10396,10397,
-10398,10399,10400,10401,10402,10403,10404,10405,10406,10407,10408,10409,
-10410,10411,10412,10413,10414,10415,10416,10417,10418,10419,10420,10421,
-10422,10423,10424,10425,10426,10427,10428,10429,10430,10431,10432,10433,
-10434,10435,10436,10437,10438,10439,10440,10441,10442,10443,10444,10445,
-10446,10447,10448,10449,10450,10451,10452,10453,10454,10455,10456,10457,
-10458,10459,10460,10461,10462,10463,10464,10465,10466,10467,10468,10469,
-10470,10471,10472,10473,10474,10475,10476,10477,10478,10479,10480,10481,
-10482,10483,10484,10485,10486,10487,10488,10489,10490,10491,10492,10493,
-10494,10495,10496,10497,10498,10499,10500,10501,10502,10503,10504,10505,
-10506,10507,10508,10509,10510,10511,10512,10513,10514,10515,10516,10517,
-10518,10519,10520,10521,10522,10523,10524,10525,10526,10527,10528,10529,
-10530,10531,10532,10533,10534,10535,10536,10537,10538,10539,10540,10541,
-10542,10543,10544,10545,10546,10547,10548,10549,10550,10551,10552,10553,
-10554,10555,10556,10557,10558,10559,10560,10561,10562,10563,10564,10565,
-10566,10567,10568,10569,10570,10571,10572,10573,10574,10575,10576,10577,
-10578,10579,10580,10581,10582,10583,10584,10585,10586,10587,10588,10589,
-10590,10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,
-10602,10603,10604,10605,10606,10607,10608,10609,10610,10611,10612,10613,
-10614,10615,10616,10617,10618,10619,10620,10621,10622,10623,10624,10625,
-10626,10627,10628,10629,10630,10631,10632,10633,10634,10635,10636,10637,
-10638,10639,10640,10641,10642,10643,10644,10645,10646,10647,10648,10649,
-10650,10651,10652,10653,10654,10655,10656,10657,10658,10659,10660,10661,
-10662,10663,10664,10665,10666,10667,10668,10669,10670,10671,10672,10673,
-10674,10675,10676,10677,10678,10679,10680,10681,10682,10683,10684,10685,
-10686,10687,10688,10689,10690,10691,10692,10693,10694,10695,10696,10697,
-10698,10699,10700,10701,10702,10703,10704,10705,10706,10707,10708,10709,
-10710,10711,10712,10713,10714,10715,10716,10717,10718,10719,10720,10721,
-10722,10723,10724,10725,10726,10727,10728,10729,10730,10731,10732,10733,
-10734,10735,10736,10737,10738,10739,10740,10741,10742,10743,10744,10745,
-10746,10747,10748,10749,10750,10751,10752,10753,10754,10755,10756,10757,
-10758,10759,10760,10761,10762,10763,10764,10765,10766,10767,10768,10769,
-10770,10771,10772,10773,10774,10775,10776,10777,10778,10779,10780,10781,
-10782,10783,10784,10785,10786,10787,10788,10789,10790,10791,10792,10793,
-10794,10795,10796,10797,10798,10799,10800,10801,10802,10803,10804,10805,
-10806,10807,10808,10809,10810,10811,10812,10813,10814,10815,10816,10817,
-10818,10819,10820,10821,10822,10823,10824,10825,10826,10827,10828,10829,
-10830,10831,10832,10833,10834,10835,10836,10837,10838,10839,10840,10841,
-10842,10843,10844,10845,10846,10847,10848,10849,10850,10851,10852,10853,
-10854,10855,10856,10857,10858,10859,10860,10861,10862,10863,10864,10865,
-10866,10867,10868,10869,10870,10871,10872,10873,10874,10875,10876,10877,
-10878,10879,10880,10881,10882,10883,10884,10885,10886,10887,10888,10889,
-10890,10891,10892,10893,10894,10895,10896,10897,10898,10899,10900,10901,
-10902,10903,10904,10905,10906,10907,10908,10909,10910,10911,10912,10913,
-10914,10915,10916,10917,10918,10919,10920,10921,10922,10923,10924,10925,
-10926,10927,10928,10929,10930,10931,10932,10933,10934,10935,10936,10937,
-10938,10939,10940,10941,10942,10943,10944,10945,10946,10947,10948,10949,
-10950,10951,10952,10953,10954,10955,10956,10957,10958,10959,10960,10961,
-10962,10963,10964,10965,10966,10967,10968,10969,10970,10971,10972,10973,
-10974,10975,10976,10977,10978,10979,10980,10981,10982,10983,10984,10985,
-10986,10987,10988,10989,10990,10991,10992,10993,10994,10995,10996,10997,
-10998,10999,11000,11001,11002,11003,11004,11005,11006,11007,11008,11009,
-11010,11011,11012,11013,11014,11015,11016,11017,11018,11019,11020,11021,
-11022,11023,11024,11025,11026,11027,11028,11029,11030,11031,11032,11033,
-11034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044,11045,
-11046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056,11057,
-11058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,
-11070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,
-11082,11083,11084,11085,11086,11087,11088,11089,11090,11091,11092,11093,
-11094,11095,11096,11097,11098,11099,11100,11101,11102,11103,11104,11105,
-11106,11107,11108,11109,11110,11111,11112,11113,11114,11115,11116,11117,
-11118,11119,11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,
-11130,11131,11132,11133,11134,11135,11136,11137,11138,11139,11140,11141,
-11142,11143,11144,11145,11146,11147,11148,11149,11150,11151,11152,11153,
-11154,11155,11156,11157,11158,11159,11160,11161,11162,11163,11164,11165,
-11166,11167,11168,11169,11170,11171,11172,11173,11174,11175,11176,11177,
-11178,11179,11180,11181,11182,11183,11184,11185,11186,11187,11188,11189,
-11190,11191,11192,11193,11194,11195,11196,11197,11198,11199,11200,11201,
-11202,11203,11204,11205,11206,11207,11208,11209,11210,11211,11212,11213,
-11214,11215,11216,11217,11218,11219,11220,11221,11222,11223,11224,11225,
-11226,11227,11228,11229,11230,11231,11232,11233,11234,11235,11236,11237,
-11238,11239,11240,11241,11242,11243,11244,11245,11246,11247,11248,11249,
-11250,11251,11252,11253,11254,11255,11256,11257,11258,11259,11260,11261,
-11262,11263,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,
-11274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,
-11286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,
-11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,
-11310,11311,11264,11265,11266,11267,11268,11269,11270,11271,11272,11273,
-11274,11275,11276,11277,11278,11279,11280,11281,11282,11283,11284,11285,
-11286,11287,11288,11289,11290,11291,11292,11293,11294,11295,11296,11297,
-11298,11299,11300,11301,11302,11303,11304,11305,11306,11307,11308,11309,
-11310,11359,11360,11360,11362,11363,11364,570,574,11367,11367,11369,11369,
-11371,11371,11373,11374,11375,11376,11377,11378,11378,11380,11381,11381,
-11383,11384,11385,11386,11387,11388,11389,11390,11391,11392,11392,11394,
-11394,11396,11396,11398,11398,11400,11400,11402,11402,11404,11404,11406,
-11406,11408,11408,11410,11410,11412,11412,11414,11414,11416,11416,11418,
-11418,11420,11420,11422,11422,11424,11424,11426,11426,11428,11428,11430,
-11430,11432,11432,11434,11434,11436,11436,11438,11438,11440,11440,11442,
-11442,11444,11444,11446,11446,11448,11448,11450,11450,11452,11452,11454,
-11454,11456,11456,11458,11458,11460,11460,11462,11462,11464,11464,11466,
-11466,11468,11468,11470,11470,11472,11472,11474,11474,11476,11476,11478,
-11478,11480,11480,11482,11482,11484,11484,11486,11486,11488,11488,11490,
-11490,11492,11493,11494,11495,11496,11497,11498,11499,11499,11501,11501,
-11503,11504,11505,11506,11507,11508,11509,11510,11511,11512,11513,11514,
-11515,11516,11517,11518,11519,4256,4257,4258,4259,4260,4261,4262,4263,4264,
-4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,
-4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,
-11558,11559,11560,11561,11562,11563,11564,11565,11566,11567,11568,11569,
-11570,11571,11572,11573,11574,11575,11576,11577,11578,11579,11580,11581,
-11582,11583,11584,11585,11586,11587,11588,11589,11590,11591,11592,11593,
-11594,11595,11596,11597,11598,11599,11600,11601,11602,11603,11604,11605,
-11606,11607,11608,11609,11610,11611,11612,11613,11614,11615,11616,11617,
-11618,11619,11620,11621,11622,11623,11624,11625,11626,11627,11628,11629,
-11630,11631,11632,11633,11634,11635,11636,11637,11638,11639,11640,11641,
-11642,11643,11644,11645,11646,11647,11648,11649,11650,11651,11652,11653,
-11654,11655,11656,11657,11658,11659,11660,11661,11662,11663,11664,11665,
-11666,11667,11668,11669,11670,11671,11672,11673,11674,11675,11676,11677,
-11678,11679,11680,11681,11682,11683,11684,11685,11686,11687,11688,11689,
-11690,11691,11692,11693,11694,11695,11696,11697,11698,11699,11700,11701,
-11702,11703,11704,11705,11706,11707,11708,11709,11710,11711,11712,11713,
-11714,11715,11716,11717,11718,11719,11720,11721,11722,11723,11724,11725,
-11726,11727,11728,11729,11730,11731,11732,11733,11734,11735,11736,11737,
-11738,11739,11740,11741,11742,11743,11744,11745,11746,11747,11748,11749,
-11750,11751,11752,11753,11754,11755,11756,11757,11758,11759,11760,11761,
-11762,11763,11764,11765,11766,11767,11768,11769,11770,11771,11772,11773,
-11774,11775,11776,11777,11778,11779,11780,11781,11782,11783,11784,11785,
-11786,11787,11788,11789,11790,11791,11792,11793,11794,11795,11796,11797,
-11798,11799,11800,11801,11802,11803,11804,11805,11806,11807,11808,11809,
-11810,11811,11812,11813,11814,11815,11816,11817,11818,11819,11820,11821,
-11822,11823,11824,11825,11826,11827,11828,11829,11830,11831,11832,11833,
-11834,11835,11836,11837,11838,11839,11840,11841,11842,11843,11844,11845,
-11846,11847,11848,11849,11850,11851,11852,11853,11854,11855,11856,11857,
-11858,11859,11860,11861,11862,11863,11864,11865,11866,11867,11868,11869,
-11870,11871,11872,11873,11874,11875,11876,11877,11878,11879,11880,11881,
-11882,11883,11884,11885,11886,11887,11888,11889,11890,11891,11892,11893,
-11894,11895,11896,11897,11898,11899,11900,11901,11902,11903,11904,11905,
-11906,11907,11908,11909,11910,11911,11912,11913,11914,11915,11916,11917,
-11918,11919,11920,11921,11922,11923,11924,11925,11926,11927,11928,11929,
-11930,11931,11932,11933,11934,11935,11936,11937,11938,11939,11940,11941,
-11942,11943,11944,11945,11946,11947,11948,11949,11950,11951,11952,11953,
-11954,11955,11956,11957,11958,11959,11960,11961,11962,11963,11964,11965,
-11966,11967,11968,11969,11970,11971,11972,11973,11974,11975,11976,11977,
-11978,11979,11980,11981,11982,11983,11984,11985,11986,11987,11988,11989,
-11990,11991,11992,11993,11994,11995,11996,11997,11998,11999,12000,12001,
-12002,12003,12004,12005,12006,12007,12008,12009,12010,12011,12012,12013,
-12014,12015,12016,12017,12018,12019,12020,12021,12022,12023,12024,12025,
-12026,12027,12028,12029,12030,12031,12032,12033,12034,12035,12036,12037,
-12038,12039,12040,12041,12042,12043,12044,12045,12046,12047,12048,12049,
-12050,12051,12052,12053,12054,12055,12056,12057,12058,12059,12060,12061,
-12062,12063,12064,12065,12066,12067,12068,12069,12070,12071,12072,12073,
-12074,12075,12076,12077,12078,12079,12080,12081,12082,12083,12084,12085,
-12086,12087,12088,12089,12090,12091,12092,12093,12094,12095,12096,12097,
-12098,12099,12100,12101,12102,12103,12104,12105,12106,12107,12108,12109,
-12110,12111,12112,12113,12114,12115,12116,12117,12118,12119,12120,12121,
-12122,12123,12124,12125,12126,12127,12128,12129,12130,12131,12132,12133,
-12134,12135,12136,12137,12138,12139,12140,12141,12142,12143,12144,12145,
-12146,12147,12148,12149,12150,12151,12152,12153,12154,12155,12156,12157,
-12158,12159,12160,12161,12162,12163,12164,12165,12166,12167,12168,12169,
-12170,12171,12172,12173,12174,12175,12176,12177,12178,12179,12180,12181,
-12182,12183,12184,12185,12186,12187,12188,12189,12190,12191,12192,12193,
-12194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204,12205,
-12206,12207,12208,12209,12210,12211,12212,12213,12214,12215,12216,12217,
-12218,12219,12220,12221,12222,12223,12224,12225,12226,12227,12228,12229,
-12230,12231,12232,12233,12234,12235,12236,12237,12238,12239,12240,12241,
-12242,12243,12244,12245,12246,12247,12248,12249,12250,12251,12252,12253,
-12254,12255,12256,12257,12258,12259,12260,12261,12262,12263,12264,12265,
-12266,12267,12268,12269,12270,12271,12272,12273,12274,12275,12276,12277,
-12278,12279,12280,12281,12282,12283,12284,12285,12286,12287,12288,12289,
-12290,12291,12292,12293,12294,12295,12296,12297,12298,12299,12300,12301,
-12302,12303,12304,12305,12306,12307,12308,12309,12310,12311,12312,12313,
-12314,12315,12316,12317,12318,12319,12320,12321,12322,12323,12324,12325,
-12326,12327,12328,12329,12330,12331,12332,12333,12334,12335,12336,12337,
-12338,12339,12340,12341,12342,12343,12344,12345,12346,12347,12348,12349,
-12350,12351,12352,12353,12354,12355,12356,12357,12358,12359,12360,12361,
-12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,
-12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,
-12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,
-12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,
-12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,
-12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,
-12434,12435,12436,12437,12438,12439,12440,12441,12442,12443,12444,12445,
-12446,12447,12448,12449,12450,12451,12452,12453,12454,12455,12456,12457,
-12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,
-12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,
-12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,
-12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,
-12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,
-12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,
-12530,12531,12532,12533,12534,12535,12536,12537,12538,12539,12540,12541,
-12542,12543,12544,12545,12546,12547,12548,12549,12550,12551,12552,12553,
-12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,
-12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,
-12578,12579,12580,12581,12582,12583,12584,12585,12586,12587,12588,12589,
-12590,12591,12592,12593,12594,12595,12596,12597,12598,12599,12600,12601,
-12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,
-12614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,
-12626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,
-12638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,
-12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,
-12662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,
-12674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,
-12686,12687,12688,12689,12690,12691,12692,12693,12694,12695,12696,12697,
-12698,12699,12700,12701,12702,12703,12704,12705,12706,12707,12708,12709,
-12710,12711,12712,12713,12714,12715,12716,12717,12718,12719,12720,12721,
-12722,12723,12724,12725,12726,12727,12728,12729,12730,12731,12732,12733,
-12734,12735,12736,12737,12738,12739,12740,12741,12742,12743,12744,12745,
-12746,12747,12748,12749,12750,12751,12752,12753,12754,12755,12756,12757,
-12758,12759,12760,12761,12762,12763,12764,12765,12766,12767,12768,12769,
-12770,12771,12772,12773,12774,12775,12776,12777,12778,12779,12780,12781,
-12782,12783,12784,12785,12786,12787,12788,12789,12790,12791,12792,12793,
-12794,12795,12796,12797,12798,12799,12800,12801,12802,12803,12804,12805,
-12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,
-12818,12819,12820,12821,12822,12823,12824,12825,12826,12827,12828,12829,
-12830,12831,12832,12833,12834,12835,12836,12837,12838,12839,12840,12841,
-12842,12843,12844,12845,12846,12847,12848,12849,12850,12851,12852,12853,
-12854,12855,12856,12857,12858,12859,12860,12861,12862,12863,12864,12865,
-12866,12867,12868,12869,12870,12871,12872,12873,12874,12875,12876,12877,
-12878,12879,12880,12881,12882,12883,12884,12885,12886,12887,12888,12889,
-12890,12891,12892,12893,12894,12895,12896,12897,12898,12899,12900,12901,
-12902,12903,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,
-12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,12924,12925,
-12926,12927,12928,12929,12930,12931,12932,12933,12934,12935,12936,12937,
-12938,12939,12940,12941,12942,12943,12944,12945,12946,12947,12948,12949,
-12950,12951,12952,12953,12954,12955,12956,12957,12958,12959,12960,12961,
-12962,12963,12964,12965,12966,12967,12968,12969,12970,12971,12972,12973,
-12974,12975,12976,12977,12978,12979,12980,12981,12982,12983,12984,12985,
-12986,12987,12988,12989,12990,12991,12992,12993,12994,12995,12996,12997,
-12998,12999,13000,13001,13002,13003,13004,13005,13006,13007,13008,13009,
-13010,13011,13012,13013,13014,13015,13016,13017,13018,13019,13020,13021,
-13022,13023,13024,13025,13026,13027,13028,13029,13030,13031,13032,13033,
-13034,13035,13036,13037,13038,13039,13040,13041,13042,13043,13044,13045,
-13046,13047,13048,13049,13050,13051,13052,13053,13054,13055,13056,13057,
-13058,13059,13060,13061,13062,13063,13064,13065,13066,13067,13068,13069,
-13070,13071,13072,13073,13074,13075,13076,13077,13078,13079,13080,13081,
-13082,13083,13084,13085,13086,13087,13088,13089,13090,13091,13092,13093,
-13094,13095,13096,13097,13098,13099,13100,13101,13102,13103,13104,13105,
-13106,13107,13108,13109,13110,13111,13112,13113,13114,13115,13116,13117,
-13118,13119,13120,13121,13122,13123,13124,13125,13126,13127,13128,13129,
-13130,13131,13132,13133,13134,13135,13136,13137,13138,13139,13140,13141,
-13142,13143,13144,13145,13146,13147,13148,13149,13150,13151,13152,13153,
-13154,13155,13156,13157,13158,13159,13160,13161,13162,13163,13164,13165,
-13166,13167,13168,13169,13170,13171,13172,13173,13174,13175,13176,13177,
-13178,13179,13180,13181,13182,13183,13184,13185,13186,13187,13188,13189,
-13190,13191,13192,13193,13194,13195,13196,13197,13198,13199,13200,13201,
-13202,13203,13204,13205,13206,13207,13208,13209,13210,13211,13212,13213,
-13214,13215,13216,13217,13218,13219,13220,13221,13222,13223,13224,13225,
-13226,13227,13228,13229,13230,13231,13232,13233,13234,13235,13236,13237,
-13238,13239,13240,13241,13242,13243,13244,13245,13246,13247,13248,13249,
-13250,13251,13252,13253,13254,13255,13256,13257,13258,13259,13260,13261,
-13262,13263,13264,13265,13266,13267,13268,13269,13270,13271,13272,13273,
-13274,13275,13276,13277,13278,13279,13280,13281,13282,13283,13284,13285,
-13286,13287,13288,13289,13290,13291,13292,13293,13294,13295,13296,13297,
-13298,13299,13300,13301,13302,13303,13304,13305,13306,13307,13308,13309,
-13310,13311,13312,13313,13314,13315,13316,13317,13318,13319,13320,13321,
-13322,13323,13324,13325,13326,13327,13328,13329,13330,13331,13332,13333,
-13334,13335,13336,13337,13338,13339,13340,13341,13342,13343,13344,13345,
-13346,13347,13348,13349,13350,13351,13352,13353,13354,13355,13356,13357,
-13358,13359,13360,13361,13362,13363,13364,13365,13366,13367,13368,13369,
-13370,13371,13372,13373,13374,13375,13376,13377,13378,13379,13380,13381,
-13382,13383,13384,13385,13386,13387,13388,13389,13390,13391,13392,13393,
-13394,13395,13396,13397,13398,13399,13400,13401,13402,13403,13404,13405,
-13406,13407,13408,13409,13410,13411,13412,13413,13414,13415,13416,13417,
-13418,13419,13420,13421,13422,13423,13424,13425,13426,13427,13428,13429,
-13430,13431,13432,13433,13434,13435,13436,13437,13438,13439,13440,13441,
-13442,13443,13444,13445,13446,13447,13448,13449,13450,13451,13452,13453,
-13454,13455,13456,13457,13458,13459,13460,13461,13462,13463,13464,13465,
-13466,13467,13468,13469,13470,13471,13472,13473,13474,13475,13476,13477,
-13478,13479,13480,13481,13482,13483,13484,13485,13486,13487,13488,13489,
-13490,13491,13492,13493,13494,13495,13496,13497,13498,13499,13500,13501,
-13502,13503,13504,13505,13506,13507,13508,13509,13510,13511,13512,13513,
-13514,13515,13516,13517,13518,13519,13520,13521,13522,13523,13524,13525,
-13526,13527,13528,13529,13530,13531,13532,13533,13534,13535,13536,13537,
-13538,13539,13540,13541,13542,13543,13544,13545,13546,13547,13548,13549,
-13550,13551,13552,13553,13554,13555,13556,13557,13558,13559,13560,13561,
-13562,13563,13564,13565,13566,13567,13568,13569,13570,13571,13572,13573,
-13574,13575,13576,13577,13578,13579,13580,13581,13582,13583,13584,13585,
-13586,13587,13588,13589,13590,13591,13592,13593,13594,13595,13596,13597,
-13598,13599,13600,13601,13602,13603,13604,13605,13606,13607,13608,13609,
-13610,13611,13612,13613,13614,13615,13616,13617,13618,13619,13620,13621,
-13622,13623,13624,13625,13626,13627,13628,13629,13630,13631,13632,13633,
-13634,13635,13636,13637,13638,13639,13640,13641,13642,13643,13644,13645,
-13646,13647,13648,13649,13650,13651,13652,13653,13654,13655,13656,13657,
-13658,13659,13660,13661,13662,13663,13664,13665,13666,13667,13668,13669,
-13670,13671,13672,13673,13674,13675,13676,13677,13678,13679,13680,13681,
-13682,13683,13684,13685,13686,13687,13688,13689,13690,13691,13692,13693,
-13694,13695,13696,13697,13698,13699,13700,13701,13702,13703,13704,13705,
-13706,13707,13708,13709,13710,13711,13712,13713,13714,13715,13716,13717,
-13718,13719,13720,13721,13722,13723,13724,13725,13726,13727,13728,13729,
-13730,13731,13732,13733,13734,13735,13736,13737,13738,13739,13740,13741,
-13742,13743,13744,13745,13746,13747,13748,13749,13750,13751,13752,13753,
-13754,13755,13756,13757,13758,13759,13760,13761,13762,13763,13764,13765,
-13766,13767,13768,13769,13770,13771,13772,13773,13774,13775,13776,13777,
-13778,13779,13780,13781,13782,13783,13784,13785,13786,13787,13788,13789,
-13790,13791,13792,13793,13794,13795,13796,13797,13798,13799,13800,13801,
-13802,13803,13804,13805,13806,13807,13808,13809,13810,13811,13812,13813,
-13814,13815,13816,13817,13818,13819,13820,13821,13822,13823,13824,13825,
-13826,13827,13828,13829,13830,13831,13832,13833,13834,13835,13836,13837,
-13838,13839,13840,13841,13842,13843,13844,13845,13846,13847,13848,13849,
-13850,13851,13852,13853,13854,13855,13856,13857,13858,13859,13860,13861,
-13862,13863,13864,13865,13866,13867,13868,13869,13870,13871,13872,13873,
-13874,13875,13876,13877,13878,13879,13880,13881,13882,13883,13884,13885,
-13886,13887,13888,13889,13890,13891,13892,13893,13894,13895,13896,13897,
-13898,13899,13900,13901,13902,13903,13904,13905,13906,13907,13908,13909,
-13910,13911,13912,13913,13914,13915,13916,13917,13918,13919,13920,13921,
-13922,13923,13924,13925,13926,13927,13928,13929,13930,13931,13932,13933,
-13934,13935,13936,13937,13938,13939,13940,13941,13942,13943,13944,13945,
-13946,13947,13948,13949,13950,13951,13952,13953,13954,13955,13956,13957,
-13958,13959,13960,13961,13962,13963,13964,13965,13966,13967,13968,13969,
-13970,13971,13972,13973,13974,13975,13976,13977,13978,13979,13980,13981,
-13982,13983,13984,13985,13986,13987,13988,13989,13990,13991,13992,13993,
-13994,13995,13996,13997,13998,13999,14000,14001,14002,14003,14004,14005,
-14006,14007,14008,14009,14010,14011,14012,14013,14014,14015,14016,14017,
-14018,14019,14020,14021,14022,14023,14024,14025,14026,14027,14028,14029,
-14030,14031,14032,14033,14034,14035,14036,14037,14038,14039,14040,14041,
-14042,14043,14044,14045,14046,14047,14048,14049,14050,14051,14052,14053,
-14054,14055,14056,14057,14058,14059,14060,14061,14062,14063,14064,14065,
-14066,14067,14068,14069,14070,14071,14072,14073,14074,14075,14076,14077,
-14078,14079,14080,14081,14082,14083,14084,14085,14086,14087,14088,14089,
-14090,14091,14092,14093,14094,14095,14096,14097,14098,14099,14100,14101,
-14102,14103,14104,14105,14106,14107,14108,14109,14110,14111,14112,14113,
-14114,14115,14116,14117,14118,14119,14120,14121,14122,14123,14124,14125,
-14126,14127,14128,14129,14130,14131,14132,14133,14134,14135,14136,14137,
-14138,14139,14140,14141,14142,14143,14144,14145,14146,14147,14148,14149,
-14150,14151,14152,14153,14154,14155,14156,14157,14158,14159,14160,14161,
-14162,14163,14164,14165,14166,14167,14168,14169,14170,14171,14172,14173,
-14174,14175,14176,14177,14178,14179,14180,14181,14182,14183,14184,14185,
-14186,14187,14188,14189,14190,14191,14192,14193,14194,14195,14196,14197,
-14198,14199,14200,14201,14202,14203,14204,14205,14206,14207,14208,14209,
-14210,14211,14212,14213,14214,14215,14216,14217,14218,14219,14220,14221,
-14222,14223,14224,14225,14226,14227,14228,14229,14230,14231,14232,14233,
-14234,14235,14236,14237,14238,14239,14240,14241,14242,14243,14244,14245,
-14246,14247,14248,14249,14250,14251,14252,14253,14254,14255,14256,14257,
-14258,14259,14260,14261,14262,14263,14264,14265,14266,14267,14268,14269,
-14270,14271,14272,14273,14274,14275,14276,14277,14278,14279,14280,14281,
-14282,14283,14284,14285,14286,14287,14288,14289,14290,14291,14292,14293,
-14294,14295,14296,14297,14298,14299,14300,14301,14302,14303,14304,14305,
-14306,14307,14308,14309,14310,14311,14312,14313,14314,14315,14316,14317,
-14318,14319,14320,14321,14322,14323,14324,14325,14326,14327,14328,14329,
-14330,14331,14332,14333,14334,14335,14336,14337,14338,14339,14340,14341,
-14342,14343,14344,14345,14346,14347,14348,14349,14350,14351,14352,14353,
-14354,14355,14356,14357,14358,14359,14360,14361,14362,14363,14364,14365,
-14366,14367,14368,14369,14370,14371,14372,14373,14374,14375,14376,14377,
-14378,14379,14380,14381,14382,14383,14384,14385,14386,14387,14388,14389,
-14390,14391,14392,14393,14394,14395,14396,14397,14398,14399,14400,14401,
-14402,14403,14404,14405,14406,14407,14408,14409,14410,14411,14412,14413,
-14414,14415,14416,14417,14418,14419,14420,14421,14422,14423,14424,14425,
-14426,14427,14428,14429,14430,14431,14432,14433,14434,14435,14436,14437,
-14438,14439,14440,14441,14442,14443,14444,14445,14446,14447,14448,14449,
-14450,14451,14452,14453,14454,14455,14456,14457,14458,14459,14460,14461,
-14462,14463,14464,14465,14466,14467,14468,14469,14470,14471,14472,14473,
-14474,14475,14476,14477,14478,14479,14480,14481,14482,14483,14484,14485,
-14486,14487,14488,14489,14490,14491,14492,14493,14494,14495,14496,14497,
-14498,14499,14500,14501,14502,14503,14504,14505,14506,14507,14508,14509,
-14510,14511,14512,14513,14514,14515,14516,14517,14518,14519,14520,14521,
-14522,14523,14524,14525,14526,14527,14528,14529,14530,14531,14532,14533,
-14534,14535,14536,14537,14538,14539,14540,14541,14542,14543,14544,14545,
-14546,14547,14548,14549,14550,14551,14552,14553,14554,14555,14556,14557,
-14558,14559,14560,14561,14562,14563,14564,14565,14566,14567,14568,14569,
-14570,14571,14572,14573,14574,14575,14576,14577,14578,14579,14580,14581,
-14582,14583,14584,14585,14586,14587,14588,14589,14590,14591,14592,14593,
-14594,14595,14596,14597,14598,14599,14600,14601,14602,14603,14604,14605,
-14606,14607,14608,14609,14610,14611,14612,14613,14614,14615,14616,14617,
-14618,14619,14620,14621,14622,14623,14624,14625,14626,14627,14628,14629,
-14630,14631,14632,14633,14634,14635,14636,14637,14638,14639,14640,14641,
-14642,14643,14644,14645,14646,14647,14648,14649,14650,14651,14652,14653,
-14654,14655,14656,14657,14658,14659,14660,14661,14662,14663,14664,14665,
-14666,14667,14668,14669,14670,14671,14672,14673,14674,14675,14676,14677,
-14678,14679,14680,14681,14682,14683,14684,14685,14686,14687,14688,14689,
-14690,14691,14692,14693,14694,14695,14696,14697,14698,14699,14700,14701,
-14702,14703,14704,14705,14706,14707,14708,14709,14710,14711,14712,14713,
-14714,14715,14716,14717,14718,14719,14720,14721,14722,14723,14724,14725,
-14726,14727,14728,14729,14730,14731,14732,14733,14734,14735,14736,14737,
-14738,14739,14740,14741,14742,14743,14744,14745,14746,14747,14748,14749,
-14750,14751,14752,14753,14754,14755,14756,14757,14758,14759,14760,14761,
-14762,14763,14764,14765,14766,14767,14768,14769,14770,14771,14772,14773,
-14774,14775,14776,14777,14778,14779,14780,14781,14782,14783,14784,14785,
-14786,14787,14788,14789,14790,14791,14792,14793,14794,14795,14796,14797,
-14798,14799,14800,14801,14802,14803,14804,14805,14806,14807,14808,14809,
-14810,14811,14812,14813,14814,14815,14816,14817,14818,14819,14820,14821,
-14822,14823,14824,14825,14826,14827,14828,14829,14830,14831,14832,14833,
-14834,14835,14836,14837,14838,14839,14840,14841,14842,14843,14844,14845,
-14846,14847,14848,14849,14850,14851,14852,14853,14854,14855,14856,14857,
-14858,14859,14860,14861,14862,14863,14864,14865,14866,14867,14868,14869,
-14870,14871,14872,14873,14874,14875,14876,14877,14878,14879,14880,14881,
-14882,14883,14884,14885,14886,14887,14888,14889,14890,14891,14892,14893,
-14894,14895,14896,14897,14898,14899,14900,14901,14902,14903,14904,14905,
-14906,14907,14908,14909,14910,14911,14912,14913,14914,14915,14916,14917,
-14918,14919,14920,14921,14922,14923,14924,14925,14926,14927,14928,14929,
-14930,14931,14932,14933,14934,14935,14936,14937,14938,14939,14940,14941,
-14942,14943,14944,14945,14946,14947,14948,14949,14950,14951,14952,14953,
-14954,14955,14956,14957,14958,14959,14960,14961,14962,14963,14964,14965,
-14966,14967,14968,14969,14970,14971,14972,14973,14974,14975,14976,14977,
-14978,14979,14980,14981,14982,14983,14984,14985,14986,14987,14988,14989,
-14990,14991,14992,14993,14994,14995,14996,14997,14998,14999,15000,15001,
-15002,15003,15004,15005,15006,15007,15008,15009,15010,15011,15012,15013,
-15014,15015,15016,15017,15018,15019,15020,15021,15022,15023,15024,15025,
-15026,15027,15028,15029,15030,15031,15032,15033,15034,15035,15036,15037,
-15038,15039,15040,15041,15042,15043,15044,15045,15046,15047,15048,15049,
-15050,15051,15052,15053,15054,15055,15056,15057,15058,15059,15060,15061,
-15062,15063,15064,15065,15066,15067,15068,15069,15070,15071,15072,15073,
-15074,15075,15076,15077,15078,15079,15080,15081,15082,15083,15084,15085,
-15086,15087,15088,15089,15090,15091,15092,15093,15094,15095,15096,15097,
-15098,15099,15100,15101,15102,15103,15104,15105,15106,15107,15108,15109,
-15110,15111,15112,15113,15114,15115,15116,15117,15118,15119,15120,15121,
-15122,15123,15124,15125,15126,15127,15128,15129,15130,15131,15132,15133,
-15134,15135,15136,15137,15138,15139,15140,15141,15142,15143,15144,15145,
-15146,15147,15148,15149,15150,15151,15152,15153,15154,15155,15156,15157,
-15158,15159,15160,15161,15162,15163,15164,15165,15166,15167,15168,15169,
-15170,15171,15172,15173,15174,15175,15176,15177,15178,15179,15180,15181,
-15182,15183,15184,15185,15186,15187,15188,15189,15190,15191,15192,15193,
-15194,15195,15196,15197,15198,15199,15200,15201,15202,15203,15204,15205,
-15206,15207,15208,15209,15210,15211,15212,15213,15214,15215,15216,15217,
-15218,15219,15220,15221,15222,15223,15224,15225,15226,15227,15228,15229,
-15230,15231,15232,15233,15234,15235,15236,15237,15238,15239,15240,15241,
-15242,15243,15244,15245,15246,15247,15248,15249,15250,15251,15252,15253,
-15254,15255,15256,15257,15258,15259,15260,15261,15262,15263,15264,15265,
-15266,15267,15268,15269,15270,15271,15272,15273,15274,15275,15276,15277,
-15278,15279,15280,15281,15282,15283,15284,15285,15286,15287,15288,15289,
-15290,15291,15292,15293,15294,15295,15296,15297,15298,15299,15300,15301,
-15302,15303,15304,15305,15306,15307,15308,15309,15310,15311,15312,15313,
-15314,15315,15316,15317,15318,15319,15320,15321,15322,15323,15324,15325,
-15326,15327,15328,15329,15330,15331,15332,15333,15334,15335,15336,15337,
-15338,15339,15340,15341,15342,15343,15344,15345,15346,15347,15348,15349,
-15350,15351,15352,15353,15354,15355,15356,15357,15358,15359,15360,15361,
-15362,15363,15364,15365,15366,15367,15368,15369,15370,15371,15372,15373,
-15374,15375,15376,15377,15378,15379,15380,15381,15382,15383,15384,15385,
-15386,15387,15388,15389,15390,15391,15392,15393,15394,15395,15396,15397,
-15398,15399,15400,15401,15402,15403,15404,15405,15406,15407,15408,15409,
-15410,15411,15412,15413,15414,15415,15416,15417,15418,15419,15420,15421,
-15422,15423,15424,15425,15426,15427,15428,15429,15430,15431,15432,15433,
-15434,15435,15436,15437,15438,15439,15440,15441,15442,15443,15444,15445,
-15446,15447,15448,15449,15450,15451,15452,15453,15454,15455,15456,15457,
-15458,15459,15460,15461,15462,15463,15464,15465,15466,15467,15468,15469,
-15470,15471,15472,15473,15474,15475,15476,15477,15478,15479,15480,15481,
-15482,15483,15484,15485,15486,15487,15488,15489,15490,15491,15492,15493,
-15494,15495,15496,15497,15498,15499,15500,15501,15502,15503,15504,15505,
-15506,15507,15508,15509,15510,15511,15512,15513,15514,15515,15516,15517,
-15518,15519,15520,15521,15522,15523,15524,15525,15526,15527,15528,15529,
-15530,15531,15532,15533,15534,15535,15536,15537,15538,15539,15540,15541,
-15542,15543,15544,15545,15546,15547,15548,15549,15550,15551,15552,15553,
-15554,15555,15556,15557,15558,15559,15560,15561,15562,15563,15564,15565,
-15566,15567,15568,15569,15570,15571,15572,15573,15574,15575,15576,15577,
-15578,15579,15580,15581,15582,15583,15584,15585,15586,15587,15588,15589,
-15590,15591,15592,15593,15594,15595,15596,15597,15598,15599,15600,15601,
-15602,15603,15604,15605,15606,15607,15608,15609,15610,15611,15612,15613,
-15614,15615,15616,15617,15618,15619,15620,15621,15622,15623,15624,15625,
-15626,15627,15628,15629,15630,15631,15632,15633,15634,15635,15636,15637,
-15638,15639,15640,15641,15642,15643,15644,15645,15646,15647,15648,15649,
-15650,15651,15652,15653,15654,15655,15656,15657,15658,15659,15660,15661,
-15662,15663,15664,15665,15666,15667,15668,15669,15670,15671,15672,15673,
-15674,15675,15676,15677,15678,15679,15680,15681,15682,15683,15684,15685,
-15686,15687,15688,15689,15690,15691,15692,15693,15694,15695,15696,15697,
-15698,15699,15700,15701,15702,15703,15704,15705,15706,15707,15708,15709,
-15710,15711,15712,15713,15714,15715,15716,15717,15718,15719,15720,15721,
-15722,15723,15724,15725,15726,15727,15728,15729,15730,15731,15732,15733,
-15734,15735,15736,15737,15738,15739,15740,15741,15742,15743,15744,15745,
-15746,15747,15748,15749,15750,15751,15752,15753,15754,15755,15756,15757,
-15758,15759,15760,15761,15762,15763,15764,15765,15766,15767,15768,15769,
-15770,15771,15772,15773,15774,15775,15776,15777,15778,15779,15780,15781,
-15782,15783,15784,15785,15786,15787,15788,15789,15790,15791,15792,15793,
-15794,15795,15796,15797,15798,15799,15800,15801,15802,15803,15804,15805,
-15806,15807,15808,15809,15810,15811,15812,15813,15814,15815,15816,15817,
-15818,15819,15820,15821,15822,15823,15824,15825,15826,15827,15828,15829,
-15830,15831,15832,15833,15834,15835,15836,15837,15838,15839,15840,15841,
-15842,15843,15844,15845,15846,15847,15848,15849,15850,15851,15852,15853,
-15854,15855,15856,15857,15858,15859,15860,15861,15862,15863,15864,15865,
-15866,15867,15868,15869,15870,15871,15872,15873,15874,15875,15876,15877,
-15878,15879,15880,15881,15882,15883,15884,15885,15886,15887,15888,15889,
-15890,15891,15892,15893,15894,15895,15896,15897,15898,15899,15900,15901,
-15902,15903,15904,15905,15906,15907,15908,15909,15910,15911,15912,15913,
-15914,15915,15916,15917,15918,15919,15920,15921,15922,15923,15924,15925,
-15926,15927,15928,15929,15930,15931,15932,15933,15934,15935,15936,15937,
-15938,15939,15940,15941,15942,15943,15944,15945,15946,15947,15948,15949,
-15950,15951,15952,15953,15954,15955,15956,15957,15958,15959,15960,15961,
-15962,15963,15964,15965,15966,15967,15968,15969,15970,15971,15972,15973,
-15974,15975,15976,15977,15978,15979,15980,15981,15982,15983,15984,15985,
-15986,15987,15988,15989,15990,15991,15992,15993,15994,15995,15996,15997,
-15998,15999,16000,16001,16002,16003,16004,16005,16006,16007,16008,16009,
-16010,16011,16012,16013,16014,16015,16016,16017,16018,16019,16020,16021,
-16022,16023,16024,16025,16026,16027,16028,16029,16030,16031,16032,16033,
-16034,16035,16036,16037,16038,16039,16040,16041,16042,16043,16044,16045,
-16046,16047,16048,16049,16050,16051,16052,16053,16054,16055,16056,16057,
-16058,16059,16060,16061,16062,16063,16064,16065,16066,16067,16068,16069,
-16070,16071,16072,16073,16074,16075,16076,16077,16078,16079,16080,16081,
-16082,16083,16084,16085,16086,16087,16088,16089,16090,16091,16092,16093,
-16094,16095,16096,16097,16098,16099,16100,16101,16102,16103,16104,16105,
-16106,16107,16108,16109,16110,16111,16112,16113,16114,16115,16116,16117,
-16118,16119,16120,16121,16122,16123,16124,16125,16126,16127,16128,16129,
-16130,16131,16132,16133,16134,16135,16136,16137,16138,16139,16140,16141,
-16142,16143,16144,16145,16146,16147,16148,16149,16150,16151,16152,16153,
-16154,16155,16156,16157,16158,16159,16160,16161,16162,16163,16164,16165,
-16166,16167,16168,16169,16170,16171,16172,16173,16174,16175,16176,16177,
-16178,16179,16180,16181,16182,16183,16184,16185,16186,16187,16188,16189,
-16190,16191,16192,16193,16194,16195,16196,16197,16198,16199,16200,16201,
-16202,16203,16204,16205,16206,16207,16208,16209,16210,16211,16212,16213,
-16214,16215,16216,16217,16218,16219,16220,16221,16222,16223,16224,16225,
-16226,16227,16228,16229,16230,16231,16232,16233,16234,16235,16236,16237,
-16238,16239,16240,16241,16242,16243,16244,16245,16246,16247,16248,16249,
-16250,16251,16252,16253,16254,16255,16256,16257,16258,16259,16260,16261,
-16262,16263,16264,16265,16266,16267,16268,16269,16270,16271,16272,16273,
-16274,16275,16276,16277,16278,16279,16280,16281,16282,16283,16284,16285,
-16286,16287,16288,16289,16290,16291,16292,16293,16294,16295,16296,16297,
-16298,16299,16300,16301,16302,16303,16304,16305,16306,16307,16308,16309,
-16310,16311,16312,16313,16314,16315,16316,16317,16318,16319,16320,16321,
-16322,16323,16324,16325,16326,16327,16328,16329,16330,16331,16332,16333,
-16334,16335,16336,16337,16338,16339,16340,16341,16342,16343,16344,16345,
-16346,16347,16348,16349,16350,16351,16352,16353,16354,16355,16356,16357,
-16358,16359,16360,16361,16362,16363,16364,16365,16366,16367,16368,16369,
-16370,16371,16372,16373,16374,16375,16376,16377,16378,16379,16380,16381,
-16382,16383,16384,16385,16386,16387,16388,16389,16390,16391,16392,16393,
-16394,16395,16396,16397,16398,16399,16400,16401,16402,16403,16404,16405,
-16406,16407,16408,16409,16410,16411,16412,16413,16414,16415,16416,16417,
-16418,16419,16420,16421,16422,16423,16424,16425,16426,16427,16428,16429,
-16430,16431,16432,16433,16434,16435,16436,16437,16438,16439,16440,16441,
-16442,16443,16444,16445,16446,16447,16448,16449,16450,16451,16452,16453,
-16454,16455,16456,16457,16458,16459,16460,16461,16462,16463,16464,16465,
-16466,16467,16468,16469,16470,16471,16472,16473,16474,16475,16476,16477,
-16478,16479,16480,16481,16482,16483,16484,16485,16486,16487,16488,16489,
-16490,16491,16492,16493,16494,16495,16496,16497,16498,16499,16500,16501,
-16502,16503,16504,16505,16506,16507,16508,16509,16510,16511,16512,16513,
-16514,16515,16516,16517,16518,16519,16520,16521,16522,16523,16524,16525,
-16526,16527,16528,16529,16530,16531,16532,16533,16534,16535,16536,16537,
-16538,16539,16540,16541,16542,16543,16544,16545,16546,16547,16548,16549,
-16550,16551,16552,16553,16554,16555,16556,16557,16558,16559,16560,16561,
-16562,16563,16564,16565,16566,16567,16568,16569,16570,16571,16572,16573,
-16574,16575,16576,16577,16578,16579,16580,16581,16582,16583,16584,16585,
-16586,16587,16588,16589,16590,16591,16592,16593,16594,16595,16596,16597,
-16598,16599,16600,16601,16602,16603,16604,16605,16606,16607,16608,16609,
-16610,16611,16612,16613,16614,16615,16616,16617,16618,16619,16620,16621,
-16622,16623,16624,16625,16626,16627,16628,16629,16630,16631,16632,16633,
-16634,16635,16636,16637,16638,16639,16640,16641,16642,16643,16644,16645,
-16646,16647,16648,16649,16650,16651,16652,16653,16654,16655,16656,16657,
-16658,16659,16660,16661,16662,16663,16664,16665,16666,16667,16668,16669,
-16670,16671,16672,16673,16674,16675,16676,16677,16678,16679,16680,16681,
-16682,16683,16684,16685,16686,16687,16688,16689,16690,16691,16692,16693,
-16694,16695,16696,16697,16698,16699,16700,16701,16702,16703,16704,16705,
-16706,16707,16708,16709,16710,16711,16712,16713,16714,16715,16716,16717,
-16718,16719,16720,16721,16722,16723,16724,16725,16726,16727,16728,16729,
-16730,16731,16732,16733,16734,16735,16736,16737,16738,16739,16740,16741,
-16742,16743,16744,16745,16746,16747,16748,16749,16750,16751,16752,16753,
-16754,16755,16756,16757,16758,16759,16760,16761,16762,16763,16764,16765,
-16766,16767,16768,16769,16770,16771,16772,16773,16774,16775,16776,16777,
-16778,16779,16780,16781,16782,16783,16784,16785,16786,16787,16788,16789,
-16790,16791,16792,16793,16794,16795,16796,16797,16798,16799,16800,16801,
-16802,16803,16804,16805,16806,16807,16808,16809,16810,16811,16812,16813,
-16814,16815,16816,16817,16818,16819,16820,16821,16822,16823,16824,16825,
-16826,16827,16828,16829,16830,16831,16832,16833,16834,16835,16836,16837,
-16838,16839,16840,16841,16842,16843,16844,16845,16846,16847,16848,16849,
-16850,16851,16852,16853,16854,16855,16856,16857,16858,16859,16860,16861,
-16862,16863,16864,16865,16866,16867,16868,16869,16870,16871,16872,16873,
-16874,16875,16876,16877,16878,16879,16880,16881,16882,16883,16884,16885,
-16886,16887,16888,16889,16890,16891,16892,16893,16894,16895,16896,16897,
-16898,16899,16900,16901,16902,16903,16904,16905,16906,16907,16908,16909,
-16910,16911,16912,16913,16914,16915,16916,16917,16918,16919,16920,16921,
-16922,16923,16924,16925,16926,16927,16928,16929,16930,16931,16932,16933,
-16934,16935,16936,16937,16938,16939,16940,16941,16942,16943,16944,16945,
-16946,16947,16948,16949,16950,16951,16952,16953,16954,16955,16956,16957,
-16958,16959,16960,16961,16962,16963,16964,16965,16966,16967,16968,16969,
-16970,16971,16972,16973,16974,16975,16976,16977,16978,16979,16980,16981,
-16982,16983,16984,16985,16986,16987,16988,16989,16990,16991,16992,16993,
-16994,16995,16996,16997,16998,16999,17000,17001,17002,17003,17004,17005,
-17006,17007,17008,17009,17010,17011,17012,17013,17014,17015,17016,17017,
-17018,17019,17020,17021,17022,17023,17024,17025,17026,17027,17028,17029,
-17030,17031,17032,17033,17034,17035,17036,17037,17038,17039,17040,17041,
-17042,17043,17044,17045,17046,17047,17048,17049,17050,17051,17052,17053,
-17054,17055,17056,17057,17058,17059,17060,17061,17062,17063,17064,17065,
-17066,17067,17068,17069,17070,17071,17072,17073,17074,17075,17076,17077,
-17078,17079,17080,17081,17082,17083,17084,17085,17086,17087,17088,17089,
-17090,17091,17092,17093,17094,17095,17096,17097,17098,17099,17100,17101,
-17102,17103,17104,17105,17106,17107,17108,17109,17110,17111,17112,17113,
-17114,17115,17116,17117,17118,17119,17120,17121,17122,17123,17124,17125,
-17126,17127,17128,17129,17130,17131,17132,17133,17134,17135,17136,17137,
-17138,17139,17140,17141,17142,17143,17144,17145,17146,17147,17148,17149,
-17150,17151,17152,17153,17154,17155,17156,17157,17158,17159,17160,17161,
-17162,17163,17164,17165,17166,17167,17168,17169,17170,17171,17172,17173,
-17174,17175,17176,17177,17178,17179,17180,17181,17182,17183,17184,17185,
-17186,17187,17188,17189,17190,17191,17192,17193,17194,17195,17196,17197,
-17198,17199,17200,17201,17202,17203,17204,17205,17206,17207,17208,17209,
-17210,17211,17212,17213,17214,17215,17216,17217,17218,17219,17220,17221,
-17222,17223,17224,17225,17226,17227,17228,17229,17230,17231,17232,17233,
-17234,17235,17236,17237,17238,17239,17240,17241,17242,17243,17244,17245,
-17246,17247,17248,17249,17250,17251,17252,17253,17254,17255,17256,17257,
-17258,17259,17260,17261,17262,17263,17264,17265,17266,17267,17268,17269,
-17270,17271,17272,17273,17274,17275,17276,17277,17278,17279,17280,17281,
-17282,17283,17284,17285,17286,17287,17288,17289,17290,17291,17292,17293,
-17294,17295,17296,17297,17298,17299,17300,17301,17302,17303,17304,17305,
-17306,17307,17308,17309,17310,17311,17312,17313,17314,17315,17316,17317,
-17318,17319,17320,17321,17322,17323,17324,17325,17326,17327,17328,17329,
-17330,17331,17332,17333,17334,17335,17336,17337,17338,17339,17340,17341,
-17342,17343,17344,17345,17346,17347,17348,17349,17350,17351,17352,17353,
-17354,17355,17356,17357,17358,17359,17360,17361,17362,17363,17364,17365,
-17366,17367,17368,17369,17370,17371,17372,17373,17374,17375,17376,17377,
-17378,17379,17380,17381,17382,17383,17384,17385,17386,17387,17388,17389,
-17390,17391,17392,17393,17394,17395,17396,17397,17398,17399,17400,17401,
-17402,17403,17404,17405,17406,17407,17408,17409,17410,17411,17412,17413,
-17414,17415,17416,17417,17418,17419,17420,17421,17422,17423,17424,17425,
-17426,17427,17428,17429,17430,17431,17432,17433,17434,17435,17436,17437,
-17438,17439,17440,17441,17442,17443,17444,17445,17446,17447,17448,17449,
-17450,17451,17452,17453,17454,17455,17456,17457,17458,17459,17460,17461,
-17462,17463,17464,17465,17466,17467,17468,17469,17470,17471,17472,17473,
-17474,17475,17476,17477,17478,17479,17480,17481,17482,17483,17484,17485,
-17486,17487,17488,17489,17490,17491,17492,17493,17494,17495,17496,17497,
-17498,17499,17500,17501,17502,17503,17504,17505,17506,17507,17508,17509,
-17510,17511,17512,17513,17514,17515,17516,17517,17518,17519,17520,17521,
-17522,17523,17524,17525,17526,17527,17528,17529,17530,17531,17532,17533,
-17534,17535,17536,17537,17538,17539,17540,17541,17542,17543,17544,17545,
-17546,17547,17548,17549,17550,17551,17552,17553,17554,17555,17556,17557,
-17558,17559,17560,17561,17562,17563,17564,17565,17566,17567,17568,17569,
-17570,17571,17572,17573,17574,17575,17576,17577,17578,17579,17580,17581,
-17582,17583,17584,17585,17586,17587,17588,17589,17590,17591,17592,17593,
-17594,17595,17596,17597,17598,17599,17600,17601,17602,17603,17604,17605,
-17606,17607,17608,17609,17610,17611,17612,17613,17614,17615,17616,17617,
-17618,17619,17620,17621,17622,17623,17624,17625,17626,17627,17628,17629,
-17630,17631,17632,17633,17634,17635,17636,17637,17638,17639,17640,17641,
-17642,17643,17644,17645,17646,17647,17648,17649,17650,17651,17652,17653,
-17654,17655,17656,17657,17658,17659,17660,17661,17662,17663,17664,17665,
-17666,17667,17668,17669,17670,17671,17672,17673,17674,17675,17676,17677,
-17678,17679,17680,17681,17682,17683,17684,17685,17686,17687,17688,17689,
-17690,17691,17692,17693,17694,17695,17696,17697,17698,17699,17700,17701,
-17702,17703,17704,17705,17706,17707,17708,17709,17710,17711,17712,17713,
-17714,17715,17716,17717,17718,17719,17720,17721,17722,17723,17724,17725,
-17726,17727,17728,17729,17730,17731,17732,17733,17734,17735,17736,17737,
-17738,17739,17740,17741,17742,17743,17744,17745,17746,17747,17748,17749,
-17750,17751,17752,17753,17754,17755,17756,17757,17758,17759,17760,17761,
-17762,17763,17764,17765,17766,17767,17768,17769,17770,17771,17772,17773,
-17774,17775,17776,17777,17778,17779,17780,17781,17782,17783,17784,17785,
-17786,17787,17788,17789,17790,17791,17792,17793,17794,17795,17796,17797,
-17798,17799,17800,17801,17802,17803,17804,17805,17806,17807,17808,17809,
-17810,17811,17812,17813,17814,17815,17816,17817,17818,17819,17820,17821,
-17822,17823,17824,17825,17826,17827,17828,17829,17830,17831,17832,17833,
-17834,17835,17836,17837,17838,17839,17840,17841,17842,17843,17844,17845,
-17846,17847,17848,17849,17850,17851,17852,17853,17854,17855,17856,17857,
-17858,17859,17860,17861,17862,17863,17864,17865,17866,17867,17868,17869,
-17870,17871,17872,17873,17874,17875,17876,17877,17878,17879,17880,17881,
-17882,17883,17884,17885,17886,17887,17888,17889,17890,17891,17892,17893,
-17894,17895,17896,17897,17898,17899,17900,17901,17902,17903,17904,17905,
-17906,17907,17908,17909,17910,17911,17912,17913,17914,17915,17916,17917,
-17918,17919,17920,17921,17922,17923,17924,17925,17926,17927,17928,17929,
-17930,17931,17932,17933,17934,17935,17936,17937,17938,17939,17940,17941,
-17942,17943,17944,17945,17946,17947,17948,17949,17950,17951,17952,17953,
-17954,17955,17956,17957,17958,17959,17960,17961,17962,17963,17964,17965,
-17966,17967,17968,17969,17970,17971,17972,17973,17974,17975,17976,17977,
-17978,17979,17980,17981,17982,17983,17984,17985,17986,17987,17988,17989,
-17990,17991,17992,17993,17994,17995,17996,17997,17998,17999,18000,18001,
-18002,18003,18004,18005,18006,18007,18008,18009,18010,18011,18012,18013,
-18014,18015,18016,18017,18018,18019,18020,18021,18022,18023,18024,18025,
-18026,18027,18028,18029,18030,18031,18032,18033,18034,18035,18036,18037,
-18038,18039,18040,18041,18042,18043,18044,18045,18046,18047,18048,18049,
-18050,18051,18052,18053,18054,18055,18056,18057,18058,18059,18060,18061,
-18062,18063,18064,18065,18066,18067,18068,18069,18070,18071,18072,18073,
-18074,18075,18076,18077,18078,18079,18080,18081,18082,18083,18084,18085,
-18086,18087,18088,18089,18090,18091,18092,18093,18094,18095,18096,18097,
-18098,18099,18100,18101,18102,18103,18104,18105,18106,18107,18108,18109,
-18110,18111,18112,18113,18114,18115,18116,18117,18118,18119,18120,18121,
-18122,18123,18124,18125,18126,18127,18128,18129,18130,18131,18132,18133,
-18134,18135,18136,18137,18138,18139,18140,18141,18142,18143,18144,18145,
-18146,18147,18148,18149,18150,18151,18152,18153,18154,18155,18156,18157,
-18158,18159,18160,18161,18162,18163,18164,18165,18166,18167,18168,18169,
-18170,18171,18172,18173,18174,18175,18176,18177,18178,18179,18180,18181,
-18182,18183,18184,18185,18186,18187,18188,18189,18190,18191,18192,18193,
-18194,18195,18196,18197,18198,18199,18200,18201,18202,18203,18204,18205,
-18206,18207,18208,18209,18210,18211,18212,18213,18214,18215,18216,18217,
-18218,18219,18220,18221,18222,18223,18224,18225,18226,18227,18228,18229,
-18230,18231,18232,18233,18234,18235,18236,18237,18238,18239,18240,18241,
-18242,18243,18244,18245,18246,18247,18248,18249,18250,18251,18252,18253,
-18254,18255,18256,18257,18258,18259,18260,18261,18262,18263,18264,18265,
-18266,18267,18268,18269,18270,18271,18272,18273,18274,18275,18276,18277,
-18278,18279,18280,18281,18282,18283,18284,18285,18286,18287,18288,18289,
-18290,18291,18292,18293,18294,18295,18296,18297,18298,18299,18300,18301,
-18302,18303,18304,18305,18306,18307,18308,18309,18310,18311,18312,18313,
-18314,18315,18316,18317,18318,18319,18320,18321,18322,18323,18324,18325,
-18326,18327,18328,18329,18330,18331,18332,18333,18334,18335,18336,18337,
-18338,18339,18340,18341,18342,18343,18344,18345,18346,18347,18348,18349,
-18350,18351,18352,18353,18354,18355,18356,18357,18358,18359,18360,18361,
-18362,18363,18364,18365,18366,18367,18368,18369,18370,18371,18372,18373,
-18374,18375,18376,18377,18378,18379,18380,18381,18382,18383,18384,18385,
-18386,18387,18388,18389,18390,18391,18392,18393,18394,18395,18396,18397,
-18398,18399,18400,18401,18402,18403,18404,18405,18406,18407,18408,18409,
-18410,18411,18412,18413,18414,18415,18416,18417,18418,18419,18420,18421,
-18422,18423,18424,18425,18426,18427,18428,18429,18430,18431,18432,18433,
-18434,18435,18436,18437,18438,18439,18440,18441,18442,18443,18444,18445,
-18446,18447,18448,18449,18450,18451,18452,18453,18454,18455,18456,18457,
-18458,18459,18460,18461,18462,18463,18464,18465,18466,18467,18468,18469,
-18470,18471,18472,18473,18474,18475,18476,18477,18478,18479,18480,18481,
-18482,18483,18484,18485,18486,18487,18488,18489,18490,18491,18492,18493,
-18494,18495,18496,18497,18498,18499,18500,18501,18502,18503,18504,18505,
-18506,18507,18508,18509,18510,18511,18512,18513,18514,18515,18516,18517,
-18518,18519,18520,18521,18522,18523,18524,18525,18526,18527,18528,18529,
-18530,18531,18532,18533,18534,18535,18536,18537,18538,18539,18540,18541,
-18542,18543,18544,18545,18546,18547,18548,18549,18550,18551,18552,18553,
-18554,18555,18556,18557,18558,18559,18560,18561,18562,18563,18564,18565,
-18566,18567,18568,18569,18570,18571,18572,18573,18574,18575,18576,18577,
-18578,18579,18580,18581,18582,18583,18584,18585,18586,18587,18588,18589,
-18590,18591,18592,18593,18594,18595,18596,18597,18598,18599,18600,18601,
-18602,18603,18604,18605,18606,18607,18608,18609,18610,18611,18612,18613,
-18614,18615,18616,18617,18618,18619,18620,18621,18622,18623,18624,18625,
-18626,18627,18628,18629,18630,18631,18632,18633,18634,18635,18636,18637,
-18638,18639,18640,18641,18642,18643,18644,18645,18646,18647,18648,18649,
-18650,18651,18652,18653,18654,18655,18656,18657,18658,18659,18660,18661,
-18662,18663,18664,18665,18666,18667,18668,18669,18670,18671,18672,18673,
-18674,18675,18676,18677,18678,18679,18680,18681,18682,18683,18684,18685,
-18686,18687,18688,18689,18690,18691,18692,18693,18694,18695,18696,18697,
-18698,18699,18700,18701,18702,18703,18704,18705,18706,18707,18708,18709,
-18710,18711,18712,18713,18714,18715,18716,18717,18718,18719,18720,18721,
-18722,18723,18724,18725,18726,18727,18728,18729,18730,18731,18732,18733,
-18734,18735,18736,18737,18738,18739,18740,18741,18742,18743,18744,18745,
-18746,18747,18748,18749,18750,18751,18752,18753,18754,18755,18756,18757,
-18758,18759,18760,18761,18762,18763,18764,18765,18766,18767,18768,18769,
-18770,18771,18772,18773,18774,18775,18776,18777,18778,18779,18780,18781,
-18782,18783,18784,18785,18786,18787,18788,18789,18790,18791,18792,18793,
-18794,18795,18796,18797,18798,18799,18800,18801,18802,18803,18804,18805,
-18806,18807,18808,18809,18810,18811,18812,18813,18814,18815,18816,18817,
-18818,18819,18820,18821,18822,18823,18824,18825,18826,18827,18828,18829,
-18830,18831,18832,18833,18834,18835,18836,18837,18838,18839,18840,18841,
-18842,18843,18844,18845,18846,18847,18848,18849,18850,18851,18852,18853,
-18854,18855,18856,18857,18858,18859,18860,18861,18862,18863,18864,18865,
-18866,18867,18868,18869,18870,18871,18872,18873,18874,18875,18876,18877,
-18878,18879,18880,18881,18882,18883,18884,18885,18886,18887,18888,18889,
-18890,18891,18892,18893,18894,18895,18896,18897,18898,18899,18900,18901,
-18902,18903,18904,18905,18906,18907,18908,18909,18910,18911,18912,18913,
-18914,18915,18916,18917,18918,18919,18920,18921,18922,18923,18924,18925,
-18926,18927,18928,18929,18930,18931,18932,18933,18934,18935,18936,18937,
-18938,18939,18940,18941,18942,18943,18944,18945,18946,18947,18948,18949,
-18950,18951,18952,18953,18954,18955,18956,18957,18958,18959,18960,18961,
-18962,18963,18964,18965,18966,18967,18968,18969,18970,18971,18972,18973,
-18974,18975,18976,18977,18978,18979,18980,18981,18982,18983,18984,18985,
-18986,18987,18988,18989,18990,18991,18992,18993,18994,18995,18996,18997,
-18998,18999,19000,19001,19002,19003,19004,19005,19006,19007,19008,19009,
-19010,19011,19012,19013,19014,19015,19016,19017,19018,19019,19020,19021,
-19022,19023,19024,19025,19026,19027,19028,19029,19030,19031,19032,19033,
-19034,19035,19036,19037,19038,19039,19040,19041,19042,19043,19044,19045,
-19046,19047,19048,19049,19050,19051,19052,19053,19054,19055,19056,19057,
-19058,19059,19060,19061,19062,19063,19064,19065,19066,19067,19068,19069,
-19070,19071,19072,19073,19074,19075,19076,19077,19078,19079,19080,19081,
-19082,19083,19084,19085,19086,19087,19088,19089,19090,19091,19092,19093,
-19094,19095,19096,19097,19098,19099,19100,19101,19102,19103,19104,19105,
-19106,19107,19108,19109,19110,19111,19112,19113,19114,19115,19116,19117,
-19118,19119,19120,19121,19122,19123,19124,19125,19126,19127,19128,19129,
-19130,19131,19132,19133,19134,19135,19136,19137,19138,19139,19140,19141,
-19142,19143,19144,19145,19146,19147,19148,19149,19150,19151,19152,19153,
-19154,19155,19156,19157,19158,19159,19160,19161,19162,19163,19164,19165,
-19166,19167,19168,19169,19170,19171,19172,19173,19174,19175,19176,19177,
-19178,19179,19180,19181,19182,19183,19184,19185,19186,19187,19188,19189,
-19190,19191,19192,19193,19194,19195,19196,19197,19198,19199,19200,19201,
-19202,19203,19204,19205,19206,19207,19208,19209,19210,19211,19212,19213,
-19214,19215,19216,19217,19218,19219,19220,19221,19222,19223,19224,19225,
-19226,19227,19228,19229,19230,19231,19232,19233,19234,19235,19236,19237,
-19238,19239,19240,19241,19242,19243,19244,19245,19246,19247,19248,19249,
-19250,19251,19252,19253,19254,19255,19256,19257,19258,19259,19260,19261,
-19262,19263,19264,19265,19266,19267,19268,19269,19270,19271,19272,19273,
-19274,19275,19276,19277,19278,19279,19280,19281,19282,19283,19284,19285,
-19286,19287,19288,19289,19290,19291,19292,19293,19294,19295,19296,19297,
-19298,19299,19300,19301,19302,19303,19304,19305,19306,19307,19308,19309,
-19310,19311,19312,19313,19314,19315,19316,19317,19318,19319,19320,19321,
-19322,19323,19324,19325,19326,19327,19328,19329,19330,19331,19332,19333,
-19334,19335,19336,19337,19338,19339,19340,19341,19342,19343,19344,19345,
-19346,19347,19348,19349,19350,19351,19352,19353,19354,19355,19356,19357,
-19358,19359,19360,19361,19362,19363,19364,19365,19366,19367,19368,19369,
-19370,19371,19372,19373,19374,19375,19376,19377,19378,19379,19380,19381,
-19382,19383,19384,19385,19386,19387,19388,19389,19390,19391,19392,19393,
-19394,19395,19396,19397,19398,19399,19400,19401,19402,19403,19404,19405,
-19406,19407,19408,19409,19410,19411,19412,19413,19414,19415,19416,19417,
-19418,19419,19420,19421,19422,19423,19424,19425,19426,19427,19428,19429,
-19430,19431,19432,19433,19434,19435,19436,19437,19438,19439,19440,19441,
-19442,19443,19444,19445,19446,19447,19448,19449,19450,19451,19452,19453,
-19454,19455,19456,19457,19458,19459,19460,19461,19462,19463,19464,19465,
-19466,19467,19468,19469,19470,19471,19472,19473,19474,19475,19476,19477,
-19478,19479,19480,19481,19482,19483,19484,19485,19486,19487,19488,19489,
-19490,19491,19492,19493,19494,19495,19496,19497,19498,19499,19500,19501,
-19502,19503,19504,19505,19506,19507,19508,19509,19510,19511,19512,19513,
-19514,19515,19516,19517,19518,19519,19520,19521,19522,19523,19524,19525,
-19526,19527,19528,19529,19530,19531,19532,19533,19534,19535,19536,19537,
-19538,19539,19540,19541,19542,19543,19544,19545,19546,19547,19548,19549,
-19550,19551,19552,19553,19554,19555,19556,19557,19558,19559,19560,19561,
-19562,19563,19564,19565,19566,19567,19568,19569,19570,19571,19572,19573,
-19574,19575,19576,19577,19578,19579,19580,19581,19582,19583,19584,19585,
-19586,19587,19588,19589,19590,19591,19592,19593,19594,19595,19596,19597,
-19598,19599,19600,19601,19602,19603,19604,19605,19606,19607,19608,19609,
-19610,19611,19612,19613,19614,19615,19616,19617,19618,19619,19620,19621,
-19622,19623,19624,19625,19626,19627,19628,19629,19630,19631,19632,19633,
-19634,19635,19636,19637,19638,19639,19640,19641,19642,19643,19644,19645,
-19646,19647,19648,19649,19650,19651,19652,19653,19654,19655,19656,19657,
-19658,19659,19660,19661,19662,19663,19664,19665,19666,19667,19668,19669,
-19670,19671,19672,19673,19674,19675,19676,19677,19678,19679,19680,19681,
-19682,19683,19684,19685,19686,19687,19688,19689,19690,19691,19692,19693,
-19694,19695,19696,19697,19698,19699,19700,19701,19702,19703,19704,19705,
-19706,19707,19708,19709,19710,19711,19712,19713,19714,19715,19716,19717,
-19718,19719,19720,19721,19722,19723,19724,19725,19726,19727,19728,19729,
-19730,19731,19732,19733,19734,19735,19736,19737,19738,19739,19740,19741,
-19742,19743,19744,19745,19746,19747,19748,19749,19750,19751,19752,19753,
-19754,19755,19756,19757,19758,19759,19760,19761,19762,19763,19764,19765,
-19766,19767,19768,19769,19770,19771,19772,19773,19774,19775,19776,19777,
-19778,19779,19780,19781,19782,19783,19784,19785,19786,19787,19788,19789,
-19790,19791,19792,19793,19794,19795,19796,19797,19798,19799,19800,19801,
-19802,19803,19804,19805,19806,19807,19808,19809,19810,19811,19812,19813,
-19814,19815,19816,19817,19818,19819,19820,19821,19822,19823,19824,19825,
-19826,19827,19828,19829,19830,19831,19832,19833,19834,19835,19836,19837,
-19838,19839,19840,19841,19842,19843,19844,19845,19846,19847,19848,19849,
-19850,19851,19852,19853,19854,19855,19856,19857,19858,19859,19860,19861,
-19862,19863,19864,19865,19866,19867,19868,19869,19870,19871,19872,19873,
-19874,19875,19876,19877,19878,19879,19880,19881,19882,19883,19884,19885,
-19886,19887,19888,19889,19890,19891,19892,19893,19894,19895,19896,19897,
-19898,19899,19900,19901,19902,19903,19904,19905,19906,19907,19908,19909,
-19910,19911,19912,19913,19914,19915,19916,19917,19918,19919,19920,19921,
-19922,19923,19924,19925,19926,19927,19928,19929,19930,19931,19932,19933,
-19934,19935,19936,19937,19938,19939,19940,19941,19942,19943,19944,19945,
-19946,19947,19948,19949,19950,19951,19952,19953,19954,19955,19956,19957,
-19958,19959,19960,19961,19962,19963,19964,19965,19966,19967,19968,19969,
-19970,19971,19972,19973,19974,19975,19976,19977,19978,19979,19980,19981,
-19982,19983,19984,19985,19986,19987,19988,19989,19990,19991,19992,19993,
-19994,19995,19996,19997,19998,19999,20000,20001,20002,20003,20004,20005,
-20006,20007,20008,20009,20010,20011,20012,20013,20014,20015,20016,20017,
-20018,20019,20020,20021,20022,20023,20024,20025,20026,20027,20028,20029,
-20030,20031,20032,20033,20034,20035,20036,20037,20038,20039,20040,20041,
-20042,20043,20044,20045,20046,20047,20048,20049,20050,20051,20052,20053,
-20054,20055,20056,20057,20058,20059,20060,20061,20062,20063,20064,20065,
-20066,20067,20068,20069,20070,20071,20072,20073,20074,20075,20076,20077,
-20078,20079,20080,20081,20082,20083,20084,20085,20086,20087,20088,20089,
-20090,20091,20092,20093,20094,20095,20096,20097,20098,20099,20100,20101,
-20102,20103,20104,20105,20106,20107,20108,20109,20110,20111,20112,20113,
-20114,20115,20116,20117,20118,20119,20120,20121,20122,20123,20124,20125,
-20126,20127,20128,20129,20130,20131,20132,20133,20134,20135,20136,20137,
-20138,20139,20140,20141,20142,20143,20144,20145,20146,20147,20148,20149,
-20150,20151,20152,20153,20154,20155,20156,20157,20158,20159,20160,20161,
-20162,20163,20164,20165,20166,20167,20168,20169,20170,20171,20172,20173,
-20174,20175,20176,20177,20178,20179,20180,20181,20182,20183,20184,20185,
-20186,20187,20188,20189,20190,20191,20192,20193,20194,20195,20196,20197,
-20198,20199,20200,20201,20202,20203,20204,20205,20206,20207,20208,20209,
-20210,20211,20212,20213,20214,20215,20216,20217,20218,20219,20220,20221,
-20222,20223,20224,20225,20226,20227,20228,20229,20230,20231,20232,20233,
-20234,20235,20236,20237,20238,20239,20240,20241,20242,20243,20244,20245,
-20246,20247,20248,20249,20250,20251,20252,20253,20254,20255,20256,20257,
-20258,20259,20260,20261,20262,20263,20264,20265,20266,20267,20268,20269,
-20270,20271,20272,20273,20274,20275,20276,20277,20278,20279,20280,20281,
-20282,20283,20284,20285,20286,20287,20288,20289,20290,20291,20292,20293,
-20294,20295,20296,20297,20298,20299,20300,20301,20302,20303,20304,20305,
-20306,20307,20308,20309,20310,20311,20312,20313,20314,20315,20316,20317,
-20318,20319,20320,20321,20322,20323,20324,20325,20326,20327,20328,20329,
-20330,20331,20332,20333,20334,20335,20336,20337,20338,20339,20340,20341,
-20342,20343,20344,20345,20346,20347,20348,20349,20350,20351,20352,20353,
-20354,20355,20356,20357,20358,20359,20360,20361,20362,20363,20364,20365,
-20366,20367,20368,20369,20370,20371,20372,20373,20374,20375,20376,20377,
-20378,20379,20380,20381,20382,20383,20384,20385,20386,20387,20388,20389,
-20390,20391,20392,20393,20394,20395,20396,20397,20398,20399,20400,20401,
-20402,20403,20404,20405,20406,20407,20408,20409,20410,20411,20412,20413,
-20414,20415,20416,20417,20418,20419,20420,20421,20422,20423,20424,20425,
-20426,20427,20428,20429,20430,20431,20432,20433,20434,20435,20436,20437,
-20438,20439,20440,20441,20442,20443,20444,20445,20446,20447,20448,20449,
-20450,20451,20452,20453,20454,20455,20456,20457,20458,20459,20460,20461,
-20462,20463,20464,20465,20466,20467,20468,20469,20470,20471,20472,20473,
-20474,20475,20476,20477,20478,20479,20480,20481,20482,20483,20484,20485,
-20486,20487,20488,20489,20490,20491,20492,20493,20494,20495,20496,20497,
-20498,20499,20500,20501,20502,20503,20504,20505,20506,20507,20508,20509,
-20510,20511,20512,20513,20514,20515,20516,20517,20518,20519,20520,20521,
-20522,20523,20524,20525,20526,20527,20528,20529,20530,20531,20532,20533,
-20534,20535,20536,20537,20538,20539,20540,20541,20542,20543,20544,20545,
-20546,20547,20548,20549,20550,20551,20552,20553,20554,20555,20556,20557,
-20558,20559,20560,20561,20562,20563,20564,20565,20566,20567,20568,20569,
-20570,20571,20572,20573,20574,20575,20576,20577,20578,20579,20580,20581,
-20582,20583,20584,20585,20586,20587,20588,20589,20590,20591,20592,20593,
-20594,20595,20596,20597,20598,20599,20600,20601,20602,20603,20604,20605,
-20606,20607,20608,20609,20610,20611,20612,20613,20614,20615,20616,20617,
-20618,20619,20620,20621,20622,20623,20624,20625,20626,20627,20628,20629,
-20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,
-20642,20643,20644,20645,20646,20647,20648,20649,20650,20651,20652,20653,
-20654,20655,20656,20657,20658,20659,20660,20661,20662,20663,20664,20665,
-20666,20667,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,
-20678,20679,20680,20681,20682,20683,20684,20685,20686,20687,20688,20689,
-20690,20691,20692,20693,20694,20695,20696,20697,20698,20699,20700,20701,
-20702,20703,20704,20705,20706,20707,20708,20709,20710,20711,20712,20713,
-20714,20715,20716,20717,20718,20719,20720,20721,20722,20723,20724,20725,
-20726,20727,20728,20729,20730,20731,20732,20733,20734,20735,20736,20737,
-20738,20739,20740,20741,20742,20743,20744,20745,20746,20747,20748,20749,
-20750,20751,20752,20753,20754,20755,20756,20757,20758,20759,20760,20761,
-20762,20763,20764,20765,20766,20767,20768,20769,20770,20771,20772,20773,
-20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,
-20786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,
-20798,20799,20800,20801,20802,20803,20804,20805,20806,20807,20808,20809,
-20810,20811,20812,20813,20814,20815,20816,20817,20818,20819,20820,20821,
-20822,20823,20824,20825,20826,20827,20828,20829,20830,20831,20832,20833,
-20834,20835,20836,20837,20838,20839,20840,20841,20842,20843,20844,20845,
-20846,20847,20848,20849,20850,20851,20852,20853,20854,20855,20856,20857,
-20858,20859,20860,20861,20862,20863,20864,20865,20866,20867,20868,20869,
-20870,20871,20872,20873,20874,20875,20876,20877,20878,20879,20880,20881,
-20882,20883,20884,20885,20886,20887,20888,20889,20890,20891,20892,20893,
-20894,20895,20896,20897,20898,20899,20900,20901,20902,20903,20904,20905,
-20906,20907,20908,20909,20910,20911,20912,20913,20914,20915,20916,20917,
-20918,20919,20920,20921,20922,20923,20924,20925,20926,20927,20928,20929,
-20930,20931,20932,20933,20934,20935,20936,20937,20938,20939,20940,20941,
-20942,20943,20944,20945,20946,20947,20948,20949,20950,20951,20952,20953,
-20954,20955,20956,20957,20958,20959,20960,20961,20962,20963,20964,20965,
-20966,20967,20968,20969,20970,20971,20972,20973,20974,20975,20976,20977,
-20978,20979,20980,20981,20982,20983,20984,20985,20986,20987,20988,20989,
-20990,20991,20992,20993,20994,20995,20996,20997,20998,20999,21000,21001,
-21002,21003,21004,21005,21006,21007,21008,21009,21010,21011,21012,21013,
-21014,21015,21016,21017,21018,21019,21020,21021,21022,21023,21024,21025,
-21026,21027,21028,21029,21030,21031,21032,21033,21034,21035,21036,21037,
-21038,21039,21040,21041,21042,21043,21044,21045,21046,21047,21048,21049,
-21050,21051,21052,21053,21054,21055,21056,21057,21058,21059,21060,21061,
-21062,21063,21064,21065,21066,21067,21068,21069,21070,21071,21072,21073,
-21074,21075,21076,21077,21078,21079,21080,21081,21082,21083,21084,21085,
-21086,21087,21088,21089,21090,21091,21092,21093,21094,21095,21096,21097,
-21098,21099,21100,21101,21102,21103,21104,21105,21106,21107,21108,21109,
-21110,21111,21112,21113,21114,21115,21116,21117,21118,21119,21120,21121,
-21122,21123,21124,21125,21126,21127,21128,21129,21130,21131,21132,21133,
-21134,21135,21136,21137,21138,21139,21140,21141,21142,21143,21144,21145,
-21146,21147,21148,21149,21150,21151,21152,21153,21154,21155,21156,21157,
-21158,21159,21160,21161,21162,21163,21164,21165,21166,21167,21168,21169,
-21170,21171,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,
-21182,21183,21184,21185,21186,21187,21188,21189,21190,21191,21192,21193,
-21194,21195,21196,21197,21198,21199,21200,21201,21202,21203,21204,21205,
-21206,21207,21208,21209,21210,21211,21212,21213,21214,21215,21216,21217,
-21218,21219,21220,21221,21222,21223,21224,21225,21226,21227,21228,21229,
-21230,21231,21232,21233,21234,21235,21236,21237,21238,21239,21240,21241,
-21242,21243,21244,21245,21246,21247,21248,21249,21250,21251,21252,21253,
-21254,21255,21256,21257,21258,21259,21260,21261,21262,21263,21264,21265,
-21266,21267,21268,21269,21270,21271,21272,21273,21274,21275,21276,21277,
-21278,21279,21280,21281,21282,21283,21284,21285,21286,21287,21288,21289,
-21290,21291,21292,21293,21294,21295,21296,21297,21298,21299,21300,21301,
-21302,21303,21304,21305,21306,21307,21308,21309,21310,21311,21312,21313,
-21314,21315,21316,21317,21318,21319,21320,21321,21322,21323,21324,21325,
-21326,21327,21328,21329,21330,21331,21332,21333,21334,21335,21336,21337,
-21338,21339,21340,21341,21342,21343,21344,21345,21346,21347,21348,21349,
-21350,21351,21352,21353,21354,21355,21356,21357,21358,21359,21360,21361,
-21362,21363,21364,21365,21366,21367,21368,21369,21370,21371,21372,21373,
-21374,21375,21376,21377,21378,21379,21380,21381,21382,21383,21384,21385,
-21386,21387,21388,21389,21390,21391,21392,21393,21394,21395,21396,21397,
-21398,21399,21400,21401,21402,21403,21404,21405,21406,21407,21408,21409,
-21410,21411,21412,21413,21414,21415,21416,21417,21418,21419,21420,21421,
-21422,21423,21424,21425,21426,21427,21428,21429,21430,21431,21432,21433,
-21434,21435,21436,21437,21438,21439,21440,21441,21442,21443,21444,21445,
-21446,21447,21448,21449,21450,21451,21452,21453,21454,21455,21456,21457,
-21458,21459,21460,21461,21462,21463,21464,21465,21466,21467,21468,21469,
-21470,21471,21472,21473,21474,21475,21476,21477,21478,21479,21480,21481,
-21482,21483,21484,21485,21486,21487,21488,21489,21490,21491,21492,21493,
-21494,21495,21496,21497,21498,21499,21500,21501,21502,21503,21504,21505,
-21506,21507,21508,21509,21510,21511,21512,21513,21514,21515,21516,21517,
-21518,21519,21520,21521,21522,21523,21524,21525,21526,21527,21528,21529,
-21530,21531,21532,21533,21534,21535,21536,21537,21538,21539,21540,21541,
-21542,21543,21544,21545,21546,21547,21548,21549,21550,21551,21552,21553,
-21554,21555,21556,21557,21558,21559,21560,21561,21562,21563,21564,21565,
-21566,21567,21568,21569,21570,21571,21572,21573,21574,21575,21576,21577,
-21578,21579,21580,21581,21582,21583,21584,21585,21586,21587,21588,21589,
-21590,21591,21592,21593,21594,21595,21596,21597,21598,21599,21600,21601,
-21602,21603,21604,21605,21606,21607,21608,21609,21610,21611,21612,21613,
-21614,21615,21616,21617,21618,21619,21620,21621,21622,21623,21624,21625,
-21626,21627,21628,21629,21630,21631,21632,21633,21634,21635,21636,21637,
-21638,21639,21640,21641,21642,21643,21644,21645,21646,21647,21648,21649,
-21650,21651,21652,21653,21654,21655,21656,21657,21658,21659,21660,21661,
-21662,21663,21664,21665,21666,21667,21668,21669,21670,21671,21672,21673,
-21674,21675,21676,21677,21678,21679,21680,21681,21682,21683,21684,21685,
-21686,21687,21688,21689,21690,21691,21692,21693,21694,21695,21696,21697,
-21698,21699,21700,21701,21702,21703,21704,21705,21706,21707,21708,21709,
-21710,21711,21712,21713,21714,21715,21716,21717,21718,21719,21720,21721,
-21722,21723,21724,21725,21726,21727,21728,21729,21730,21731,21732,21733,
-21734,21735,21736,21737,21738,21739,21740,21741,21742,21743,21744,21745,
-21746,21747,21748,21749,21750,21751,21752,21753,21754,21755,21756,21757,
-21758,21759,21760,21761,21762,21763,21764,21765,21766,21767,21768,21769,
-21770,21771,21772,21773,21774,21775,21776,21777,21778,21779,21780,21781,
-21782,21783,21784,21785,21786,21787,21788,21789,21790,21791,21792,21793,
-21794,21795,21796,21797,21798,21799,21800,21801,21802,21803,21804,21805,
-21806,21807,21808,21809,21810,21811,21812,21813,21814,21815,21816,21817,
-21818,21819,21820,21821,21822,21823,21824,21825,21826,21827,21828,21829,
-21830,21831,21832,21833,21834,21835,21836,21837,21838,21839,21840,21841,
-21842,21843,21844,21845,21846,21847,21848,21849,21850,21851,21852,21853,
-21854,21855,21856,21857,21858,21859,21860,21861,21862,21863,21864,21865,
-21866,21867,21868,21869,21870,21871,21872,21873,21874,21875,21876,21877,
-21878,21879,21880,21881,21882,21883,21884,21885,21886,21887,21888,21889,
-21890,21891,21892,21893,21894,21895,21896,21897,21898,21899,21900,21901,
-21902,21903,21904,21905,21906,21907,21908,21909,21910,21911,21912,21913,
-21914,21915,21916,21917,21918,21919,21920,21921,21922,21923,21924,21925,
-21926,21927,21928,21929,21930,21931,21932,21933,21934,21935,21936,21937,
-21938,21939,21940,21941,21942,21943,21944,21945,21946,21947,21948,21949,
-21950,21951,21952,21953,21954,21955,21956,21957,21958,21959,21960,21961,
-21962,21963,21964,21965,21966,21967,21968,21969,21970,21971,21972,21973,
-21974,21975,21976,21977,21978,21979,21980,21981,21982,21983,21984,21985,
-21986,21987,21988,21989,21990,21991,21992,21993,21994,21995,21996,21997,
-21998,21999,22000,22001,22002,22003,22004,22005,22006,22007,22008,22009,
-22010,22011,22012,22013,22014,22015,22016,22017,22018,22019,22020,22021,
-22022,22023,22024,22025,22026,22027,22028,22029,22030,22031,22032,22033,
-22034,22035,22036,22037,22038,22039,22040,22041,22042,22043,22044,22045,
-22046,22047,22048,22049,22050,22051,22052,22053,22054,22055,22056,22057,
-22058,22059,22060,22061,22062,22063,22064,22065,22066,22067,22068,22069,
-22070,22071,22072,22073,22074,22075,22076,22077,22078,22079,22080,22081,
-22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22092,22093,
-22094,22095,22096,22097,22098,22099,22100,22101,22102,22103,22104,22105,
-22106,22107,22108,22109,22110,22111,22112,22113,22114,22115,22116,22117,
-22118,22119,22120,22121,22122,22123,22124,22125,22126,22127,22128,22129,
-22130,22131,22132,22133,22134,22135,22136,22137,22138,22139,22140,22141,
-22142,22143,22144,22145,22146,22147,22148,22149,22150,22151,22152,22153,
-22154,22155,22156,22157,22158,22159,22160,22161,22162,22163,22164,22165,
-22166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,
-22178,22179,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,
-22190,22191,22192,22193,22194,22195,22196,22197,22198,22199,22200,22201,
-22202,22203,22204,22205,22206,22207,22208,22209,22210,22211,22212,22213,
-22214,22215,22216,22217,22218,22219,22220,22221,22222,22223,22224,22225,
-22226,22227,22228,22229,22230,22231,22232,22233,22234,22235,22236,22237,
-22238,22239,22240,22241,22242,22243,22244,22245,22246,22247,22248,22249,
-22250,22251,22252,22253,22254,22255,22256,22257,22258,22259,22260,22261,
-22262,22263,22264,22265,22266,22267,22268,22269,22270,22271,22272,22273,
-22274,22275,22276,22277,22278,22279,22280,22281,22282,22283,22284,22285,
-22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,
-22298,22299,22300,22301,22302,22303,22304,22305,22306,22307,22308,22309,
-22310,22311,22312,22313,22314,22315,22316,22317,22318,22319,22320,22321,
-22322,22323,22324,22325,22326,22327,22328,22329,22330,22331,22332,22333,
-22334,22335,22336,22337,22338,22339,22340,22341,22342,22343,22344,22345,
-22346,22347,22348,22349,22350,22351,22352,22353,22354,22355,22356,22357,
-22358,22359,22360,22361,22362,22363,22364,22365,22366,22367,22368,22369,
-22370,22371,22372,22373,22374,22375,22376,22377,22378,22379,22380,22381,
-22382,22383,22384,22385,22386,22387,22388,22389,22390,22391,22392,22393,
-22394,22395,22396,22397,22398,22399,22400,22401,22402,22403,22404,22405,
-22406,22407,22408,22409,22410,22411,22412,22413,22414,22415,22416,22417,
-22418,22419,22420,22421,22422,22423,22424,22425,22426,22427,22428,22429,
-22430,22431,22432,22433,22434,22435,22436,22437,22438,22439,22440,22441,
-22442,22443,22444,22445,22446,22447,22448,22449,22450,22451,22452,22453,
-22454,22455,22456,22457,22458,22459,22460,22461,22462,22463,22464,22465,
-22466,22467,22468,22469,22470,22471,22472,22473,22474,22475,22476,22477,
-22478,22479,22480,22481,22482,22483,22484,22485,22486,22487,22488,22489,
-22490,22491,22492,22493,22494,22495,22496,22497,22498,22499,22500,22501,
-22502,22503,22504,22505,22506,22507,22508,22509,22510,22511,22512,22513,
-22514,22515,22516,22517,22518,22519,22520,22521,22522,22523,22524,22525,
-22526,22527,22528,22529,22530,22531,22532,22533,22534,22535,22536,22537,
-22538,22539,22540,22541,22542,22543,22544,22545,22546,22547,22548,22549,
-22550,22551,22552,22553,22554,22555,22556,22557,22558,22559,22560,22561,
-22562,22563,22564,22565,22566,22567,22568,22569,22570,22571,22572,22573,
-22574,22575,22576,22577,22578,22579,22580,22581,22582,22583,22584,22585,
-22586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22596,22597,
-22598,22599,22600,22601,22602,22603,22604,22605,22606,22607,22608,22609,
-22610,22611,22612,22613,22614,22615,22616,22617,22618,22619,22620,22621,
-22622,22623,22624,22625,22626,22627,22628,22629,22630,22631,22632,22633,
-22634,22635,22636,22637,22638,22639,22640,22641,22642,22643,22644,22645,
-22646,22647,22648,22649,22650,22651,22652,22653,22654,22655,22656,22657,
-22658,22659,22660,22661,22662,22663,22664,22665,22666,22667,22668,22669,
-22670,22671,22672,22673,22674,22675,22676,22677,22678,22679,22680,22681,
-22682,22683,22684,22685,22686,22687,22688,22689,22690,22691,22692,22693,
-22694,22695,22696,22697,22698,22699,22700,22701,22702,22703,22704,22705,
-22706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22716,22717,
-22718,22719,22720,22721,22722,22723,22724,22725,22726,22727,22728,22729,
-22730,22731,22732,22733,22734,22735,22736,22737,22738,22739,22740,22741,
-22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,
-22754,22755,22756,22757,22758,22759,22760,22761,22762,22763,22764,22765,
-22766,22767,22768,22769,22770,22771,22772,22773,22774,22775,22776,22777,
-22778,22779,22780,22781,22782,22783,22784,22785,22786,22787,22788,22789,
-22790,22791,22792,22793,22794,22795,22796,22797,22798,22799,22800,22801,
-22802,22803,22804,22805,22806,22807,22808,22809,22810,22811,22812,22813,
-22814,22815,22816,22817,22818,22819,22820,22821,22822,22823,22824,22825,
-22826,22827,22828,22829,22830,22831,22832,22833,22834,22835,22836,22837,
-22838,22839,22840,22841,22842,22843,22844,22845,22846,22847,22848,22849,
-22850,22851,22852,22853,22854,22855,22856,22857,22858,22859,22860,22861,
-22862,22863,22864,22865,22866,22867,22868,22869,22870,22871,22872,22873,
-22874,22875,22876,22877,22878,22879,22880,22881,22882,22883,22884,22885,
-22886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,
-22898,22899,22900,22901,22902,22903,22904,22905,22906,22907,22908,22909,
-22910,22911,22912,22913,22914,22915,22916,22917,22918,22919,22920,22921,
-22922,22923,22924,22925,22926,22927,22928,22929,22930,22931,22932,22933,
-22934,22935,22936,22937,22938,22939,22940,22941,22942,22943,22944,22945,
-22946,22947,22948,22949,22950,22951,22952,22953,22954,22955,22956,22957,
-22958,22959,22960,22961,22962,22963,22964,22965,22966,22967,22968,22969,
-22970,22971,22972,22973,22974,22975,22976,22977,22978,22979,22980,22981,
-22982,22983,22984,22985,22986,22987,22988,22989,22990,22991,22992,22993,
-22994,22995,22996,22997,22998,22999,23000,23001,23002,23003,23004,23005,
-23006,23007,23008,23009,23010,23011,23012,23013,23014,23015,23016,23017,
-23018,23019,23020,23021,23022,23023,23024,23025,23026,23027,23028,23029,
-23030,23031,23032,23033,23034,23035,23036,23037,23038,23039,23040,23041,
-23042,23043,23044,23045,23046,23047,23048,23049,23050,23051,23052,23053,
-23054,23055,23056,23057,23058,23059,23060,23061,23062,23063,23064,23065,
-23066,23067,23068,23069,23070,23071,23072,23073,23074,23075,23076,23077,
-23078,23079,23080,23081,23082,23083,23084,23085,23086,23087,23088,23089,
-23090,23091,23092,23093,23094,23095,23096,23097,23098,23099,23100,23101,
-23102,23103,23104,23105,23106,23107,23108,23109,23110,23111,23112,23113,
-23114,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23125,
-23126,23127,23128,23129,23130,23131,23132,23133,23134,23135,23136,23137,
-23138,23139,23140,23141,23142,23143,23144,23145,23146,23147,23148,23149,
-23150,23151,23152,23153,23154,23155,23156,23157,23158,23159,23160,23161,
-23162,23163,23164,23165,23166,23167,23168,23169,23170,23171,23172,23173,
-23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,
-23186,23187,23188,23189,23190,23191,23192,23193,23194,23195,23196,23197,
-23198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,
-23210,23211,23212,23213,23214,23215,23216,23217,23218,23219,23220,23221,
-23222,23223,23224,23225,23226,23227,23228,23229,23230,23231,23232,23233,
-23234,23235,23236,23237,23238,23239,23240,23241,23242,23243,23244,23245,
-23246,23247,23248,23249,23250,23251,23252,23253,23254,23255,23256,23257,
-23258,23259,23260,23261,23262,23263,23264,23265,23266,23267,23268,23269,
-23270,23271,23272,23273,23274,23275,23276,23277,23278,23279,23280,23281,
-23282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,
-23294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23305,
-23306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,
-23318,23319,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,
-23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,
-23342,23343,23344,23345,23346,23347,23348,23349,23350,23351,23352,23353,
-23354,23355,23356,23357,23358,23359,23360,23361,23362,23363,23364,23365,
-23366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23376,23377,
-23378,23379,23380,23381,23382,23383,23384,23385,23386,23387,23388,23389,
-23390,23391,23392,23393,23394,23395,23396,23397,23398,23399,23400,23401,
-23402,23403,23404,23405,23406,23407,23408,23409,23410,23411,23412,23413,
-23414,23415,23416,23417,23418,23419,23420,23421,23422,23423,23424,23425,
-23426,23427,23428,23429,23430,23431,23432,23433,23434,23435,23436,23437,
-23438,23439,23440,23441,23442,23443,23444,23445,23446,23447,23448,23449,
-23450,23451,23452,23453,23454,23455,23456,23457,23458,23459,23460,23461,
-23462,23463,23464,23465,23466,23467,23468,23469,23470,23471,23472,23473,
-23474,23475,23476,23477,23478,23479,23480,23481,23482,23483,23484,23485,
-23486,23487,23488,23489,23490,23491,23492,23493,23494,23495,23496,23497,
-23498,23499,23500,23501,23502,23503,23504,23505,23506,23507,23508,23509,
-23510,23511,23512,23513,23514,23515,23516,23517,23518,23519,23520,23521,
-23522,23523,23524,23525,23526,23527,23528,23529,23530,23531,23532,23533,
-23534,23535,23536,23537,23538,23539,23540,23541,23542,23543,23544,23545,
-23546,23547,23548,23549,23550,23551,23552,23553,23554,23555,23556,23557,
-23558,23559,23560,23561,23562,23563,23564,23565,23566,23567,23568,23569,
-23570,23571,23572,23573,23574,23575,23576,23577,23578,23579,23580,23581,
-23582,23583,23584,23585,23586,23587,23588,23589,23590,23591,23592,23593,
-23594,23595,23596,23597,23598,23599,23600,23601,23602,23603,23604,23605,
-23606,23607,23608,23609,23610,23611,23612,23613,23614,23615,23616,23617,
-23618,23619,23620,23621,23622,23623,23624,23625,23626,23627,23628,23629,
-23630,23631,23632,23633,23634,23635,23636,23637,23638,23639,23640,23641,
-23642,23643,23644,23645,23646,23647,23648,23649,23650,23651,23652,23653,
-23654,23655,23656,23657,23658,23659,23660,23661,23662,23663,23664,23665,
-23666,23667,23668,23669,23670,23671,23672,23673,23674,23675,23676,23677,
-23678,23679,23680,23681,23682,23683,23684,23685,23686,23687,23688,23689,
-23690,23691,23692,23693,23694,23695,23696,23697,23698,23699,23700,23701,
-23702,23703,23704,23705,23706,23707,23708,23709,23710,23711,23712,23713,
-23714,23715,23716,23717,23718,23719,23720,23721,23722,23723,23724,23725,
-23726,23727,23728,23729,23730,23731,23732,23733,23734,23735,23736,23737,
-23738,23739,23740,23741,23742,23743,23744,23745,23746,23747,23748,23749,
-23750,23751,23752,23753,23754,23755,23756,23757,23758,23759,23760,23761,
-23762,23763,23764,23765,23766,23767,23768,23769,23770,23771,23772,23773,
-23774,23775,23776,23777,23778,23779,23780,23781,23782,23783,23784,23785,
-23786,23787,23788,23789,23790,23791,23792,23793,23794,23795,23796,23797,
-23798,23799,23800,23801,23802,23803,23804,23805,23806,23807,23808,23809,
-23810,23811,23812,23813,23814,23815,23816,23817,23818,23819,23820,23821,
-23822,23823,23824,23825,23826,23827,23828,23829,23830,23831,23832,23833,
-23834,23835,23836,23837,23838,23839,23840,23841,23842,23843,23844,23845,
-23846,23847,23848,23849,23850,23851,23852,23853,23854,23855,23856,23857,
-23858,23859,23860,23861,23862,23863,23864,23865,23866,23867,23868,23869,
-23870,23871,23872,23873,23874,23875,23876,23877,23878,23879,23880,23881,
-23882,23883,23884,23885,23886,23887,23888,23889,23890,23891,23892,23893,
-23894,23895,23896,23897,23898,23899,23900,23901,23902,23903,23904,23905,
-23906,23907,23908,23909,23910,23911,23912,23913,23914,23915,23916,23917,
-23918,23919,23920,23921,23922,23923,23924,23925,23926,23927,23928,23929,
-23930,23931,23932,23933,23934,23935,23936,23937,23938,23939,23940,23941,
-23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,
-23954,23955,23956,23957,23958,23959,23960,23961,23962,23963,23964,23965,
-23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,
-23978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,
-23990,23991,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,
-24002,24003,24004,24005,24006,24007,24008,24009,24010,24011,24012,24013,
-24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,
-24026,24027,24028,24029,24030,24031,24032,24033,24034,24035,24036,24037,
-24038,24039,24040,24041,24042,24043,24044,24045,24046,24047,24048,24049,
-24050,24051,24052,24053,24054,24055,24056,24057,24058,24059,24060,24061,
-24062,24063,24064,24065,24066,24067,24068,24069,24070,24071,24072,24073,
-24074,24075,24076,24077,24078,24079,24080,24081,24082,24083,24084,24085,
-24086,24087,24088,24089,24090,24091,24092,24093,24094,24095,24096,24097,
-24098,24099,24100,24101,24102,24103,24104,24105,24106,24107,24108,24109,
-24110,24111,24112,24113,24114,24115,24116,24117,24118,24119,24120,24121,
-24122,24123,24124,24125,24126,24127,24128,24129,24130,24131,24132,24133,
-24134,24135,24136,24137,24138,24139,24140,24141,24142,24143,24144,24145,
-24146,24147,24148,24149,24150,24151,24152,24153,24154,24155,24156,24157,
-24158,24159,24160,24161,24162,24163,24164,24165,24166,24167,24168,24169,
-24170,24171,24172,24173,24174,24175,24176,24177,24178,24179,24180,24181,
-24182,24183,24184,24185,24186,24187,24188,24189,24190,24191,24192,24193,
-24194,24195,24196,24197,24198,24199,24200,24201,24202,24203,24204,24205,
-24206,24207,24208,24209,24210,24211,24212,24213,24214,24215,24216,24217,
-24218,24219,24220,24221,24222,24223,24224,24225,24226,24227,24228,24229,
-24230,24231,24232,24233,24234,24235,24236,24237,24238,24239,24240,24241,
-24242,24243,24244,24245,24246,24247,24248,24249,24250,24251,24252,24253,
-24254,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24265,
-24266,24267,24268,24269,24270,24271,24272,24273,24274,24275,24276,24277,
-24278,24279,24280,24281,24282,24283,24284,24285,24286,24287,24288,24289,
-24290,24291,24292,24293,24294,24295,24296,24297,24298,24299,24300,24301,
-24302,24303,24304,24305,24306,24307,24308,24309,24310,24311,24312,24313,
-24314,24315,24316,24317,24318,24319,24320,24321,24322,24323,24324,24325,
-24326,24327,24328,24329,24330,24331,24332,24333,24334,24335,24336,24337,
-24338,24339,24340,24341,24342,24343,24344,24345,24346,24347,24348,24349,
-24350,24351,24352,24353,24354,24355,24356,24357,24358,24359,24360,24361,
-24362,24363,24364,24365,24366,24367,24368,24369,24370,24371,24372,24373,
-24374,24375,24376,24377,24378,24379,24380,24381,24382,24383,24384,24385,
-24386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,
-24398,24399,24400,24401,24402,24403,24404,24405,24406,24407,24408,24409,
-24410,24411,24412,24413,24414,24415,24416,24417,24418,24419,24420,24421,
-24422,24423,24424,24425,24426,24427,24428,24429,24430,24431,24432,24433,
-24434,24435,24436,24437,24438,24439,24440,24441,24442,24443,24444,24445,
-24446,24447,24448,24449,24450,24451,24452,24453,24454,24455,24456,24457,
-24458,24459,24460,24461,24462,24463,24464,24465,24466,24467,24468,24469,
-24470,24471,24472,24473,24474,24475,24476,24477,24478,24479,24480,24481,
-24482,24483,24484,24485,24486,24487,24488,24489,24490,24491,24492,24493,
-24494,24495,24496,24497,24498,24499,24500,24501,24502,24503,24504,24505,
-24506,24507,24508,24509,24510,24511,24512,24513,24514,24515,24516,24517,
-24518,24519,24520,24521,24522,24523,24524,24525,24526,24527,24528,24529,
-24530,24531,24532,24533,24534,24535,24536,24537,24538,24539,24540,24541,
-24542,24543,24544,24545,24546,24547,24548,24549,24550,24551,24552,24553,
-24554,24555,24556,24557,24558,24559,24560,24561,24562,24563,24564,24565,
-24566,24567,24568,24569,24570,24571,24572,24573,24574,24575,24576,24577,
-24578,24579,24580,24581,24582,24583,24584,24585,24586,24587,24588,24589,
-24590,24591,24592,24593,24594,24595,24596,24597,24598,24599,24600,24601,
-24602,24603,24604,24605,24606,24607,24608,24609,24610,24611,24612,24613,
-24614,24615,24616,24617,24618,24619,24620,24621,24622,24623,24624,24625,
-24626,24627,24628,24629,24630,24631,24632,24633,24634,24635,24636,24637,
-24638,24639,24640,24641,24642,24643,24644,24645,24646,24647,24648,24649,
-24650,24651,24652,24653,24654,24655,24656,24657,24658,24659,24660,24661,
-24662,24663,24664,24665,24666,24667,24668,24669,24670,24671,24672,24673,
-24674,24675,24676,24677,24678,24679,24680,24681,24682,24683,24684,24685,
-24686,24687,24688,24689,24690,24691,24692,24693,24694,24695,24696,24697,
-24698,24699,24700,24701,24702,24703,24704,24705,24706,24707,24708,24709,
-24710,24711,24712,24713,24714,24715,24716,24717,24718,24719,24720,24721,
-24722,24723,24724,24725,24726,24727,24728,24729,24730,24731,24732,24733,
-24734,24735,24736,24737,24738,24739,24740,24741,24742,24743,24744,24745,
-24746,24747,24748,24749,24750,24751,24752,24753,24754,24755,24756,24757,
-24758,24759,24760,24761,24762,24763,24764,24765,24766,24767,24768,24769,
-24770,24771,24772,24773,24774,24775,24776,24777,24778,24779,24780,24781,
-24782,24783,24784,24785,24786,24787,24788,24789,24790,24791,24792,24793,
-24794,24795,24796,24797,24798,24799,24800,24801,24802,24803,24804,24805,
-24806,24807,24808,24809,24810,24811,24812,24813,24814,24815,24816,24817,
-24818,24819,24820,24821,24822,24823,24824,24825,24826,24827,24828,24829,
-24830,24831,24832,24833,24834,24835,24836,24837,24838,24839,24840,24841,
-24842,24843,24844,24845,24846,24847,24848,24849,24850,24851,24852,24853,
-24854,24855,24856,24857,24858,24859,24860,24861,24862,24863,24864,24865,
-24866,24867,24868,24869,24870,24871,24872,24873,24874,24875,24876,24877,
-24878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,
-24890,24891,24892,24893,24894,24895,24896,24897,24898,24899,24900,24901,
-24902,24903,24904,24905,24906,24907,24908,24909,24910,24911,24912,24913,
-24914,24915,24916,24917,24918,24919,24920,24921,24922,24923,24924,24925,
-24926,24927,24928,24929,24930,24931,24932,24933,24934,24935,24936,24937,
-24938,24939,24940,24941,24942,24943,24944,24945,24946,24947,24948,24949,
-24950,24951,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,
-24962,24963,24964,24965,24966,24967,24968,24969,24970,24971,24972,24973,
-24974,24975,24976,24977,24978,24979,24980,24981,24982,24983,24984,24985,
-24986,24987,24988,24989,24990,24991,24992,24993,24994,24995,24996,24997,
-24998,24999,25000,25001,25002,25003,25004,25005,25006,25007,25008,25009,
-25010,25011,25012,25013,25014,25015,25016,25017,25018,25019,25020,25021,
-25022,25023,25024,25025,25026,25027,25028,25029,25030,25031,25032,25033,
-25034,25035,25036,25037,25038,25039,25040,25041,25042,25043,25044,25045,
-25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,
-25058,25059,25060,25061,25062,25063,25064,25065,25066,25067,25068,25069,
-25070,25071,25072,25073,25074,25075,25076,25077,25078,25079,25080,25081,
-25082,25083,25084,25085,25086,25087,25088,25089,25090,25091,25092,25093,
-25094,25095,25096,25097,25098,25099,25100,25101,25102,25103,25104,25105,
-25106,25107,25108,25109,25110,25111,25112,25113,25114,25115,25116,25117,
-25118,25119,25120,25121,25122,25123,25124,25125,25126,25127,25128,25129,
-25130,25131,25132,25133,25134,25135,25136,25137,25138,25139,25140,25141,
-25142,25143,25144,25145,25146,25147,25148,25149,25150,25151,25152,25153,
-25154,25155,25156,25157,25158,25159,25160,25161,25162,25163,25164,25165,
-25166,25167,25168,25169,25170,25171,25172,25173,25174,25175,25176,25177,
-25178,25179,25180,25181,25182,25183,25184,25185,25186,25187,25188,25189,
-25190,25191,25192,25193,25194,25195,25196,25197,25198,25199,25200,25201,
-25202,25203,25204,25205,25206,25207,25208,25209,25210,25211,25212,25213,
-25214,25215,25216,25217,25218,25219,25220,25221,25222,25223,25224,25225,
-25226,25227,25228,25229,25230,25231,25232,25233,25234,25235,25236,25237,
-25238,25239,25240,25241,25242,25243,25244,25245,25246,25247,25248,25249,
-25250,25251,25252,25253,25254,25255,25256,25257,25258,25259,25260,25261,
-25262,25263,25264,25265,25266,25267,25268,25269,25270,25271,25272,25273,
-25274,25275,25276,25277,25278,25279,25280,25281,25282,25283,25284,25285,
-25286,25287,25288,25289,25290,25291,25292,25293,25294,25295,25296,25297,
-25298,25299,25300,25301,25302,25303,25304,25305,25306,25307,25308,25309,
-25310,25311,25312,25313,25314,25315,25316,25317,25318,25319,25320,25321,
-25322,25323,25324,25325,25326,25327,25328,25329,25330,25331,25332,25333,
-25334,25335,25336,25337,25338,25339,25340,25341,25342,25343,25344,25345,
-25346,25347,25348,25349,25350,25351,25352,25353,25354,25355,25356,25357,
-25358,25359,25360,25361,25362,25363,25364,25365,25366,25367,25368,25369,
-25370,25371,25372,25373,25374,25375,25376,25377,25378,25379,25380,25381,
-25382,25383,25384,25385,25386,25387,25388,25389,25390,25391,25392,25393,
-25394,25395,25396,25397,25398,25399,25400,25401,25402,25403,25404,25405,
-25406,25407,25408,25409,25410,25411,25412,25413,25414,25415,25416,25417,
-25418,25419,25420,25421,25422,25423,25424,25425,25426,25427,25428,25429,
-25430,25431,25432,25433,25434,25435,25436,25437,25438,25439,25440,25441,
-25442,25443,25444,25445,25446,25447,25448,25449,25450,25451,25452,25453,
-25454,25455,25456,25457,25458,25459,25460,25461,25462,25463,25464,25465,
-25466,25467,25468,25469,25470,25471,25472,25473,25474,25475,25476,25477,
-25478,25479,25480,25481,25482,25483,25484,25485,25486,25487,25488,25489,
-25490,25491,25492,25493,25494,25495,25496,25497,25498,25499,25500,25501,
-25502,25503,25504,25505,25506,25507,25508,25509,25510,25511,25512,25513,
-25514,25515,25516,25517,25518,25519,25520,25521,25522,25523,25524,25525,
-25526,25527,25528,25529,25530,25531,25532,25533,25534,25535,25536,25537,
-25538,25539,25540,25541,25542,25543,25544,25545,25546,25547,25548,25549,
-25550,25551,25552,25553,25554,25555,25556,25557,25558,25559,25560,25561,
-25562,25563,25564,25565,25566,25567,25568,25569,25570,25571,25572,25573,
-25574,25575,25576,25577,25578,25579,25580,25581,25582,25583,25584,25585,
-25586,25587,25588,25589,25590,25591,25592,25593,25594,25595,25596,25597,
-25598,25599,25600,25601,25602,25603,25604,25605,25606,25607,25608,25609,
-25610,25611,25612,25613,25614,25615,25616,25617,25618,25619,25620,25621,
-25622,25623,25624,25625,25626,25627,25628,25629,25630,25631,25632,25633,
-25634,25635,25636,25637,25638,25639,25640,25641,25642,25643,25644,25645,
-25646,25647,25648,25649,25650,25651,25652,25653,25654,25655,25656,25657,
-25658,25659,25660,25661,25662,25663,25664,25665,25666,25667,25668,25669,
-25670,25671,25672,25673,25674,25675,25676,25677,25678,25679,25680,25681,
-25682,25683,25684,25685,25686,25687,25688,25689,25690,25691,25692,25693,
-25694,25695,25696,25697,25698,25699,25700,25701,25702,25703,25704,25705,
-25706,25707,25708,25709,25710,25711,25712,25713,25714,25715,25716,25717,
-25718,25719,25720,25721,25722,25723,25724,25725,25726,25727,25728,25729,
-25730,25731,25732,25733,25734,25735,25736,25737,25738,25739,25740,25741,
-25742,25743,25744,25745,25746,25747,25748,25749,25750,25751,25752,25753,
-25754,25755,25756,25757,25758,25759,25760,25761,25762,25763,25764,25765,
-25766,25767,25768,25769,25770,25771,25772,25773,25774,25775,25776,25777,
-25778,25779,25780,25781,25782,25783,25784,25785,25786,25787,25788,25789,
-25790,25791,25792,25793,25794,25795,25796,25797,25798,25799,25800,25801,
-25802,25803,25804,25805,25806,25807,25808,25809,25810,25811,25812,25813,
-25814,25815,25816,25817,25818,25819,25820,25821,25822,25823,25824,25825,
-25826,25827,25828,25829,25830,25831,25832,25833,25834,25835,25836,25837,
-25838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,
-25850,25851,25852,25853,25854,25855,25856,25857,25858,25859,25860,25861,
-25862,25863,25864,25865,25866,25867,25868,25869,25870,25871,25872,25873,
-25874,25875,25876,25877,25878,25879,25880,25881,25882,25883,25884,25885,
-25886,25887,25888,25889,25890,25891,25892,25893,25894,25895,25896,25897,
-25898,25899,25900,25901,25902,25903,25904,25905,25906,25907,25908,25909,
-25910,25911,25912,25913,25914,25915,25916,25917,25918,25919,25920,25921,
-25922,25923,25924,25925,25926,25927,25928,25929,25930,25931,25932,25933,
-25934,25935,25936,25937,25938,25939,25940,25941,25942,25943,25944,25945,
-25946,25947,25948,25949,25950,25951,25952,25953,25954,25955,25956,25957,
-25958,25959,25960,25961,25962,25963,25964,25965,25966,25967,25968,25969,
-25970,25971,25972,25973,25974,25975,25976,25977,25978,25979,25980,25981,
-25982,25983,25984,25985,25986,25987,25988,25989,25990,25991,25992,25993,
-25994,25995,25996,25997,25998,25999,26000,26001,26002,26003,26004,26005,
-26006,26007,26008,26009,26010,26011,26012,26013,26014,26015,26016,26017,
-26018,26019,26020,26021,26022,26023,26024,26025,26026,26027,26028,26029,
-26030,26031,26032,26033,26034,26035,26036,26037,26038,26039,26040,26041,
-26042,26043,26044,26045,26046,26047,26048,26049,26050,26051,26052,26053,
-26054,26055,26056,26057,26058,26059,26060,26061,26062,26063,26064,26065,
-26066,26067,26068,26069,26070,26071,26072,26073,26074,26075,26076,26077,
-26078,26079,26080,26081,26082,26083,26084,26085,26086,26087,26088,26089,
-26090,26091,26092,26093,26094,26095,26096,26097,26098,26099,26100,26101,
-26102,26103,26104,26105,26106,26107,26108,26109,26110,26111,26112,26113,
-26114,26115,26116,26117,26118,26119,26120,26121,26122,26123,26124,26125,
-26126,26127,26128,26129,26130,26131,26132,26133,26134,26135,26136,26137,
-26138,26139,26140,26141,26142,26143,26144,26145,26146,26147,26148,26149,
-26150,26151,26152,26153,26154,26155,26156,26157,26158,26159,26160,26161,
-26162,26163,26164,26165,26166,26167,26168,26169,26170,26171,26172,26173,
-26174,26175,26176,26177,26178,26179,26180,26181,26182,26183,26184,26185,
-26186,26187,26188,26189,26190,26191,26192,26193,26194,26195,26196,26197,
-26198,26199,26200,26201,26202,26203,26204,26205,26206,26207,26208,26209,
-26210,26211,26212,26213,26214,26215,26216,26217,26218,26219,26220,26221,
-26222,26223,26224,26225,26226,26227,26228,26229,26230,26231,26232,26233,
-26234,26235,26236,26237,26238,26239,26240,26241,26242,26243,26244,26245,
-26246,26247,26248,26249,26250,26251,26252,26253,26254,26255,26256,26257,
-26258,26259,26260,26261,26262,26263,26264,26265,26266,26267,26268,26269,
-26270,26271,26272,26273,26274,26275,26276,26277,26278,26279,26280,26281,
-26282,26283,26284,26285,26286,26287,26288,26289,26290,26291,26292,26293,
-26294,26295,26296,26297,26298,26299,26300,26301,26302,26303,26304,26305,
-26306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,
-26318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26329,
-26330,26331,26332,26333,26334,26335,26336,26337,26338,26339,26340,26341,
-26342,26343,26344,26345,26346,26347,26348,26349,26350,26351,26352,26353,
-26354,26355,26356,26357,26358,26359,26360,26361,26362,26363,26364,26365,
-26366,26367,26368,26369,26370,26371,26372,26373,26374,26375,26376,26377,
-26378,26379,26380,26381,26382,26383,26384,26385,26386,26387,26388,26389,
-26390,26391,26392,26393,26394,26395,26396,26397,26398,26399,26400,26401,
-26402,26403,26404,26405,26406,26407,26408,26409,26410,26411,26412,26413,
-26414,26415,26416,26417,26418,26419,26420,26421,26422,26423,26424,26425,
-26426,26427,26428,26429,26430,26431,26432,26433,26434,26435,26436,26437,
-26438,26439,26440,26441,26442,26443,26444,26445,26446,26447,26448,26449,
-26450,26451,26452,26453,26454,26455,26456,26457,26458,26459,26460,26461,
-26462,26463,26464,26465,26466,26467,26468,26469,26470,26471,26472,26473,
-26474,26475,26476,26477,26478,26479,26480,26481,26482,26483,26484,26485,
-26486,26487,26488,26489,26490,26491,26492,26493,26494,26495,26496,26497,
-26498,26499,26500,26501,26502,26503,26504,26505,26506,26507,26508,26509,
-26510,26511,26512,26513,26514,26515,26516,26517,26518,26519,26520,26521,
-26522,26523,26524,26525,26526,26527,26528,26529,26530,26531,26532,26533,
-26534,26535,26536,26537,26538,26539,26540,26541,26542,26543,26544,26545,
-26546,26547,26548,26549,26550,26551,26552,26553,26554,26555,26556,26557,
-26558,26559,26560,26561,26562,26563,26564,26565,26566,26567,26568,26569,
-26570,26571,26572,26573,26574,26575,26576,26577,26578,26579,26580,26581,
-26582,26583,26584,26585,26586,26587,26588,26589,26590,26591,26592,26593,
-26594,26595,26596,26597,26598,26599,26600,26601,26602,26603,26604,26605,
-26606,26607,26608,26609,26610,26611,26612,26613,26614,26615,26616,26617,
-26618,26619,26620,26621,26622,26623,26624,26625,26626,26627,26628,26629,
-26630,26631,26632,26633,26634,26635,26636,26637,26638,26639,26640,26641,
-26642,26643,26644,26645,26646,26647,26648,26649,26650,26651,26652,26653,
-26654,26655,26656,26657,26658,26659,26660,26661,26662,26663,26664,26665,
-26666,26667,26668,26669,26670,26671,26672,26673,26674,26675,26676,26677,
-26678,26679,26680,26681,26682,26683,26684,26685,26686,26687,26688,26689,
-26690,26691,26692,26693,26694,26695,26696,26697,26698,26699,26700,26701,
-26702,26703,26704,26705,26706,26707,26708,26709,26710,26711,26712,26713,
-26714,26715,26716,26717,26718,26719,26720,26721,26722,26723,26724,26725,
-26726,26727,26728,26729,26730,26731,26732,26733,26734,26735,26736,26737,
-26738,26739,26740,26741,26742,26743,26744,26745,26746,26747,26748,26749,
-26750,26751,26752,26753,26754,26755,26756,26757,26758,26759,26760,26761,
-26762,26763,26764,26765,26766,26767,26768,26769,26770,26771,26772,26773,
-26774,26775,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,
-26786,26787,26788,26789,26790,26791,26792,26793,26794,26795,26796,26797,
-26798,26799,26800,26801,26802,26803,26804,26805,26806,26807,26808,26809,
-26810,26811,26812,26813,26814,26815,26816,26817,26818,26819,26820,26821,
-26822,26823,26824,26825,26826,26827,26828,26829,26830,26831,26832,26833,
-26834,26835,26836,26837,26838,26839,26840,26841,26842,26843,26844,26845,
-26846,26847,26848,26849,26850,26851,26852,26853,26854,26855,26856,26857,
-26858,26859,26860,26861,26862,26863,26864,26865,26866,26867,26868,26869,
-26870,26871,26872,26873,26874,26875,26876,26877,26878,26879,26880,26881,
-26882,26883,26884,26885,26886,26887,26888,26889,26890,26891,26892,26893,
-26894,26895,26896,26897,26898,26899,26900,26901,26902,26903,26904,26905,
-26906,26907,26908,26909,26910,26911,26912,26913,26914,26915,26916,26917,
-26918,26919,26920,26921,26922,26923,26924,26925,26926,26927,26928,26929,
-26930,26931,26932,26933,26934,26935,26936,26937,26938,26939,26940,26941,
-26942,26943,26944,26945,26946,26947,26948,26949,26950,26951,26952,26953,
-26954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26964,26965,
-26966,26967,26968,26969,26970,26971,26972,26973,26974,26975,26976,26977,
-26978,26979,26980,26981,26982,26983,26984,26985,26986,26987,26988,26989,
-26990,26991,26992,26993,26994,26995,26996,26997,26998,26999,27000,27001,
-27002,27003,27004,27005,27006,27007,27008,27009,27010,27011,27012,27013,
-27014,27015,27016,27017,27018,27019,27020,27021,27022,27023,27024,27025,
-27026,27027,27028,27029,27030,27031,27032,27033,27034,27035,27036,27037,
-27038,27039,27040,27041,27042,27043,27044,27045,27046,27047,27048,27049,
-27050,27051,27052,27053,27054,27055,27056,27057,27058,27059,27060,27061,
-27062,27063,27064,27065,27066,27067,27068,27069,27070,27071,27072,27073,
-27074,27075,27076,27077,27078,27079,27080,27081,27082,27083,27084,27085,
-27086,27087,27088,27089,27090,27091,27092,27093,27094,27095,27096,27097,
-27098,27099,27100,27101,27102,27103,27104,27105,27106,27107,27108,27109,
-27110,27111,27112,27113,27114,27115,27116,27117,27118,27119,27120,27121,
-27122,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27133,
-27134,27135,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,
-27146,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,
-27158,27159,27160,27161,27162,27163,27164,27165,27166,27167,27168,27169,
-27170,27171,27172,27173,27174,27175,27176,27177,27178,27179,27180,27181,
-27182,27183,27184,27185,27186,27187,27188,27189,27190,27191,27192,27193,
-27194,27195,27196,27197,27198,27199,27200,27201,27202,27203,27204,27205,
-27206,27207,27208,27209,27210,27211,27212,27213,27214,27215,27216,27217,
-27218,27219,27220,27221,27222,27223,27224,27225,27226,27227,27228,27229,
-27230,27231,27232,27233,27234,27235,27236,27237,27238,27239,27240,27241,
-27242,27243,27244,27245,27246,27247,27248,27249,27250,27251,27252,27253,
-27254,27255,27256,27257,27258,27259,27260,27261,27262,27263,27264,27265,
-27266,27267,27268,27269,27270,27271,27272,27273,27274,27275,27276,27277,
-27278,27279,27280,27281,27282,27283,27284,27285,27286,27287,27288,27289,
-27290,27291,27292,27293,27294,27295,27296,27297,27298,27299,27300,27301,
-27302,27303,27304,27305,27306,27307,27308,27309,27310,27311,27312,27313,
-27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,
-27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,
-27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,
-27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,
-27362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,
-27374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,
-27386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,
-27398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,
-27410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,
-27422,27423,27424,27425,27426,27427,27428,27429,27430,27431,27432,27433,
-27434,27435,27436,27437,27438,27439,27440,27441,27442,27443,27444,27445,
-27446,27447,27448,27449,27450,27451,27452,27453,27454,27455,27456,27457,
-27458,27459,27460,27461,27462,27463,27464,27465,27466,27467,27468,27469,
-27470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27481,
-27482,27483,27484,27485,27486,27487,27488,27489,27490,27491,27492,27493,
-27494,27495,27496,27497,27498,27499,27500,27501,27502,27503,27504,27505,
-27506,27507,27508,27509,27510,27511,27512,27513,27514,27515,27516,27517,
-27518,27519,27520,27521,27522,27523,27524,27525,27526,27527,27528,27529,
-27530,27531,27532,27533,27534,27535,27536,27537,27538,27539,27540,27541,
-27542,27543,27544,27545,27546,27547,27548,27549,27550,27551,27552,27553,
-27554,27555,27556,27557,27558,27559,27560,27561,27562,27563,27564,27565,
-27566,27567,27568,27569,27570,27571,27572,27573,27574,27575,27576,27577,
-27578,27579,27580,27581,27582,27583,27584,27585,27586,27587,27588,27589,
-27590,27591,27592,27593,27594,27595,27596,27597,27598,27599,27600,27601,
-27602,27603,27604,27605,27606,27607,27608,27609,27610,27611,27612,27613,
-27614,27615,27616,27617,27618,27619,27620,27621,27622,27623,27624,27625,
-27626,27627,27628,27629,27630,27631,27632,27633,27634,27635,27636,27637,
-27638,27639,27640,27641,27642,27643,27644,27645,27646,27647,27648,27649,
-27650,27651,27652,27653,27654,27655,27656,27657,27658,27659,27660,27661,
-27662,27663,27664,27665,27666,27667,27668,27669,27670,27671,27672,27673,
-27674,27675,27676,27677,27678,27679,27680,27681,27682,27683,27684,27685,
-27686,27687,27688,27689,27690,27691,27692,27693,27694,27695,27696,27697,
-27698,27699,27700,27701,27702,27703,27704,27705,27706,27707,27708,27709,
-27710,27711,27712,27713,27714,27715,27716,27717,27718,27719,27720,27721,
-27722,27723,27724,27725,27726,27727,27728,27729,27730,27731,27732,27733,
-27734,27735,27736,27737,27738,27739,27740,27741,27742,27743,27744,27745,
-27746,27747,27748,27749,27750,27751,27752,27753,27754,27755,27756,27757,
-27758,27759,27760,27761,27762,27763,27764,27765,27766,27767,27768,27769,
-27770,27771,27772,27773,27774,27775,27776,27777,27778,27779,27780,27781,
-27782,27783,27784,27785,27786,27787,27788,27789,27790,27791,27792,27793,
-27794,27795,27796,27797,27798,27799,27800,27801,27802,27803,27804,27805,
-27806,27807,27808,27809,27810,27811,27812,27813,27814,27815,27816,27817,
-27818,27819,27820,27821,27822,27823,27824,27825,27826,27827,27828,27829,
-27830,27831,27832,27833,27834,27835,27836,27837,27838,27839,27840,27841,
-27842,27843,27844,27845,27846,27847,27848,27849,27850,27851,27852,27853,
-27854,27855,27856,27857,27858,27859,27860,27861,27862,27863,27864,27865,
-27866,27867,27868,27869,27870,27871,27872,27873,27874,27875,27876,27877,
-27878,27879,27880,27881,27882,27883,27884,27885,27886,27887,27888,27889,
-27890,27891,27892,27893,27894,27895,27896,27897,27898,27899,27900,27901,
-27902,27903,27904,27905,27906,27907,27908,27909,27910,27911,27912,27913,
-27914,27915,27916,27917,27918,27919,27920,27921,27922,27923,27924,27925,
-27926,27927,27928,27929,27930,27931,27932,27933,27934,27935,27936,27937,
-27938,27939,27940,27941,27942,27943,27944,27945,27946,27947,27948,27949,
-27950,27951,27952,27953,27954,27955,27956,27957,27958,27959,27960,27961,
-27962,27963,27964,27965,27966,27967,27968,27969,27970,27971,27972,27973,
-27974,27975,27976,27977,27978,27979,27980,27981,27982,27983,27984,27985,
-27986,27987,27988,27989,27990,27991,27992,27993,27994,27995,27996,27997,
-27998,27999,28000,28001,28002,28003,28004,28005,28006,28007,28008,28009,
-28010,28011,28012,28013,28014,28015,28016,28017,28018,28019,28020,28021,
-28022,28023,28024,28025,28026,28027,28028,28029,28030,28031,28032,28033,
-28034,28035,28036,28037,28038,28039,28040,28041,28042,28043,28044,28045,
-28046,28047,28048,28049,28050,28051,28052,28053,28054,28055,28056,28057,
-28058,28059,28060,28061,28062,28063,28064,28065,28066,28067,28068,28069,
-28070,28071,28072,28073,28074,28075,28076,28077,28078,28079,28080,28081,
-28082,28083,28084,28085,28086,28087,28088,28089,28090,28091,28092,28093,
-28094,28095,28096,28097,28098,28099,28100,28101,28102,28103,28104,28105,
-28106,28107,28108,28109,28110,28111,28112,28113,28114,28115,28116,28117,
-28118,28119,28120,28121,28122,28123,28124,28125,28126,28127,28128,28129,
-28130,28131,28132,28133,28134,28135,28136,28137,28138,28139,28140,28141,
-28142,28143,28144,28145,28146,28147,28148,28149,28150,28151,28152,28153,
-28154,28155,28156,28157,28158,28159,28160,28161,28162,28163,28164,28165,
-28166,28167,28168,28169,28170,28171,28172,28173,28174,28175,28176,28177,
-28178,28179,28180,28181,28182,28183,28184,28185,28186,28187,28188,28189,
-28190,28191,28192,28193,28194,28195,28196,28197,28198,28199,28200,28201,
-28202,28203,28204,28205,28206,28207,28208,28209,28210,28211,28212,28213,
-28214,28215,28216,28217,28218,28219,28220,28221,28222,28223,28224,28225,
-28226,28227,28228,28229,28230,28231,28232,28233,28234,28235,28236,28237,
-28238,28239,28240,28241,28242,28243,28244,28245,28246,28247,28248,28249,
-28250,28251,28252,28253,28254,28255,28256,28257,28258,28259,28260,28261,
-28262,28263,28264,28265,28266,28267,28268,28269,28270,28271,28272,28273,
-28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,
-28286,28287,28288,28289,28290,28291,28292,28293,28294,28295,28296,28297,
-28298,28299,28300,28301,28302,28303,28304,28305,28306,28307,28308,28309,
-28310,28311,28312,28313,28314,28315,28316,28317,28318,28319,28320,28321,
-28322,28323,28324,28325,28326,28327,28328,28329,28330,28331,28332,28333,
-28334,28335,28336,28337,28338,28339,28340,28341,28342,28343,28344,28345,
-28346,28347,28348,28349,28350,28351,28352,28353,28354,28355,28356,28357,
-28358,28359,28360,28361,28362,28363,28364,28365,28366,28367,28368,28369,
-28370,28371,28372,28373,28374,28375,28376,28377,28378,28379,28380,28381,
-28382,28383,28384,28385,28386,28387,28388,28389,28390,28391,28392,28393,
-28394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28404,28405,
-28406,28407,28408,28409,28410,28411,28412,28413,28414,28415,28416,28417,
-28418,28419,28420,28421,28422,28423,28424,28425,28426,28427,28428,28429,
-28430,28431,28432,28433,28434,28435,28436,28437,28438,28439,28440,28441,
-28442,28443,28444,28445,28446,28447,28448,28449,28450,28451,28452,28453,
-28454,28455,28456,28457,28458,28459,28460,28461,28462,28463,28464,28465,
-28466,28467,28468,28469,28470,28471,28472,28473,28474,28475,28476,28477,
-28478,28479,28480,28481,28482,28483,28484,28485,28486,28487,28488,28489,
-28490,28491,28492,28493,28494,28495,28496,28497,28498,28499,28500,28501,
-28502,28503,28504,28505,28506,28507,28508,28509,28510,28511,28512,28513,
-28514,28515,28516,28517,28518,28519,28520,28521,28522,28523,28524,28525,
-28526,28527,28528,28529,28530,28531,28532,28533,28534,28535,28536,28537,
-28538,28539,28540,28541,28542,28543,28544,28545,28546,28547,28548,28549,
-28550,28551,28552,28553,28554,28555,28556,28557,28558,28559,28560,28561,
-28562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28572,28573,
-28574,28575,28576,28577,28578,28579,28580,28581,28582,28583,28584,28585,
-28586,28587,28588,28589,28590,28591,28592,28593,28594,28595,28596,28597,
-28598,28599,28600,28601,28602,28603,28604,28605,28606,28607,28608,28609,
-28610,28611,28612,28613,28614,28615,28616,28617,28618,28619,28620,28621,
-28622,28623,28624,28625,28626,28627,28628,28629,28630,28631,28632,28633,
-28634,28635,28636,28637,28638,28639,28640,28641,28642,28643,28644,28645,
-28646,28647,28648,28649,28650,28651,28652,28653,28654,28655,28656,28657,
-28658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,
-28670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,
-28682,28683,28684,28685,28686,28687,28688,28689,28690,28691,28692,28693,
-28694,28695,28696,28697,28698,28699,28700,28701,28702,28703,28704,28705,
-28706,28707,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,
-28718,28719,28720,28721,28722,28723,28724,28725,28726,28727,28728,28729,
-28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,
-28742,28743,28744,28745,28746,28747,28748,28749,28750,28751,28752,28753,
-28754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,
-28766,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,
-28778,28779,28780,28781,28782,28783,28784,28785,28786,28787,28788,28789,
-28790,28791,28792,28793,28794,28795,28796,28797,28798,28799,28800,28801,
-28802,28803,28804,28805,28806,28807,28808,28809,28810,28811,28812,28813,
-28814,28815,28816,28817,28818,28819,28820,28821,28822,28823,28824,28825,
-28826,28827,28828,28829,28830,28831,28832,28833,28834,28835,28836,28837,
-28838,28839,28840,28841,28842,28843,28844,28845,28846,28847,28848,28849,
-28850,28851,28852,28853,28854,28855,28856,28857,28858,28859,28860,28861,
-28862,28863,28864,28865,28866,28867,28868,28869,28870,28871,28872,28873,
-28874,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,
-28886,28887,28888,28889,28890,28891,28892,28893,28894,28895,28896,28897,
-28898,28899,28900,28901,28902,28903,28904,28905,28906,28907,28908,28909,
-28910,28911,28912,28913,28914,28915,28916,28917,28918,28919,28920,28921,
-28922,28923,28924,28925,28926,28927,28928,28929,28930,28931,28932,28933,
-28934,28935,28936,28937,28938,28939,28940,28941,28942,28943,28944,28945,
-28946,28947,28948,28949,28950,28951,28952,28953,28954,28955,28956,28957,
-28958,28959,28960,28961,28962,28963,28964,28965,28966,28967,28968,28969,
-28970,28971,28972,28973,28974,28975,28976,28977,28978,28979,28980,28981,
-28982,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,
-28994,28995,28996,28997,28998,28999,29000,29001,29002,29003,29004,29005,
-29006,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,
-29018,29019,29020,29021,29022,29023,29024,29025,29026,29027,29028,29029,
-29030,29031,29032,29033,29034,29035,29036,29037,29038,29039,29040,29041,
-29042,29043,29044,29045,29046,29047,29048,29049,29050,29051,29052,29053,
-29054,29055,29056,29057,29058,29059,29060,29061,29062,29063,29064,29065,
-29066,29067,29068,29069,29070,29071,29072,29073,29074,29075,29076,29077,
-29078,29079,29080,29081,29082,29083,29084,29085,29086,29087,29088,29089,
-29090,29091,29092,29093,29094,29095,29096,29097,29098,29099,29100,29101,
-29102,29103,29104,29105,29106,29107,29108,29109,29110,29111,29112,29113,
-29114,29115,29116,29117,29118,29119,29120,29121,29122,29123,29124,29125,
-29126,29127,29128,29129,29130,29131,29132,29133,29134,29135,29136,29137,
-29138,29139,29140,29141,29142,29143,29144,29145,29146,29147,29148,29149,
-29150,29151,29152,29153,29154,29155,29156,29157,29158,29159,29160,29161,
-29162,29163,29164,29165,29166,29167,29168,29169,29170,29171,29172,29173,
-29174,29175,29176,29177,29178,29179,29180,29181,29182,29183,29184,29185,
-29186,29187,29188,29189,29190,29191,29192,29193,29194,29195,29196,29197,
-29198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,
-29210,29211,29212,29213,29214,29215,29216,29217,29218,29219,29220,29221,
-29222,29223,29224,29225,29226,29227,29228,29229,29230,29231,29232,29233,
-29234,29235,29236,29237,29238,29239,29240,29241,29242,29243,29244,29245,
-29246,29247,29248,29249,29250,29251,29252,29253,29254,29255,29256,29257,
-29258,29259,29260,29261,29262,29263,29264,29265,29266,29267,29268,29269,
-29270,29271,29272,29273,29274,29275,29276,29277,29278,29279,29280,29281,
-29282,29283,29284,29285,29286,29287,29288,29289,29290,29291,29292,29293,
-29294,29295,29296,29297,29298,29299,29300,29301,29302,29303,29304,29305,
-29306,29307,29308,29309,29310,29311,29312,29313,29314,29315,29316,29317,
-29318,29319,29320,29321,29322,29323,29324,29325,29326,29327,29328,29329,
-29330,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,
-29342,29343,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,
-29354,29355,29356,29357,29358,29359,29360,29361,29362,29363,29364,29365,
-29366,29367,29368,29369,29370,29371,29372,29373,29374,29375,29376,29377,
-29378,29379,29380,29381,29382,29383,29384,29385,29386,29387,29388,29389,
-29390,29391,29392,29393,29394,29395,29396,29397,29398,29399,29400,29401,
-29402,29403,29404,29405,29406,29407,29408,29409,29410,29411,29412,29413,
-29414,29415,29416,29417,29418,29419,29420,29421,29422,29423,29424,29425,
-29426,29427,29428,29429,29430,29431,29432,29433,29434,29435,29436,29437,
-29438,29439,29440,29441,29442,29443,29444,29445,29446,29447,29448,29449,
-29450,29451,29452,29453,29454,29455,29456,29457,29458,29459,29460,29461,
-29462,29463,29464,29465,29466,29467,29468,29469,29470,29471,29472,29473,
-29474,29475,29476,29477,29478,29479,29480,29481,29482,29483,29484,29485,
-29486,29487,29488,29489,29490,29491,29492,29493,29494,29495,29496,29497,
-29498,29499,29500,29501,29502,29503,29504,29505,29506,29507,29508,29509,
-29510,29511,29512,29513,29514,29515,29516,29517,29518,29519,29520,29521,
-29522,29523,29524,29525,29526,29527,29528,29529,29530,29531,29532,29533,
-29534,29535,29536,29537,29538,29539,29540,29541,29542,29543,29544,29545,
-29546,29547,29548,29549,29550,29551,29552,29553,29554,29555,29556,29557,
-29558,29559,29560,29561,29562,29563,29564,29565,29566,29567,29568,29569,
-29570,29571,29572,29573,29574,29575,29576,29577,29578,29579,29580,29581,
-29582,29583,29584,29585,29586,29587,29588,29589,29590,29591,29592,29593,
-29594,29595,29596,29597,29598,29599,29600,29601,29602,29603,29604,29605,
-29606,29607,29608,29609,29610,29611,29612,29613,29614,29615,29616,29617,
-29618,29619,29620,29621,29622,29623,29624,29625,29626,29627,29628,29629,
-29630,29631,29632,29633,29634,29635,29636,29637,29638,29639,29640,29641,
-29642,29643,29644,29645,29646,29647,29648,29649,29650,29651,29652,29653,
-29654,29655,29656,29657,29658,29659,29660,29661,29662,29663,29664,29665,
-29666,29667,29668,29669,29670,29671,29672,29673,29674,29675,29676,29677,
-29678,29679,29680,29681,29682,29683,29684,29685,29686,29687,29688,29689,
-29690,29691,29692,29693,29694,29695,29696,29697,29698,29699,29700,29701,
-29702,29703,29704,29705,29706,29707,29708,29709,29710,29711,29712,29713,
-29714,29715,29716,29717,29718,29719,29720,29721,29722,29723,29724,29725,
-29726,29727,29728,29729,29730,29731,29732,29733,29734,29735,29736,29737,
-29738,29739,29740,29741,29742,29743,29744,29745,29746,29747,29748,29749,
-29750,29751,29752,29753,29754,29755,29756,29757,29758,29759,29760,29761,
-29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,
-29774,29775,29776,29777,29778,29779,29780,29781,29782,29783,29784,29785,
-29786,29787,29788,29789,29790,29791,29792,29793,29794,29795,29796,29797,
-29798,29799,29800,29801,29802,29803,29804,29805,29806,29807,29808,29809,
-29810,29811,29812,29813,29814,29815,29816,29817,29818,29819,29820,29821,
-29822,29823,29824,29825,29826,29827,29828,29829,29830,29831,29832,29833,
-29834,29835,29836,29837,29838,29839,29840,29841,29842,29843,29844,29845,
-29846,29847,29848,29849,29850,29851,29852,29853,29854,29855,29856,29857,
-29858,29859,29860,29861,29862,29863,29864,29865,29866,29867,29868,29869,
-29870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,
-29882,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,
-29894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,
-29906,29907,29908,29909,29910,29911,29912,29913,29914,29915,29916,29917,
-29918,29919,29920,29921,29922,29923,29924,29925,29926,29927,29928,29929,
-29930,29931,29932,29933,29934,29935,29936,29937,29938,29939,29940,29941,
-29942,29943,29944,29945,29946,29947,29948,29949,29950,29951,29952,29953,
-29954,29955,29956,29957,29958,29959,29960,29961,29962,29963,29964,29965,
-29966,29967,29968,29969,29970,29971,29972,29973,29974,29975,29976,29977,
-29978,29979,29980,29981,29982,29983,29984,29985,29986,29987,29988,29989,
-29990,29991,29992,29993,29994,29995,29996,29997,29998,29999,30000,30001,
-30002,30003,30004,30005,30006,30007,30008,30009,30010,30011,30012,30013,
-30014,30015,30016,30017,30018,30019,30020,30021,30022,30023,30024,30025,
-30026,30027,30028,30029,30030,30031,30032,30033,30034,30035,30036,30037,
-30038,30039,30040,30041,30042,30043,30044,30045,30046,30047,30048,30049,
-30050,30051,30052,30053,30054,30055,30056,30057,30058,30059,30060,30061,
-30062,30063,30064,30065,30066,30067,30068,30069,30070,30071,30072,30073,
-30074,30075,30076,30077,30078,30079,30080,30081,30082,30083,30084,30085,
-30086,30087,30088,30089,30090,30091,30092,30093,30094,30095,30096,30097,
-30098,30099,30100,30101,30102,30103,30104,30105,30106,30107,30108,30109,
-30110,30111,30112,30113,30114,30115,30116,30117,30118,30119,30120,30121,
-30122,30123,30124,30125,30126,30127,30128,30129,30130,30131,30132,30133,
-30134,30135,30136,30137,30138,30139,30140,30141,30142,30143,30144,30145,
-30146,30147,30148,30149,30150,30151,30152,30153,30154,30155,30156,30157,
-30158,30159,30160,30161,30162,30163,30164,30165,30166,30167,30168,30169,
-30170,30171,30172,30173,30174,30175,30176,30177,30178,30179,30180,30181,
-30182,30183,30184,30185,30186,30187,30188,30189,30190,30191,30192,30193,
-30194,30195,30196,30197,30198,30199,30200,30201,30202,30203,30204,30205,
-30206,30207,30208,30209,30210,30211,30212,30213,30214,30215,30216,30217,
-30218,30219,30220,30221,30222,30223,30224,30225,30226,30227,30228,30229,
-30230,30231,30232,30233,30234,30235,30236,30237,30238,30239,30240,30241,
-30242,30243,30244,30245,30246,30247,30248,30249,30250,30251,30252,30253,
-30254,30255,30256,30257,30258,30259,30260,30261,30262,30263,30264,30265,
-30266,30267,30268,30269,30270,30271,30272,30273,30274,30275,30276,30277,
-30278,30279,30280,30281,30282,30283,30284,30285,30286,30287,30288,30289,
-30290,30291,30292,30293,30294,30295,30296,30297,30298,30299,30300,30301,
-30302,30303,30304,30305,30306,30307,30308,30309,30310,30311,30312,30313,
-30314,30315,30316,30317,30318,30319,30320,30321,30322,30323,30324,30325,
-30326,30327,30328,30329,30330,30331,30332,30333,30334,30335,30336,30337,
-30338,30339,30340,30341,30342,30343,30344,30345,30346,30347,30348,30349,
-30350,30351,30352,30353,30354,30355,30356,30357,30358,30359,30360,30361,
-30362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30372,30373,
-30374,30375,30376,30377,30378,30379,30380,30381,30382,30383,30384,30385,
-30386,30387,30388,30389,30390,30391,30392,30393,30394,30395,30396,30397,
-30398,30399,30400,30401,30402,30403,30404,30405,30406,30407,30408,30409,
-30410,30411,30412,30413,30414,30415,30416,30417,30418,30419,30420,30421,
-30422,30423,30424,30425,30426,30427,30428,30429,30430,30431,30432,30433,
-30434,30435,30436,30437,30438,30439,30440,30441,30442,30443,30444,30445,
-30446,30447,30448,30449,30450,30451,30452,30453,30454,30455,30456,30457,
-30458,30459,30460,30461,30462,30463,30464,30465,30466,30467,30468,30469,
-30470,30471,30472,30473,30474,30475,30476,30477,30478,30479,30480,30481,
-30482,30483,30484,30485,30486,30487,30488,30489,30490,30491,30492,30493,
-30494,30495,30496,30497,30498,30499,30500,30501,30502,30503,30504,30505,
-30506,30507,30508,30509,30510,30511,30512,30513,30514,30515,30516,30517,
-30518,30519,30520,30521,30522,30523,30524,30525,30526,30527,30528,30529,
-30530,30531,30532,30533,30534,30535,30536,30537,30538,30539,30540,30541,
-30542,30543,30544,30545,30546,30547,30548,30549,30550,30551,30552,30553,
-30554,30555,30556,30557,30558,30559,30560,30561,30562,30563,30564,30565,
-30566,30567,30568,30569,30570,30571,30572,30573,30574,30575,30576,30577,
-30578,30579,30580,30581,30582,30583,30584,30585,30586,30587,30588,30589,
-30590,30591,30592,30593,30594,30595,30596,30597,30598,30599,30600,30601,
-30602,30603,30604,30605,30606,30607,30608,30609,30610,30611,30612,30613,
-30614,30615,30616,30617,30618,30619,30620,30621,30622,30623,30624,30625,
-30626,30627,30628,30629,30630,30631,30632,30633,30634,30635,30636,30637,
-30638,30639,30640,30641,30642,30643,30644,30645,30646,30647,30648,30649,
-30650,30651,30652,30653,30654,30655,30656,30657,30658,30659,30660,30661,
-30662,30663,30664,30665,30666,30667,30668,30669,30670,30671,30672,30673,
-30674,30675,30676,30677,30678,30679,30680,30681,30682,30683,30684,30685,
-30686,30687,30688,30689,30690,30691,30692,30693,30694,30695,30696,30697,
-30698,30699,30700,30701,30702,30703,30704,30705,30706,30707,30708,30709,
-30710,30711,30712,30713,30714,30715,30716,30717,30718,30719,30720,30721,
-30722,30723,30724,30725,30726,30727,30728,30729,30730,30731,30732,30733,
-30734,30735,30736,30737,30738,30739,30740,30741,30742,30743,30744,30745,
-30746,30747,30748,30749,30750,30751,30752,30753,30754,30755,30756,30757,
-30758,30759,30760,30761,30762,30763,30764,30765,30766,30767,30768,30769,
-30770,30771,30772,30773,30774,30775,30776,30777,30778,30779,30780,30781,
-30782,30783,30784,30785,30786,30787,30788,30789,30790,30791,30792,30793,
-30794,30795,30796,30797,30798,30799,30800,30801,30802,30803,30804,30805,
-30806,30807,30808,30809,30810,30811,30812,30813,30814,30815,30816,30817,
-30818,30819,30820,30821,30822,30823,30824,30825,30826,30827,30828,30829,
-30830,30831,30832,30833,30834,30835,30836,30837,30838,30839,30840,30841,
-30842,30843,30844,30845,30846,30847,30848,30849,30850,30851,30852,30853,
-30854,30855,30856,30857,30858,30859,30860,30861,30862,30863,30864,30865,
-30866,30867,30868,30869,30870,30871,30872,30873,30874,30875,30876,30877,
-30878,30879,30880,30881,30882,30883,30884,30885,30886,30887,30888,30889,
-30890,30891,30892,30893,30894,30895,30896,30897,30898,30899,30900,30901,
-30902,30903,30904,30905,30906,30907,30908,30909,30910,30911,30912,30913,
-30914,30915,30916,30917,30918,30919,30920,30921,30922,30923,30924,30925,
-30926,30927,30928,30929,30930,30931,30932,30933,30934,30935,30936,30937,
-30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,
-30950,30951,30952,30953,30954,30955,30956,30957,30958,30959,30960,30961,
-30962,30963,30964,30965,30966,30967,30968,30969,30970,30971,30972,30973,
-30974,30975,30976,30977,30978,30979,30980,30981,30982,30983,30984,30985,
-30986,30987,30988,30989,30990,30991,30992,30993,30994,30995,30996,30997,
-30998,30999,31000,31001,31002,31003,31004,31005,31006,31007,31008,31009,
-31010,31011,31012,31013,31014,31015,31016,31017,31018,31019,31020,31021,
-31022,31023,31024,31025,31026,31027,31028,31029,31030,31031,31032,31033,
-31034,31035,31036,31037,31038,31039,31040,31041,31042,31043,31044,31045,
-31046,31047,31048,31049,31050,31051,31052,31053,31054,31055,31056,31057,
-31058,31059,31060,31061,31062,31063,31064,31065,31066,31067,31068,31069,
-31070,31071,31072,31073,31074,31075,31076,31077,31078,31079,31080,31081,
-31082,31083,31084,31085,31086,31087,31088,31089,31090,31091,31092,31093,
-31094,31095,31096,31097,31098,31099,31100,31101,31102,31103,31104,31105,
-31106,31107,31108,31109,31110,31111,31112,31113,31114,31115,31116,31117,
-31118,31119,31120,31121,31122,31123,31124,31125,31126,31127,31128,31129,
-31130,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,
-31142,31143,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,
-31154,31155,31156,31157,31158,31159,31160,31161,31162,31163,31164,31165,
-31166,31167,31168,31169,31170,31171,31172,31173,31174,31175,31176,31177,
-31178,31179,31180,31181,31182,31183,31184,31185,31186,31187,31188,31189,
-31190,31191,31192,31193,31194,31195,31196,31197,31198,31199,31200,31201,
-31202,31203,31204,31205,31206,31207,31208,31209,31210,31211,31212,31213,
-31214,31215,31216,31217,31218,31219,31220,31221,31222,31223,31224,31225,
-31226,31227,31228,31229,31230,31231,31232,31233,31234,31235,31236,31237,
-31238,31239,31240,31241,31242,31243,31244,31245,31246,31247,31248,31249,
-31250,31251,31252,31253,31254,31255,31256,31257,31258,31259,31260,31261,
-31262,31263,31264,31265,31266,31267,31268,31269,31270,31271,31272,31273,
-31274,31275,31276,31277,31278,31279,31280,31281,31282,31283,31284,31285,
-31286,31287,31288,31289,31290,31291,31292,31293,31294,31295,31296,31297,
-31298,31299,31300,31301,31302,31303,31304,31305,31306,31307,31308,31309,
-31310,31311,31312,31313,31314,31315,31316,31317,31318,31319,31320,31321,
-31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,
-31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31344,31345,
-31346,31347,31348,31349,31350,31351,31352,31353,31354,31355,31356,31357,
-31358,31359,31360,31361,31362,31363,31364,31365,31366,31367,31368,31369,
-31370,31371,31372,31373,31374,31375,31376,31377,31378,31379,31380,31381,
-31382,31383,31384,31385,31386,31387,31388,31389,31390,31391,31392,31393,
-31394,31395,31396,31397,31398,31399,31400,31401,31402,31403,31404,31405,
-31406,31407,31408,31409,31410,31411,31412,31413,31414,31415,31416,31417,
-31418,31419,31420,31421,31422,31423,31424,31425,31426,31427,31428,31429,
-31430,31431,31432,31433,31434,31435,31436,31437,31438,31439,31440,31441,
-31442,31443,31444,31445,31446,31447,31448,31449,31450,31451,31452,31453,
-31454,31455,31456,31457,31458,31459,31460,31461,31462,31463,31464,31465,
-31466,31467,31468,31469,31470,31471,31472,31473,31474,31475,31476,31477,
-31478,31479,31480,31481,31482,31483,31484,31485,31486,31487,31488,31489,
-31490,31491,31492,31493,31494,31495,31496,31497,31498,31499,31500,31501,
-31502,31503,31504,31505,31506,31507,31508,31509,31510,31511,31512,31513,
-31514,31515,31516,31517,31518,31519,31520,31521,31522,31523,31524,31525,
-31526,31527,31528,31529,31530,31531,31532,31533,31534,31535,31536,31537,
-31538,31539,31540,31541,31542,31543,31544,31545,31546,31547,31548,31549,
-31550,31551,31552,31553,31554,31555,31556,31557,31558,31559,31560,31561,
-31562,31563,31564,31565,31566,31567,31568,31569,31570,31571,31572,31573,
-31574,31575,31576,31577,31578,31579,31580,31581,31582,31583,31584,31585,
-31586,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,
-31598,31599,31600,31601,31602,31603,31604,31605,31606,31607,31608,31609,
-31610,31611,31612,31613,31614,31615,31616,31617,31618,31619,31620,31621,
-31622,31623,31624,31625,31626,31627,31628,31629,31630,31631,31632,31633,
-31634,31635,31636,31637,31638,31639,31640,31641,31642,31643,31644,31645,
-31646,31647,31648,31649,31650,31651,31652,31653,31654,31655,31656,31657,
-31658,31659,31660,31661,31662,31663,31664,31665,31666,31667,31668,31669,
-31670,31671,31672,31673,31674,31675,31676,31677,31678,31679,31680,31681,
-31682,31683,31684,31685,31686,31687,31688,31689,31690,31691,31692,31693,
-31694,31695,31696,31697,31698,31699,31700,31701,31702,31703,31704,31705,
-31706,31707,31708,31709,31710,31711,31712,31713,31714,31715,31716,31717,
-31718,31719,31720,31721,31722,31723,31724,31725,31726,31727,31728,31729,
-31730,31731,31732,31733,31734,31735,31736,31737,31738,31739,31740,31741,
-31742,31743,31744,31745,31746,31747,31748,31749,31750,31751,31752,31753,
-31754,31755,31756,31757,31758,31759,31760,31761,31762,31763,31764,31765,
-31766,31767,31768,31769,31770,31771,31772,31773,31774,31775,31776,31777,
-31778,31779,31780,31781,31782,31783,31784,31785,31786,31787,31788,31789,
-31790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31800,31801,
-31802,31803,31804,31805,31806,31807,31808,31809,31810,31811,31812,31813,
-31814,31815,31816,31817,31818,31819,31820,31821,31822,31823,31824,31825,
-31826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,
-31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,
-31850,31851,31852,31853,31854,31855,31856,31857,31858,31859,31860,31861,
-31862,31863,31864,31865,31866,31867,31868,31869,31870,31871,31872,31873,
-31874,31875,31876,31877,31878,31879,31880,31881,31882,31883,31884,31885,
-31886,31887,31888,31889,31890,31891,31892,31893,31894,31895,31896,31897,
-31898,31899,31900,31901,31902,31903,31904,31905,31906,31907,31908,31909,
-31910,31911,31912,31913,31914,31915,31916,31917,31918,31919,31920,31921,
-31922,31923,31924,31925,31926,31927,31928,31929,31930,31931,31932,31933,
-31934,31935,31936,31937,31938,31939,31940,31941,31942,31943,31944,31945,
-31946,31947,31948,31949,31950,31951,31952,31953,31954,31955,31956,31957,
-31958,31959,31960,31961,31962,31963,31964,31965,31966,31967,31968,31969,
-31970,31971,31972,31973,31974,31975,31976,31977,31978,31979,31980,31981,
-31982,31983,31984,31985,31986,31987,31988,31989,31990,31991,31992,31993,
-31994,31995,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,
-32006,32007,32008,32009,32010,32011,32012,32013,32014,32015,32016,32017,
-32018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,
-32030,32031,32032,32033,32034,32035,32036,32037,32038,32039,32040,32041,
-32042,32043,32044,32045,32046,32047,32048,32049,32050,32051,32052,32053,
-32054,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,
-32066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,
-32078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,
-32090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,
-32102,32103,32104,32105,32106,32107,32108,32109,32110,32111,32112,32113,
-32114,32115,32116,32117,32118,32119,32120,32121,32122,32123,32124,32125,
-32126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,
-32138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,
-32150,32151,32152,32153,32154,32155,32156,32157,32158,32159,32160,32161,
-32162,32163,32164,32165,32166,32167,32168,32169,32170,32171,32172,32173,
-32174,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,
-32186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,
-32198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,
-32210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,
-32222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,
-32234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,
-32246,32247,32248,32249,32250,32251,32252,32253,32254,32255,32256,32257,
-32258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,
-32270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,
-32282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,
-32294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,
-32306,32307,32308,32309,32310,32311,32312,32313,32314,32315,32316,32317,
-32318,32319,32320,32321,32322,32323,32324,32325,32326,32327,32328,32329,
-32330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,
-32342,32343,32344,32345,32346,32347,32348,32349,32350,32351,32352,32353,
-32354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,
-32366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,
-32378,32379,32380,32381,32382,32383,32384,32385,32386,32387,32388,32389,
-32390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,
-32402,32403,32404,32405,32406,32407,32408,32409,32410,32411,32412,32413,
-32414,32415,32416,32417,32418,32419,32420,32421,32422,32423,32424,32425,
-32426,32427,32428,32429,32430,32431,32432,32433,32434,32435,32436,32437,
-32438,32439,32440,32441,32442,32443,32444,32445,32446,32447,32448,32449,
-32450,32451,32452,32453,32454,32455,32456,32457,32458,32459,32460,32461,
-32462,32463,32464,32465,32466,32467,32468,32469,32470,32471,32472,32473,
-32474,32475,32476,32477,32478,32479,32480,32481,32482,32483,32484,32485,
-32486,32487,32488,32489,32490,32491,32492,32493,32494,32495,32496,32497,
-32498,32499,32500,32501,32502,32503,32504,32505,32506,32507,32508,32509,
-32510,32511,32512,32513,32514,32515,32516,32517,32518,32519,32520,32521,
-32522,32523,32524,32525,32526,32527,32528,32529,32530,32531,32532,32533,
-32534,32535,32536,32537,32538,32539,32540,32541,32542,32543,32544,32545,
-32546,32547,32548,32549,32550,32551,32552,32553,32554,32555,32556,32557,
-32558,32559,32560,32561,32562,32563,32564,32565,32566,32567,32568,32569,
-32570,32571,32572,32573,32574,32575,32576,32577,32578,32579,32580,32581,
-32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32592,32593,
-32594,32595,32596,32597,32598,32599,32600,32601,32602,32603,32604,32605,
-32606,32607,32608,32609,32610,32611,32612,32613,32614,32615,32616,32617,
-32618,32619,32620,32621,32622,32623,32624,32625,32626,32627,32628,32629,
-32630,32631,32632,32633,32634,32635,32636,32637,32638,32639,32640,32641,
-32642,32643,32644,32645,32646,32647,32648,32649,32650,32651,32652,32653,
-32654,32655,32656,32657,32658,32659,32660,32661,32662,32663,32664,32665,
-32666,32667,32668,32669,32670,32671,32672,32673,32674,32675,32676,32677,
-32678,32679,32680,32681,32682,32683,32684,32685,32686,32687,32688,32689,
-32690,32691,32692,32693,32694,32695,32696,32697,32698,32699,32700,32701,
-32702,32703,32704,32705,32706,32707,32708,32709,32710,32711,32712,32713,
-32714,32715,32716,32717,32718,32719,32720,32721,32722,32723,32724,32725,
-32726,32727,32728,32729,32730,32731,32732,32733,32734,32735,32736,32737,
-32738,32739,32740,32741,32742,32743,32744,32745,32746,32747,32748,32749,
-32750,32751,32752,32753,32754,32755,32756,32757,32758,32759,32760,32761,
-32762,32763,32764,32765,32766,32767,32768L,32769L,32770L,32771L,32772L,
-32773L,32774L,32775L,32776L,32777L,32778L,32779L,32780L,32781L,32782L,
-32783L,32784L,32785L,32786L,32787L,32788L,32789L,32790L,32791L,32792L,
-32793L,32794L,32795L,32796L,32797L,32798L,32799L,32800L,32801L,32802L,
-32803L,32804L,32805L,32806L,32807L,32808L,32809L,32810L,32811L,32812L,
-32813L,32814L,32815L,32816L,32817L,32818L,32819L,32820L,32821L,32822L,
-32823L,32824L,32825L,32826L,32827L,32828L,32829L,32830L,32831L,32832L,
-32833L,32834L,32835L,32836L,32837L,32838L,32839L,32840L,32841L,32842L,
-32843L,32844L,32845L,32846L,32847L,32848L,32849L,32850L,32851L,32852L,
-32853L,32854L,32855L,32856L,32857L,32858L,32859L,32860L,32861L,32862L,
-32863L,32864L,32865L,32866L,32867L,32868L,32869L,32870L,32871L,32872L,
-32873L,32874L,32875L,32876L,32877L,32878L,32879L,32880L,32881L,32882L,
-32883L,32884L,32885L,32886L,32887L,32888L,32889L,32890L,32891L,32892L,
-32893L,32894L,32895L,32896L,32897L,32898L,32899L,32900L,32901L,32902L,
-32903L,32904L,32905L,32906L,32907L,32908L,32909L,32910L,32911L,32912L,
-32913L,32914L,32915L,32916L,32917L,32918L,32919L,32920L,32921L,32922L,
-32923L,32924L,32925L,32926L,32927L,32928L,32929L,32930L,32931L,32932L,
-32933L,32934L,32935L,32936L,32937L,32938L,32939L,32940L,32941L,32942L,
-32943L,32944L,32945L,32946L,32947L,32948L,32949L,32950L,32951L,32952L,
-32953L,32954L,32955L,32956L,32957L,32958L,32959L,32960L,32961L,32962L,
-32963L,32964L,32965L,32966L,32967L,32968L,32969L,32970L,32971L,32972L,
-32973L,32974L,32975L,32976L,32977L,32978L,32979L,32980L,32981L,32982L,
-32983L,32984L,32985L,32986L,32987L,32988L,32989L,32990L,32991L,32992L,
-32993L,32994L,32995L,32996L,32997L,32998L,32999L,33000L,33001L,33002L,
-33003L,33004L,33005L,33006L,33007L,33008L,33009L,33010L,33011L,33012L,
-33013L,33014L,33015L,33016L,33017L,33018L,33019L,33020L,33021L,33022L,
-33023L,33024L,33025L,33026L,33027L,33028L,33029L,33030L,33031L,33032L,
-33033L,33034L,33035L,33036L,33037L,33038L,33039L,33040L,33041L,33042L,
-33043L,33044L,33045L,33046L,33047L,33048L,33049L,33050L,33051L,33052L,
-33053L,33054L,33055L,33056L,33057L,33058L,33059L,33060L,33061L,33062L,
-33063L,33064L,33065L,33066L,33067L,33068L,33069L,33070L,33071L,33072L,
-33073L,33074L,33075L,33076L,33077L,33078L,33079L,33080L,33081L,33082L,
-33083L,33084L,33085L,33086L,33087L,33088L,33089L,33090L,33091L,33092L,
-33093L,33094L,33095L,33096L,33097L,33098L,33099L,33100L,33101L,33102L,
-33103L,33104L,33105L,33106L,33107L,33108L,33109L,33110L,33111L,33112L,
-33113L,33114L,33115L,33116L,33117L,33118L,33119L,33120L,33121L,33122L,
-33123L,33124L,33125L,33126L,33127L,33128L,33129L,33130L,33131L,33132L,
-33133L,33134L,33135L,33136L,33137L,33138L,33139L,33140L,33141L,33142L,
-33143L,33144L,33145L,33146L,33147L,33148L,33149L,33150L,33151L,33152L,
-33153L,33154L,33155L,33156L,33157L,33158L,33159L,33160L,33161L,33162L,
-33163L,33164L,33165L,33166L,33167L,33168L,33169L,33170L,33171L,33172L,
-33173L,33174L,33175L,33176L,33177L,33178L,33179L,33180L,33181L,33182L,
-33183L,33184L,33185L,33186L,33187L,33188L,33189L,33190L,33191L,33192L,
-33193L,33194L,33195L,33196L,33197L,33198L,33199L,33200L,33201L,33202L,
-33203L,33204L,33205L,33206L,33207L,33208L,33209L,33210L,33211L,33212L,
-33213L,33214L,33215L,33216L,33217L,33218L,33219L,33220L,33221L,33222L,
-33223L,33224L,33225L,33226L,33227L,33228L,33229L,33230L,33231L,33232L,
-33233L,33234L,33235L,33236L,33237L,33238L,33239L,33240L,33241L,33242L,
-33243L,33244L,33245L,33246L,33247L,33248L,33249L,33250L,33251L,33252L,
-33253L,33254L,33255L,33256L,33257L,33258L,33259L,33260L,33261L,33262L,
-33263L,33264L,33265L,33266L,33267L,33268L,33269L,33270L,33271L,33272L,
-33273L,33274L,33275L,33276L,33277L,33278L,33279L,33280L,33281L,33282L,
-33283L,33284L,33285L,33286L,33287L,33288L,33289L,33290L,33291L,33292L,
-33293L,33294L,33295L,33296L,33297L,33298L,33299L,33300L,33301L,33302L,
-33303L,33304L,33305L,33306L,33307L,33308L,33309L,33310L,33311L,33312L,
-33313L,33314L,33315L,33316L,33317L,33318L,33319L,33320L,33321L,33322L,
-33323L,33324L,33325L,33326L,33327L,33328L,33329L,33330L,33331L,33332L,
-33333L,33334L,33335L,33336L,33337L,33338L,33339L,33340L,33341L,33342L,
-33343L,33344L,33345L,33346L,33347L,33348L,33349L,33350L,33351L,33352L,
-33353L,33354L,33355L,33356L,33357L,33358L,33359L,33360L,33361L,33362L,
-33363L,33364L,33365L,33366L,33367L,33368L,33369L,33370L,33371L,33372L,
-33373L,33374L,33375L,33376L,33377L,33378L,33379L,33380L,33381L,33382L,
-33383L,33384L,33385L,33386L,33387L,33388L,33389L,33390L,33391L,33392L,
-33393L,33394L,33395L,33396L,33397L,33398L,33399L,33400L,33401L,33402L,
-33403L,33404L,33405L,33406L,33407L,33408L,33409L,33410L,33411L,33412L,
-33413L,33414L,33415L,33416L,33417L,33418L,33419L,33420L,33421L,33422L,
-33423L,33424L,33425L,33426L,33427L,33428L,33429L,33430L,33431L,33432L,
-33433L,33434L,33435L,33436L,33437L,33438L,33439L,33440L,33441L,33442L,
-33443L,33444L,33445L,33446L,33447L,33448L,33449L,33450L,33451L,33452L,
-33453L,33454L,33455L,33456L,33457L,33458L,33459L,33460L,33461L,33462L,
-33463L,33464L,33465L,33466L,33467L,33468L,33469L,33470L,33471L,33472L,
-33473L,33474L,33475L,33476L,33477L,33478L,33479L,33480L,33481L,33482L,
-33483L,33484L,33485L,33486L,33487L,33488L,33489L,33490L,33491L,33492L,
-33493L,33494L,33495L,33496L,33497L,33498L,33499L,33500L,33501L,33502L,
-33503L,33504L,33505L,33506L,33507L,33508L,33509L,33510L,33511L,33512L,
-33513L,33514L,33515L,33516L,33517L,33518L,33519L,33520L,33521L,33522L,
-33523L,33524L,33525L,33526L,33527L,33528L,33529L,33530L,33531L,33532L,
-33533L,33534L,33535L,33536L,33537L,33538L,33539L,33540L,33541L,33542L,
-33543L,33544L,33545L,33546L,33547L,33548L,33549L,33550L,33551L,33552L,
-33553L,33554L,33555L,33556L,33557L,33558L,33559L,33560L,33561L,33562L,
-33563L,33564L,33565L,33566L,33567L,33568L,33569L,33570L,33571L,33572L,
-33573L,33574L,33575L,33576L,33577L,33578L,33579L,33580L,33581L,33582L,
-33583L,33584L,33585L,33586L,33587L,33588L,33589L,33590L,33591L,33592L,
-33593L,33594L,33595L,33596L,33597L,33598L,33599L,33600L,33601L,33602L,
-33603L,33604L,33605L,33606L,33607L,33608L,33609L,33610L,33611L,33612L,
-33613L,33614L,33615L,33616L,33617L,33618L,33619L,33620L,33621L,33622L,
-33623L,33624L,33625L,33626L,33627L,33628L,33629L,33630L,33631L,33632L,
-33633L,33634L,33635L,33636L,33637L,33638L,33639L,33640L,33641L,33642L,
-33643L,33644L,33645L,33646L,33647L,33648L,33649L,33650L,33651L,33652L,
-33653L,33654L,33655L,33656L,33657L,33658L,33659L,33660L,33661L,33662L,
-33663L,33664L,33665L,33666L,33667L,33668L,33669L,33670L,33671L,33672L,
-33673L,33674L,33675L,33676L,33677L,33678L,33679L,33680L,33681L,33682L,
-33683L,33684L,33685L,33686L,33687L,33688L,33689L,33690L,33691L,33692L,
-33693L,33694L,33695L,33696L,33697L,33698L,33699L,33700L,33701L,33702L,
-33703L,33704L,33705L,33706L,33707L,33708L,33709L,33710L,33711L,33712L,
-33713L,33714L,33715L,33716L,33717L,33718L,33719L,33720L,33721L,33722L,
-33723L,33724L,33725L,33726L,33727L,33728L,33729L,33730L,33731L,33732L,
-33733L,33734L,33735L,33736L,33737L,33738L,33739L,33740L,33741L,33742L,
-33743L,33744L,33745L,33746L,33747L,33748L,33749L,33750L,33751L,33752L,
-33753L,33754L,33755L,33756L,33757L,33758L,33759L,33760L,33761L,33762L,
-33763L,33764L,33765L,33766L,33767L,33768L,33769L,33770L,33771L,33772L,
-33773L,33774L,33775L,33776L,33777L,33778L,33779L,33780L,33781L,33782L,
-33783L,33784L,33785L,33786L,33787L,33788L,33789L,33790L,33791L,33792L,
-33793L,33794L,33795L,33796L,33797L,33798L,33799L,33800L,33801L,33802L,
-33803L,33804L,33805L,33806L,33807L,33808L,33809L,33810L,33811L,33812L,
-33813L,33814L,33815L,33816L,33817L,33818L,33819L,33820L,33821L,33822L,
-33823L,33824L,33825L,33826L,33827L,33828L,33829L,33830L,33831L,33832L,
-33833L,33834L,33835L,33836L,33837L,33838L,33839L,33840L,33841L,33842L,
-33843L,33844L,33845L,33846L,33847L,33848L,33849L,33850L,33851L,33852L,
-33853L,33854L,33855L,33856L,33857L,33858L,33859L,33860L,33861L,33862L,
-33863L,33864L,33865L,33866L,33867L,33868L,33869L,33870L,33871L,33872L,
-33873L,33874L,33875L,33876L,33877L,33878L,33879L,33880L,33881L,33882L,
-33883L,33884L,33885L,33886L,33887L,33888L,33889L,33890L,33891L,33892L,
-33893L,33894L,33895L,33896L,33897L,33898L,33899L,33900L,33901L,33902L,
-33903L,33904L,33905L,33906L,33907L,33908L,33909L,33910L,33911L,33912L,
-33913L,33914L,33915L,33916L,33917L,33918L,33919L,33920L,33921L,33922L,
-33923L,33924L,33925L,33926L,33927L,33928L,33929L,33930L,33931L,33932L,
-33933L,33934L,33935L,33936L,33937L,33938L,33939L,33940L,33941L,33942L,
-33943L,33944L,33945L,33946L,33947L,33948L,33949L,33950L,33951L,33952L,
-33953L,33954L,33955L,33956L,33957L,33958L,33959L,33960L,33961L,33962L,
-33963L,33964L,33965L,33966L,33967L,33968L,33969L,33970L,33971L,33972L,
-33973L,33974L,33975L,33976L,33977L,33978L,33979L,33980L,33981L,33982L,
-33983L,33984L,33985L,33986L,33987L,33988L,33989L,33990L,33991L,33992L,
-33993L,33994L,33995L,33996L,33997L,33998L,33999L,34000L,34001L,34002L,
-34003L,34004L,34005L,34006L,34007L,34008L,34009L,34010L,34011L,34012L,
-34013L,34014L,34015L,34016L,34017L,34018L,34019L,34020L,34021L,34022L,
-34023L,34024L,34025L,34026L,34027L,34028L,34029L,34030L,34031L,34032L,
-34033L,34034L,34035L,34036L,34037L,34038L,34039L,34040L,34041L,34042L,
-34043L,34044L,34045L,34046L,34047L,34048L,34049L,34050L,34051L,34052L,
-34053L,34054L,34055L,34056L,34057L,34058L,34059L,34060L,34061L,34062L,
-34063L,34064L,34065L,34066L,34067L,34068L,34069L,34070L,34071L,34072L,
-34073L,34074L,34075L,34076L,34077L,34078L,34079L,34080L,34081L,34082L,
-34083L,34084L,34085L,34086L,34087L,34088L,34089L,34090L,34091L,34092L,
-34093L,34094L,34095L,34096L,34097L,34098L,34099L,34100L,34101L,34102L,
-34103L,34104L,34105L,34106L,34107L,34108L,34109L,34110L,34111L,34112L,
-34113L,34114L,34115L,34116L,34117L,34118L,34119L,34120L,34121L,34122L,
-34123L,34124L,34125L,34126L,34127L,34128L,34129L,34130L,34131L,34132L,
-34133L,34134L,34135L,34136L,34137L,34138L,34139L,34140L,34141L,34142L,
-34143L,34144L,34145L,34146L,34147L,34148L,34149L,34150L,34151L,34152L,
-34153L,34154L,34155L,34156L,34157L,34158L,34159L,34160L,34161L,34162L,
-34163L,34164L,34165L,34166L,34167L,34168L,34169L,34170L,34171L,34172L,
-34173L,34174L,34175L,34176L,34177L,34178L,34179L,34180L,34181L,34182L,
-34183L,34184L,34185L,34186L,34187L,34188L,34189L,34190L,34191L,34192L,
-34193L,34194L,34195L,34196L,34197L,34198L,34199L,34200L,34201L,34202L,
-34203L,34204L,34205L,34206L,34207L,34208L,34209L,34210L,34211L,34212L,
-34213L,34214L,34215L,34216L,34217L,34218L,34219L,34220L,34221L,34222L,
-34223L,34224L,34225L,34226L,34227L,34228L,34229L,34230L,34231L,34232L,
-34233L,34234L,34235L,34236L,34237L,34238L,34239L,34240L,34241L,34242L,
-34243L,34244L,34245L,34246L,34247L,34248L,34249L,34250L,34251L,34252L,
-34253L,34254L,34255L,34256L,34257L,34258L,34259L,34260L,34261L,34262L,
-34263L,34264L,34265L,34266L,34267L,34268L,34269L,34270L,34271L,34272L,
-34273L,34274L,34275L,34276L,34277L,34278L,34279L,34280L,34281L,34282L,
-34283L,34284L,34285L,34286L,34287L,34288L,34289L,34290L,34291L,34292L,
-34293L,34294L,34295L,34296L,34297L,34298L,34299L,34300L,34301L,34302L,
-34303L,34304L,34305L,34306L,34307L,34308L,34309L,34310L,34311L,34312L,
-34313L,34314L,34315L,34316L,34317L,34318L,34319L,34320L,34321L,34322L,
-34323L,34324L,34325L,34326L,34327L,34328L,34329L,34330L,34331L,34332L,
-34333L,34334L,34335L,34336L,34337L,34338L,34339L,34340L,34341L,34342L,
-34343L,34344L,34345L,34346L,34347L,34348L,34349L,34350L,34351L,34352L,
-34353L,34354L,34355L,34356L,34357L,34358L,34359L,34360L,34361L,34362L,
-34363L,34364L,34365L,34366L,34367L,34368L,34369L,34370L,34371L,34372L,
-34373L,34374L,34375L,34376L,34377L,34378L,34379L,34380L,34381L,34382L,
-34383L,34384L,34385L,34386L,34387L,34388L,34389L,34390L,34391L,34392L,
-34393L,34394L,34395L,34396L,34397L,34398L,34399L,34400L,34401L,34402L,
-34403L,34404L,34405L,34406L,34407L,34408L,34409L,34410L,34411L,34412L,
-34413L,34414L,34415L,34416L,34417L,34418L,34419L,34420L,34421L,34422L,
-34423L,34424L,34425L,34426L,34427L,34428L,34429L,34430L,34431L,34432L,
-34433L,34434L,34435L,34436L,34437L,34438L,34439L,34440L,34441L,34442L,
-34443L,34444L,34445L,34446L,34447L,34448L,34449L,34450L,34451L,34452L,
-34453L,34454L,34455L,34456L,34457L,34458L,34459L,34460L,34461L,34462L,
-34463L,34464L,34465L,34466L,34467L,34468L,34469L,34470L,34471L,34472L,
-34473L,34474L,34475L,34476L,34477L,34478L,34479L,34480L,34481L,34482L,
-34483L,34484L,34485L,34486L,34487L,34488L,34489L,34490L,34491L,34492L,
-34493L,34494L,34495L,34496L,34497L,34498L,34499L,34500L,34501L,34502L,
-34503L,34504L,34505L,34506L,34507L,34508L,34509L,34510L,34511L,34512L,
-34513L,34514L,34515L,34516L,34517L,34518L,34519L,34520L,34521L,34522L,
-34523L,34524L,34525L,34526L,34527L,34528L,34529L,34530L,34531L,34532L,
-34533L,34534L,34535L,34536L,34537L,34538L,34539L,34540L,34541L,34542L,
-34543L,34544L,34545L,34546L,34547L,34548L,34549L,34550L,34551L,34552L,
-34553L,34554L,34555L,34556L,34557L,34558L,34559L,34560L,34561L,34562L,
-34563L,34564L,34565L,34566L,34567L,34568L,34569L,34570L,34571L,34572L,
-34573L,34574L,34575L,34576L,34577L,34578L,34579L,34580L,34581L,34582L,
-34583L,34584L,34585L,34586L,34587L,34588L,34589L,34590L,34591L,34592L,
-34593L,34594L,34595L,34596L,34597L,34598L,34599L,34600L,34601L,34602L,
-34603L,34604L,34605L,34606L,34607L,34608L,34609L,34610L,34611L,34612L,
-34613L,34614L,34615L,34616L,34617L,34618L,34619L,34620L,34621L,34622L,
-34623L,34624L,34625L,34626L,34627L,34628L,34629L,34630L,34631L,34632L,
-34633L,34634L,34635L,34636L,34637L,34638L,34639L,34640L,34641L,34642L,
-34643L,34644L,34645L,34646L,34647L,34648L,34649L,34650L,34651L,34652L,
-34653L,34654L,34655L,34656L,34657L,34658L,34659L,34660L,34661L,34662L,
-34663L,34664L,34665L,34666L,34667L,34668L,34669L,34670L,34671L,34672L,
-34673L,34674L,34675L,34676L,34677L,34678L,34679L,34680L,34681L,34682L,
-34683L,34684L,34685L,34686L,34687L,34688L,34689L,34690L,34691L,34692L,
-34693L,34694L,34695L,34696L,34697L,34698L,34699L,34700L,34701L,34702L,
-34703L,34704L,34705L,34706L,34707L,34708L,34709L,34710L,34711L,34712L,
-34713L,34714L,34715L,34716L,34717L,34718L,34719L,34720L,34721L,34722L,
-34723L,34724L,34725L,34726L,34727L,34728L,34729L,34730L,34731L,34732L,
-34733L,34734L,34735L,34736L,34737L,34738L,34739L,34740L,34741L,34742L,
-34743L,34744L,34745L,34746L,34747L,34748L,34749L,34750L,34751L,34752L,
-34753L,34754L,34755L,34756L,34757L,34758L,34759L,34760L,34761L,34762L,
-34763L,34764L,34765L,34766L,34767L,34768L,34769L,34770L,34771L,34772L,
-34773L,34774L,34775L,34776L,34777L,34778L,34779L,34780L,34781L,34782L,
-34783L,34784L,34785L,34786L,34787L,34788L,34789L,34790L,34791L,34792L,
-34793L,34794L,34795L,34796L,34797L,34798L,34799L,34800L,34801L,34802L,
-34803L,34804L,34805L,34806L,34807L,34808L,34809L,34810L,34811L,34812L,
-34813L,34814L,34815L,34816L,34817L,34818L,34819L,34820L,34821L,34822L,
-34823L,34824L,34825L,34826L,34827L,34828L,34829L,34830L,34831L,34832L,
-34833L,34834L,34835L,34836L,34837L,34838L,34839L,34840L,34841L,34842L,
-34843L,34844L,34845L,34846L,34847L,34848L,34849L,34850L,34851L,34852L,
-34853L,34854L,34855L,34856L,34857L,34858L,34859L,34860L,34861L,34862L,
-34863L,34864L,34865L,34866L,34867L,34868L,34869L,34870L,34871L,34872L,
-34873L,34874L,34875L,34876L,34877L,34878L,34879L,34880L,34881L,34882L,
-34883L,34884L,34885L,34886L,34887L,34888L,34889L,34890L,34891L,34892L,
-34893L,34894L,34895L,34896L,34897L,34898L,34899L,34900L,34901L,34902L,
-34903L,34904L,34905L,34906L,34907L,34908L,34909L,34910L,34911L,34912L,
-34913L,34914L,34915L,34916L,34917L,34918L,34919L,34920L,34921L,34922L,
-34923L,34924L,34925L,34926L,34927L,34928L,34929L,34930L,34931L,34932L,
-34933L,34934L,34935L,34936L,34937L,34938L,34939L,34940L,34941L,34942L,
-34943L,34944L,34945L,34946L,34947L,34948L,34949L,34950L,34951L,34952L,
-34953L,34954L,34955L,34956L,34957L,34958L,34959L,34960L,34961L,34962L,
-34963L,34964L,34965L,34966L,34967L,34968L,34969L,34970L,34971L,34972L,
-34973L,34974L,34975L,34976L,34977L,34978L,34979L,34980L,34981L,34982L,
-34983L,34984L,34985L,34986L,34987L,34988L,34989L,34990L,34991L,34992L,
-34993L,34994L,34995L,34996L,34997L,34998L,34999L,35000L,35001L,35002L,
-35003L,35004L,35005L,35006L,35007L,35008L,35009L,35010L,35011L,35012L,
-35013L,35014L,35015L,35016L,35017L,35018L,35019L,35020L,35021L,35022L,
-35023L,35024L,35025L,35026L,35027L,35028L,35029L,35030L,35031L,35032L,
-35033L,35034L,35035L,35036L,35037L,35038L,35039L,35040L,35041L,35042L,
-35043L,35044L,35045L,35046L,35047L,35048L,35049L,35050L,35051L,35052L,
-35053L,35054L,35055L,35056L,35057L,35058L,35059L,35060L,35061L,35062L,
-35063L,35064L,35065L,35066L,35067L,35068L,35069L,35070L,35071L,35072L,
-35073L,35074L,35075L,35076L,35077L,35078L,35079L,35080L,35081L,35082L,
-35083L,35084L,35085L,35086L,35087L,35088L,35089L,35090L,35091L,35092L,
-35093L,35094L,35095L,35096L,35097L,35098L,35099L,35100L,35101L,35102L,
-35103L,35104L,35105L,35106L,35107L,35108L,35109L,35110L,35111L,35112L,
-35113L,35114L,35115L,35116L,35117L,35118L,35119L,35120L,35121L,35122L,
-35123L,35124L,35125L,35126L,35127L,35128L,35129L,35130L,35131L,35132L,
-35133L,35134L,35135L,35136L,35137L,35138L,35139L,35140L,35141L,35142L,
-35143L,35144L,35145L,35146L,35147L,35148L,35149L,35150L,35151L,35152L,
-35153L,35154L,35155L,35156L,35157L,35158L,35159L,35160L,35161L,35162L,
-35163L,35164L,35165L,35166L,35167L,35168L,35169L,35170L,35171L,35172L,
-35173L,35174L,35175L,35176L,35177L,35178L,35179L,35180L,35181L,35182L,
-35183L,35184L,35185L,35186L,35187L,35188L,35189L,35190L,35191L,35192L,
-35193L,35194L,35195L,35196L,35197L,35198L,35199L,35200L,35201L,35202L,
-35203L,35204L,35205L,35206L,35207L,35208L,35209L,35210L,35211L,35212L,
-35213L,35214L,35215L,35216L,35217L,35218L,35219L,35220L,35221L,35222L,
-35223L,35224L,35225L,35226L,35227L,35228L,35229L,35230L,35231L,35232L,
-35233L,35234L,35235L,35236L,35237L,35238L,35239L,35240L,35241L,35242L,
-35243L,35244L,35245L,35246L,35247L,35248L,35249L,35250L,35251L,35252L,
-35253L,35254L,35255L,35256L,35257L,35258L,35259L,35260L,35261L,35262L,
-35263L,35264L,35265L,35266L,35267L,35268L,35269L,35270L,35271L,35272L,
-35273L,35274L,35275L,35276L,35277L,35278L,35279L,35280L,35281L,35282L,
-35283L,35284L,35285L,35286L,35287L,35288L,35289L,35290L,35291L,35292L,
-35293L,35294L,35295L,35296L,35297L,35298L,35299L,35300L,35301L,35302L,
-35303L,35304L,35305L,35306L,35307L,35308L,35309L,35310L,35311L,35312L,
-35313L,35314L,35315L,35316L,35317L,35318L,35319L,35320L,35321L,35322L,
-35323L,35324L,35325L,35326L,35327L,35328L,35329L,35330L,35331L,35332L,
-35333L,35334L,35335L,35336L,35337L,35338L,35339L,35340L,35341L,35342L,
-35343L,35344L,35345L,35346L,35347L,35348L,35349L,35350L,35351L,35352L,
-35353L,35354L,35355L,35356L,35357L,35358L,35359L,35360L,35361L,35362L,
-35363L,35364L,35365L,35366L,35367L,35368L,35369L,35370L,35371L,35372L,
-35373L,35374L,35375L,35376L,35377L,35378L,35379L,35380L,35381L,35382L,
-35383L,35384L,35385L,35386L,35387L,35388L,35389L,35390L,35391L,35392L,
-35393L,35394L,35395L,35396L,35397L,35398L,35399L,35400L,35401L,35402L,
-35403L,35404L,35405L,35406L,35407L,35408L,35409L,35410L,35411L,35412L,
-35413L,35414L,35415L,35416L,35417L,35418L,35419L,35420L,35421L,35422L,
-35423L,35424L,35425L,35426L,35427L,35428L,35429L,35430L,35431L,35432L,
-35433L,35434L,35435L,35436L,35437L,35438L,35439L,35440L,35441L,35442L,
-35443L,35444L,35445L,35446L,35447L,35448L,35449L,35450L,35451L,35452L,
-35453L,35454L,35455L,35456L,35457L,35458L,35459L,35460L,35461L,35462L,
-35463L,35464L,35465L,35466L,35467L,35468L,35469L,35470L,35471L,35472L,
-35473L,35474L,35475L,35476L,35477L,35478L,35479L,35480L,35481L,35482L,
-35483L,35484L,35485L,35486L,35487L,35488L,35489L,35490L,35491L,35492L,
-35493L,35494L,35495L,35496L,35497L,35498L,35499L,35500L,35501L,35502L,
-35503L,35504L,35505L,35506L,35507L,35508L,35509L,35510L,35511L,35512L,
-35513L,35514L,35515L,35516L,35517L,35518L,35519L,35520L,35521L,35522L,
-35523L,35524L,35525L,35526L,35527L,35528L,35529L,35530L,35531L,35532L,
-35533L,35534L,35535L,35536L,35537L,35538L,35539L,35540L,35541L,35542L,
-35543L,35544L,35545L,35546L,35547L,35548L,35549L,35550L,35551L,35552L,
-35553L,35554L,35555L,35556L,35557L,35558L,35559L,35560L,35561L,35562L,
-35563L,35564L,35565L,35566L,35567L,35568L,35569L,35570L,35571L,35572L,
-35573L,35574L,35575L,35576L,35577L,35578L,35579L,35580L,35581L,35582L,
-35583L,35584L,35585L,35586L,35587L,35588L,35589L,35590L,35591L,35592L,
-35593L,35594L,35595L,35596L,35597L,35598L,35599L,35600L,35601L,35602L,
-35603L,35604L,35605L,35606L,35607L,35608L,35609L,35610L,35611L,35612L,
-35613L,35614L,35615L,35616L,35617L,35618L,35619L,35620L,35621L,35622L,
-35623L,35624L,35625L,35626L,35627L,35628L,35629L,35630L,35631L,35632L,
-35633L,35634L,35635L,35636L,35637L,35638L,35639L,35640L,35641L,35642L,
-35643L,35644L,35645L,35646L,35647L,35648L,35649L,35650L,35651L,35652L,
-35653L,35654L,35655L,35656L,35657L,35658L,35659L,35660L,35661L,35662L,
-35663L,35664L,35665L,35666L,35667L,35668L,35669L,35670L,35671L,35672L,
-35673L,35674L,35675L,35676L,35677L,35678L,35679L,35680L,35681L,35682L,
-35683L,35684L,35685L,35686L,35687L,35688L,35689L,35690L,35691L,35692L,
-35693L,35694L,35695L,35696L,35697L,35698L,35699L,35700L,35701L,35702L,
-35703L,35704L,35705L,35706L,35707L,35708L,35709L,35710L,35711L,35712L,
-35713L,35714L,35715L,35716L,35717L,35718L,35719L,35720L,35721L,35722L,
-35723L,35724L,35725L,35726L,35727L,35728L,35729L,35730L,35731L,35732L,
-35733L,35734L,35735L,35736L,35737L,35738L,35739L,35740L,35741L,35742L,
-35743L,35744L,35745L,35746L,35747L,35748L,35749L,35750L,35751L,35752L,
-35753L,35754L,35755L,35756L,35757L,35758L,35759L,35760L,35761L,35762L,
-35763L,35764L,35765L,35766L,35767L,35768L,35769L,35770L,35771L,35772L,
-35773L,35774L,35775L,35776L,35777L,35778L,35779L,35780L,35781L,35782L,
-35783L,35784L,35785L,35786L,35787L,35788L,35789L,35790L,35791L,35792L,
-35793L,35794L,35795L,35796L,35797L,35798L,35799L,35800L,35801L,35802L,
-35803L,35804L,35805L,35806L,35807L,35808L,35809L,35810L,35811L,35812L,
-35813L,35814L,35815L,35816L,35817L,35818L,35819L,35820L,35821L,35822L,
-35823L,35824L,35825L,35826L,35827L,35828L,35829L,35830L,35831L,35832L,
-35833L,35834L,35835L,35836L,35837L,35838L,35839L,35840L,35841L,35842L,
-35843L,35844L,35845L,35846L,35847L,35848L,35849L,35850L,35851L,35852L,
-35853L,35854L,35855L,35856L,35857L,35858L,35859L,35860L,35861L,35862L,
-35863L,35864L,35865L,35866L,35867L,35868L,35869L,35870L,35871L,35872L,
-35873L,35874L,35875L,35876L,35877L,35878L,35879L,35880L,35881L,35882L,
-35883L,35884L,35885L,35886L,35887L,35888L,35889L,35890L,35891L,35892L,
-35893L,35894L,35895L,35896L,35897L,35898L,35899L,35900L,35901L,35902L,
-35903L,35904L,35905L,35906L,35907L,35908L,35909L,35910L,35911L,35912L,
-35913L,35914L,35915L,35916L,35917L,35918L,35919L,35920L,35921L,35922L,
-35923L,35924L,35925L,35926L,35927L,35928L,35929L,35930L,35931L,35932L,
-35933L,35934L,35935L,35936L,35937L,35938L,35939L,35940L,35941L,35942L,
-35943L,35944L,35945L,35946L,35947L,35948L,35949L,35950L,35951L,35952L,
-35953L,35954L,35955L,35956L,35957L,35958L,35959L,35960L,35961L,35962L,
-35963L,35964L,35965L,35966L,35967L,35968L,35969L,35970L,35971L,35972L,
-35973L,35974L,35975L,35976L,35977L,35978L,35979L,35980L,35981L,35982L,
-35983L,35984L,35985L,35986L,35987L,35988L,35989L,35990L,35991L,35992L,
-35993L,35994L,35995L,35996L,35997L,35998L,35999L,36000L,36001L,36002L,
-36003L,36004L,36005L,36006L,36007L,36008L,36009L,36010L,36011L,36012L,
-36013L,36014L,36015L,36016L,36017L,36018L,36019L,36020L,36021L,36022L,
-36023L,36024L,36025L,36026L,36027L,36028L,36029L,36030L,36031L,36032L,
-36033L,36034L,36035L,36036L,36037L,36038L,36039L,36040L,36041L,36042L,
-36043L,36044L,36045L,36046L,36047L,36048L,36049L,36050L,36051L,36052L,
-36053L,36054L,36055L,36056L,36057L,36058L,36059L,36060L,36061L,36062L,
-36063L,36064L,36065L,36066L,36067L,36068L,36069L,36070L,36071L,36072L,
-36073L,36074L,36075L,36076L,36077L,36078L,36079L,36080L,36081L,36082L,
-36083L,36084L,36085L,36086L,36087L,36088L,36089L,36090L,36091L,36092L,
-36093L,36094L,36095L,36096L,36097L,36098L,36099L,36100L,36101L,36102L,
-36103L,36104L,36105L,36106L,36107L,36108L,36109L,36110L,36111L,36112L,
-36113L,36114L,36115L,36116L,36117L,36118L,36119L,36120L,36121L,36122L,
-36123L,36124L,36125L,36126L,36127L,36128L,36129L,36130L,36131L,36132L,
-36133L,36134L,36135L,36136L,36137L,36138L,36139L,36140L,36141L,36142L,
-36143L,36144L,36145L,36146L,36147L,36148L,36149L,36150L,36151L,36152L,
-36153L,36154L,36155L,36156L,36157L,36158L,36159L,36160L,36161L,36162L,
-36163L,36164L,36165L,36166L,36167L,36168L,36169L,36170L,36171L,36172L,
-36173L,36174L,36175L,36176L,36177L,36178L,36179L,36180L,36181L,36182L,
-36183L,36184L,36185L,36186L,36187L,36188L,36189L,36190L,36191L,36192L,
-36193L,36194L,36195L,36196L,36197L,36198L,36199L,36200L,36201L,36202L,
-36203L,36204L,36205L,36206L,36207L,36208L,36209L,36210L,36211L,36212L,
-36213L,36214L,36215L,36216L,36217L,36218L,36219L,36220L,36221L,36222L,
-36223L,36224L,36225L,36226L,36227L,36228L,36229L,36230L,36231L,36232L,
-36233L,36234L,36235L,36236L,36237L,36238L,36239L,36240L,36241L,36242L,
-36243L,36244L,36245L,36246L,36247L,36248L,36249L,36250L,36251L,36252L,
-36253L,36254L,36255L,36256L,36257L,36258L,36259L,36260L,36261L,36262L,
-36263L,36264L,36265L,36266L,36267L,36268L,36269L,36270L,36271L,36272L,
-36273L,36274L,36275L,36276L,36277L,36278L,36279L,36280L,36281L,36282L,
-36283L,36284L,36285L,36286L,36287L,36288L,36289L,36290L,36291L,36292L,
-36293L,36294L,36295L,36296L,36297L,36298L,36299L,36300L,36301L,36302L,
-36303L,36304L,36305L,36306L,36307L,36308L,36309L,36310L,36311L,36312L,
-36313L,36314L,36315L,36316L,36317L,36318L,36319L,36320L,36321L,36322L,
-36323L,36324L,36325L,36326L,36327L,36328L,36329L,36330L,36331L,36332L,
-36333L,36334L,36335L,36336L,36337L,36338L,36339L,36340L,36341L,36342L,
-36343L,36344L,36345L,36346L,36347L,36348L,36349L,36350L,36351L,36352L,
-36353L,36354L,36355L,36356L,36357L,36358L,36359L,36360L,36361L,36362L,
-36363L,36364L,36365L,36366L,36367L,36368L,36369L,36370L,36371L,36372L,
-36373L,36374L,36375L,36376L,36377L,36378L,36379L,36380L,36381L,36382L,
-36383L,36384L,36385L,36386L,36387L,36388L,36389L,36390L,36391L,36392L,
-36393L,36394L,36395L,36396L,36397L,36398L,36399L,36400L,36401L,36402L,
-36403L,36404L,36405L,36406L,36407L,36408L,36409L,36410L,36411L,36412L,
-36413L,36414L,36415L,36416L,36417L,36418L,36419L,36420L,36421L,36422L,
-36423L,36424L,36425L,36426L,36427L,36428L,36429L,36430L,36431L,36432L,
-36433L,36434L,36435L,36436L,36437L,36438L,36439L,36440L,36441L,36442L,
-36443L,36444L,36445L,36446L,36447L,36448L,36449L,36450L,36451L,36452L,
-36453L,36454L,36455L,36456L,36457L,36458L,36459L,36460L,36461L,36462L,
-36463L,36464L,36465L,36466L,36467L,36468L,36469L,36470L,36471L,36472L,
-36473L,36474L,36475L,36476L,36477L,36478L,36479L,36480L,36481L,36482L,
-36483L,36484L,36485L,36486L,36487L,36488L,36489L,36490L,36491L,36492L,
-36493L,36494L,36495L,36496L,36497L,36498L,36499L,36500L,36501L,36502L,
-36503L,36504L,36505L,36506L,36507L,36508L,36509L,36510L,36511L,36512L,
-36513L,36514L,36515L,36516L,36517L,36518L,36519L,36520L,36521L,36522L,
-36523L,36524L,36525L,36526L,36527L,36528L,36529L,36530L,36531L,36532L,
-36533L,36534L,36535L,36536L,36537L,36538L,36539L,36540L,36541L,36542L,
-36543L,36544L,36545L,36546L,36547L,36548L,36549L,36550L,36551L,36552L,
-36553L,36554L,36555L,36556L,36557L,36558L,36559L,36560L,36561L,36562L,
-36563L,36564L,36565L,36566L,36567L,36568L,36569L,36570L,36571L,36572L,
-36573L,36574L,36575L,36576L,36577L,36578L,36579L,36580L,36581L,36582L,
-36583L,36584L,36585L,36586L,36587L,36588L,36589L,36590L,36591L,36592L,
-36593L,36594L,36595L,36596L,36597L,36598L,36599L,36600L,36601L,36602L,
-36603L,36604L,36605L,36606L,36607L,36608L,36609L,36610L,36611L,36612L,
-36613L,36614L,36615L,36616L,36617L,36618L,36619L,36620L,36621L,36622L,
-36623L,36624L,36625L,36626L,36627L,36628L,36629L,36630L,36631L,36632L,
-36633L,36634L,36635L,36636L,36637L,36638L,36639L,36640L,36641L,36642L,
-36643L,36644L,36645L,36646L,36647L,36648L,36649L,36650L,36651L,36652L,
-36653L,36654L,36655L,36656L,36657L,36658L,36659L,36660L,36661L,36662L,
-36663L,36664L,36665L,36666L,36667L,36668L,36669L,36670L,36671L,36672L,
-36673L,36674L,36675L,36676L,36677L,36678L,36679L,36680L,36681L,36682L,
-36683L,36684L,36685L,36686L,36687L,36688L,36689L,36690L,36691L,36692L,
-36693L,36694L,36695L,36696L,36697L,36698L,36699L,36700L,36701L,36702L,
-36703L,36704L,36705L,36706L,36707L,36708L,36709L,36710L,36711L,36712L,
-36713L,36714L,36715L,36716L,36717L,36718L,36719L,36720L,36721L,36722L,
-36723L,36724L,36725L,36726L,36727L,36728L,36729L,36730L,36731L,36732L,
-36733L,36734L,36735L,36736L,36737L,36738L,36739L,36740L,36741L,36742L,
-36743L,36744L,36745L,36746L,36747L,36748L,36749L,36750L,36751L,36752L,
-36753L,36754L,36755L,36756L,36757L,36758L,36759L,36760L,36761L,36762L,
-36763L,36764L,36765L,36766L,36767L,36768L,36769L,36770L,36771L,36772L,
-36773L,36774L,36775L,36776L,36777L,36778L,36779L,36780L,36781L,36782L,
-36783L,36784L,36785L,36786L,36787L,36788L,36789L,36790L,36791L,36792L,
-36793L,36794L,36795L,36796L,36797L,36798L,36799L,36800L,36801L,36802L,
-36803L,36804L,36805L,36806L,36807L,36808L,36809L,36810L,36811L,36812L,
-36813L,36814L,36815L,36816L,36817L,36818L,36819L,36820L,36821L,36822L,
-36823L,36824L,36825L,36826L,36827L,36828L,36829L,36830L,36831L,36832L,
-36833L,36834L,36835L,36836L,36837L,36838L,36839L,36840L,36841L,36842L,
-36843L,36844L,36845L,36846L,36847L,36848L,36849L,36850L,36851L,36852L,
-36853L,36854L,36855L,36856L,36857L,36858L,36859L,36860L,36861L,36862L,
-36863L,36864L,36865L,36866L,36867L,36868L,36869L,36870L,36871L,36872L,
-36873L,36874L,36875L,36876L,36877L,36878L,36879L,36880L,36881L,36882L,
-36883L,36884L,36885L,36886L,36887L,36888L,36889L,36890L,36891L,36892L,
-36893L,36894L,36895L,36896L,36897L,36898L,36899L,36900L,36901L,36902L,
-36903L,36904L,36905L,36906L,36907L,36908L,36909L,36910L,36911L,36912L,
-36913L,36914L,36915L,36916L,36917L,36918L,36919L,36920L,36921L,36922L,
-36923L,36924L,36925L,36926L,36927L,36928L,36929L,36930L,36931L,36932L,
-36933L,36934L,36935L,36936L,36937L,36938L,36939L,36940L,36941L,36942L,
-36943L,36944L,36945L,36946L,36947L,36948L,36949L,36950L,36951L,36952L,
-36953L,36954L,36955L,36956L,36957L,36958L,36959L,36960L,36961L,36962L,
-36963L,36964L,36965L,36966L,36967L,36968L,36969L,36970L,36971L,36972L,
-36973L,36974L,36975L,36976L,36977L,36978L,36979L,36980L,36981L,36982L,
-36983L,36984L,36985L,36986L,36987L,36988L,36989L,36990L,36991L,36992L,
-36993L,36994L,36995L,36996L,36997L,36998L,36999L,37000L,37001L,37002L,
-37003L,37004L,37005L,37006L,37007L,37008L,37009L,37010L,37011L,37012L,
-37013L,37014L,37015L,37016L,37017L,37018L,37019L,37020L,37021L,37022L,
-37023L,37024L,37025L,37026L,37027L,37028L,37029L,37030L,37031L,37032L,
-37033L,37034L,37035L,37036L,37037L,37038L,37039L,37040L,37041L,37042L,
-37043L,37044L,37045L,37046L,37047L,37048L,37049L,37050L,37051L,37052L,
-37053L,37054L,37055L,37056L,37057L,37058L,37059L,37060L,37061L,37062L,
-37063L,37064L,37065L,37066L,37067L,37068L,37069L,37070L,37071L,37072L,
-37073L,37074L,37075L,37076L,37077L,37078L,37079L,37080L,37081L,37082L,
-37083L,37084L,37085L,37086L,37087L,37088L,37089L,37090L,37091L,37092L,
-37093L,37094L,37095L,37096L,37097L,37098L,37099L,37100L,37101L,37102L,
-37103L,37104L,37105L,37106L,37107L,37108L,37109L,37110L,37111L,37112L,
-37113L,37114L,37115L,37116L,37117L,37118L,37119L,37120L,37121L,37122L,
-37123L,37124L,37125L,37126L,37127L,37128L,37129L,37130L,37131L,37132L,
-37133L,37134L,37135L,37136L,37137L,37138L,37139L,37140L,37141L,37142L,
-37143L,37144L,37145L,37146L,37147L,37148L,37149L,37150L,37151L,37152L,
-37153L,37154L,37155L,37156L,37157L,37158L,37159L,37160L,37161L,37162L,
-37163L,37164L,37165L,37166L,37167L,37168L,37169L,37170L,37171L,37172L,
-37173L,37174L,37175L,37176L,37177L,37178L,37179L,37180L,37181L,37182L,
-37183L,37184L,37185L,37186L,37187L,37188L,37189L,37190L,37191L,37192L,
-37193L,37194L,37195L,37196L,37197L,37198L,37199L,37200L,37201L,37202L,
-37203L,37204L,37205L,37206L,37207L,37208L,37209L,37210L,37211L,37212L,
-37213L,37214L,37215L,37216L,37217L,37218L,37219L,37220L,37221L,37222L,
-37223L,37224L,37225L,37226L,37227L,37228L,37229L,37230L,37231L,37232L,
-37233L,37234L,37235L,37236L,37237L,37238L,37239L,37240L,37241L,37242L,
-37243L,37244L,37245L,37246L,37247L,37248L,37249L,37250L,37251L,37252L,
-37253L,37254L,37255L,37256L,37257L,37258L,37259L,37260L,37261L,37262L,
-37263L,37264L,37265L,37266L,37267L,37268L,37269L,37270L,37271L,37272L,
-37273L,37274L,37275L,37276L,37277L,37278L,37279L,37280L,37281L,37282L,
-37283L,37284L,37285L,37286L,37287L,37288L,37289L,37290L,37291L,37292L,
-37293L,37294L,37295L,37296L,37297L,37298L,37299L,37300L,37301L,37302L,
-37303L,37304L,37305L,37306L,37307L,37308L,37309L,37310L,37311L,37312L,
-37313L,37314L,37315L,37316L,37317L,37318L,37319L,37320L,37321L,37322L,
-37323L,37324L,37325L,37326L,37327L,37328L,37329L,37330L,37331L,37332L,
-37333L,37334L,37335L,37336L,37337L,37338L,37339L,37340L,37341L,37342L,
-37343L,37344L,37345L,37346L,37347L,37348L,37349L,37350L,37351L,37352L,
-37353L,37354L,37355L,37356L,37357L,37358L,37359L,37360L,37361L,37362L,
-37363L,37364L,37365L,37366L,37367L,37368L,37369L,37370L,37371L,37372L,
-37373L,37374L,37375L,37376L,37377L,37378L,37379L,37380L,37381L,37382L,
-37383L,37384L,37385L,37386L,37387L,37388L,37389L,37390L,37391L,37392L,
-37393L,37394L,37395L,37396L,37397L,37398L,37399L,37400L,37401L,37402L,
-37403L,37404L,37405L,37406L,37407L,37408L,37409L,37410L,37411L,37412L,
-37413L,37414L,37415L,37416L,37417L,37418L,37419L,37420L,37421L,37422L,
-37423L,37424L,37425L,37426L,37427L,37428L,37429L,37430L,37431L,37432L,
-37433L,37434L,37435L,37436L,37437L,37438L,37439L,37440L,37441L,37442L,
-37443L,37444L,37445L,37446L,37447L,37448L,37449L,37450L,37451L,37452L,
-37453L,37454L,37455L,37456L,37457L,37458L,37459L,37460L,37461L,37462L,
-37463L,37464L,37465L,37466L,37467L,37468L,37469L,37470L,37471L,37472L,
-37473L,37474L,37475L,37476L,37477L,37478L,37479L,37480L,37481L,37482L,
-37483L,37484L,37485L,37486L,37487L,37488L,37489L,37490L,37491L,37492L,
-37493L,37494L,37495L,37496L,37497L,37498L,37499L,37500L,37501L,37502L,
-37503L,37504L,37505L,37506L,37507L,37508L,37509L,37510L,37511L,37512L,
-37513L,37514L,37515L,37516L,37517L,37518L,37519L,37520L,37521L,37522L,
-37523L,37524L,37525L,37526L,37527L,37528L,37529L,37530L,37531L,37532L,
-37533L,37534L,37535L,37536L,37537L,37538L,37539L,37540L,37541L,37542L,
-37543L,37544L,37545L,37546L,37547L,37548L,37549L,37550L,37551L,37552L,
-37553L,37554L,37555L,37556L,37557L,37558L,37559L,37560L,37561L,37562L,
-37563L,37564L,37565L,37566L,37567L,37568L,37569L,37570L,37571L,37572L,
-37573L,37574L,37575L,37576L,37577L,37578L,37579L,37580L,37581L,37582L,
-37583L,37584L,37585L,37586L,37587L,37588L,37589L,37590L,37591L,37592L,
-37593L,37594L,37595L,37596L,37597L,37598L,37599L,37600L,37601L,37602L,
-37603L,37604L,37605L,37606L,37607L,37608L,37609L,37610L,37611L,37612L,
-37613L,37614L,37615L,37616L,37617L,37618L,37619L,37620L,37621L,37622L,
-37623L,37624L,37625L,37626L,37627L,37628L,37629L,37630L,37631L,37632L,
-37633L,37634L,37635L,37636L,37637L,37638L,37639L,37640L,37641L,37642L,
-37643L,37644L,37645L,37646L,37647L,37648L,37649L,37650L,37651L,37652L,
-37653L,37654L,37655L,37656L,37657L,37658L,37659L,37660L,37661L,37662L,
-37663L,37664L,37665L,37666L,37667L,37668L,37669L,37670L,37671L,37672L,
-37673L,37674L,37675L,37676L,37677L,37678L,37679L,37680L,37681L,37682L,
-37683L,37684L,37685L,37686L,37687L,37688L,37689L,37690L,37691L,37692L,
-37693L,37694L,37695L,37696L,37697L,37698L,37699L,37700L,37701L,37702L,
-37703L,37704L,37705L,37706L,37707L,37708L,37709L,37710L,37711L,37712L,
-37713L,37714L,37715L,37716L,37717L,37718L,37719L,37720L,37721L,37722L,
-37723L,37724L,37725L,37726L,37727L,37728L,37729L,37730L,37731L,37732L,
-37733L,37734L,37735L,37736L,37737L,37738L,37739L,37740L,37741L,37742L,
-37743L,37744L,37745L,37746L,37747L,37748L,37749L,37750L,37751L,37752L,
-37753L,37754L,37755L,37756L,37757L,37758L,37759L,37760L,37761L,37762L,
-37763L,37764L,37765L,37766L,37767L,37768L,37769L,37770L,37771L,37772L,
-37773L,37774L,37775L,37776L,37777L,37778L,37779L,37780L,37781L,37782L,
-37783L,37784L,37785L,37786L,37787L,37788L,37789L,37790L,37791L,37792L,
-37793L,37794L,37795L,37796L,37797L,37798L,37799L,37800L,37801L,37802L,
-37803L,37804L,37805L,37806L,37807L,37808L,37809L,37810L,37811L,37812L,
-37813L,37814L,37815L,37816L,37817L,37818L,37819L,37820L,37821L,37822L,
-37823L,37824L,37825L,37826L,37827L,37828L,37829L,37830L,37831L,37832L,
-37833L,37834L,37835L,37836L,37837L,37838L,37839L,37840L,37841L,37842L,
-37843L,37844L,37845L,37846L,37847L,37848L,37849L,37850L,37851L,37852L,
-37853L,37854L,37855L,37856L,37857L,37858L,37859L,37860L,37861L,37862L,
-37863L,37864L,37865L,37866L,37867L,37868L,37869L,37870L,37871L,37872L,
-37873L,37874L,37875L,37876L,37877L,37878L,37879L,37880L,37881L,37882L,
-37883L,37884L,37885L,37886L,37887L,37888L,37889L,37890L,37891L,37892L,
-37893L,37894L,37895L,37896L,37897L,37898L,37899L,37900L,37901L,37902L,
-37903L,37904L,37905L,37906L,37907L,37908L,37909L,37910L,37911L,37912L,
-37913L,37914L,37915L,37916L,37917L,37918L,37919L,37920L,37921L,37922L,
-37923L,37924L,37925L,37926L,37927L,37928L,37929L,37930L,37931L,37932L,
-37933L,37934L,37935L,37936L,37937L,37938L,37939L,37940L,37941L,37942L,
-37943L,37944L,37945L,37946L,37947L,37948L,37949L,37950L,37951L,37952L,
-37953L,37954L,37955L,37956L,37957L,37958L,37959L,37960L,37961L,37962L,
-37963L,37964L,37965L,37966L,37967L,37968L,37969L,37970L,37971L,37972L,
-37973L,37974L,37975L,37976L,37977L,37978L,37979L,37980L,37981L,37982L,
-37983L,37984L,37985L,37986L,37987L,37988L,37989L,37990L,37991L,37992L,
-37993L,37994L,37995L,37996L,37997L,37998L,37999L,38000L,38001L,38002L,
-38003L,38004L,38005L,38006L,38007L,38008L,38009L,38010L,38011L,38012L,
-38013L,38014L,38015L,38016L,38017L,38018L,38019L,38020L,38021L,38022L,
-38023L,38024L,38025L,38026L,38027L,38028L,38029L,38030L,38031L,38032L,
-38033L,38034L,38035L,38036L,38037L,38038L,38039L,38040L,38041L,38042L,
-38043L,38044L,38045L,38046L,38047L,38048L,38049L,38050L,38051L,38052L,
-38053L,38054L,38055L,38056L,38057L,38058L,38059L,38060L,38061L,38062L,
-38063L,38064L,38065L,38066L,38067L,38068L,38069L,38070L,38071L,38072L,
-38073L,38074L,38075L,38076L,38077L,38078L,38079L,38080L,38081L,38082L,
-38083L,38084L,38085L,38086L,38087L,38088L,38089L,38090L,38091L,38092L,
-38093L,38094L,38095L,38096L,38097L,38098L,38099L,38100L,38101L,38102L,
-38103L,38104L,38105L,38106L,38107L,38108L,38109L,38110L,38111L,38112L,
-38113L,38114L,38115L,38116L,38117L,38118L,38119L,38120L,38121L,38122L,
-38123L,38124L,38125L,38126L,38127L,38128L,38129L,38130L,38131L,38132L,
-38133L,38134L,38135L,38136L,38137L,38138L,38139L,38140L,38141L,38142L,
-38143L,38144L,38145L,38146L,38147L,38148L,38149L,38150L,38151L,38152L,
-38153L,38154L,38155L,38156L,38157L,38158L,38159L,38160L,38161L,38162L,
-38163L,38164L,38165L,38166L,38167L,38168L,38169L,38170L,38171L,38172L,
-38173L,38174L,38175L,38176L,38177L,38178L,38179L,38180L,38181L,38182L,
-38183L,38184L,38185L,38186L,38187L,38188L,38189L,38190L,38191L,38192L,
-38193L,38194L,38195L,38196L,38197L,38198L,38199L,38200L,38201L,38202L,
-38203L,38204L,38205L,38206L,38207L,38208L,38209L,38210L,38211L,38212L,
-38213L,38214L,38215L,38216L,38217L,38218L,38219L,38220L,38221L,38222L,
-38223L,38224L,38225L,38226L,38227L,38228L,38229L,38230L,38231L,38232L,
-38233L,38234L,38235L,38236L,38237L,38238L,38239L,38240L,38241L,38242L,
-38243L,38244L,38245L,38246L,38247L,38248L,38249L,38250L,38251L,38252L,
-38253L,38254L,38255L,38256L,38257L,38258L,38259L,38260L,38261L,38262L,
-38263L,38264L,38265L,38266L,38267L,38268L,38269L,38270L,38271L,38272L,
-38273L,38274L,38275L,38276L,38277L,38278L,38279L,38280L,38281L,38282L,
-38283L,38284L,38285L,38286L,38287L,38288L,38289L,38290L,38291L,38292L,
-38293L,38294L,38295L,38296L,38297L,38298L,38299L,38300L,38301L,38302L,
-38303L,38304L,38305L,38306L,38307L,38308L,38309L,38310L,38311L,38312L,
-38313L,38314L,38315L,38316L,38317L,38318L,38319L,38320L,38321L,38322L,
-38323L,38324L,38325L,38326L,38327L,38328L,38329L,38330L,38331L,38332L,
-38333L,38334L,38335L,38336L,38337L,38338L,38339L,38340L,38341L,38342L,
-38343L,38344L,38345L,38346L,38347L,38348L,38349L,38350L,38351L,38352L,
-38353L,38354L,38355L,38356L,38357L,38358L,38359L,38360L,38361L,38362L,
-38363L,38364L,38365L,38366L,38367L,38368L,38369L,38370L,38371L,38372L,
-38373L,38374L,38375L,38376L,38377L,38378L,38379L,38380L,38381L,38382L,
-38383L,38384L,38385L,38386L,38387L,38388L,38389L,38390L,38391L,38392L,
-38393L,38394L,38395L,38396L,38397L,38398L,38399L,38400L,38401L,38402L,
-38403L,38404L,38405L,38406L,38407L,38408L,38409L,38410L,38411L,38412L,
-38413L,38414L,38415L,38416L,38417L,38418L,38419L,38420L,38421L,38422L,
-38423L,38424L,38425L,38426L,38427L,38428L,38429L,38430L,38431L,38432L,
-38433L,38434L,38435L,38436L,38437L,38438L,38439L,38440L,38441L,38442L,
-38443L,38444L,38445L,38446L,38447L,38448L,38449L,38450L,38451L,38452L,
-38453L,38454L,38455L,38456L,38457L,38458L,38459L,38460L,38461L,38462L,
-38463L,38464L,38465L,38466L,38467L,38468L,38469L,38470L,38471L,38472L,
-38473L,38474L,38475L,38476L,38477L,38478L,38479L,38480L,38481L,38482L,
-38483L,38484L,38485L,38486L,38487L,38488L,38489L,38490L,38491L,38492L,
-38493L,38494L,38495L,38496L,38497L,38498L,38499L,38500L,38501L,38502L,
-38503L,38504L,38505L,38506L,38507L,38508L,38509L,38510L,38511L,38512L,
-38513L,38514L,38515L,38516L,38517L,38518L,38519L,38520L,38521L,38522L,
-38523L,38524L,38525L,38526L,38527L,38528L,38529L,38530L,38531L,38532L,
-38533L,38534L,38535L,38536L,38537L,38538L,38539L,38540L,38541L,38542L,
-38543L,38544L,38545L,38546L,38547L,38548L,38549L,38550L,38551L,38552L,
-38553L,38554L,38555L,38556L,38557L,38558L,38559L,38560L,38561L,38562L,
-38563L,38564L,38565L,38566L,38567L,38568L,38569L,38570L,38571L,38572L,
-38573L,38574L,38575L,38576L,38577L,38578L,38579L,38580L,38581L,38582L,
-38583L,38584L,38585L,38586L,38587L,38588L,38589L,38590L,38591L,38592L,
-38593L,38594L,38595L,38596L,38597L,38598L,38599L,38600L,38601L,38602L,
-38603L,38604L,38605L,38606L,38607L,38608L,38609L,38610L,38611L,38612L,
-38613L,38614L,38615L,38616L,38617L,38618L,38619L,38620L,38621L,38622L,
-38623L,38624L,38625L,38626L,38627L,38628L,38629L,38630L,38631L,38632L,
-38633L,38634L,38635L,38636L,38637L,38638L,38639L,38640L,38641L,38642L,
-38643L,38644L,38645L,38646L,38647L,38648L,38649L,38650L,38651L,38652L,
-38653L,38654L,38655L,38656L,38657L,38658L,38659L,38660L,38661L,38662L,
-38663L,38664L,38665L,38666L,38667L,38668L,38669L,38670L,38671L,38672L,
-38673L,38674L,38675L,38676L,38677L,38678L,38679L,38680L,38681L,38682L,
-38683L,38684L,38685L,38686L,38687L,38688L,38689L,38690L,38691L,38692L,
-38693L,38694L,38695L,38696L,38697L,38698L,38699L,38700L,38701L,38702L,
-38703L,38704L,38705L,38706L,38707L,38708L,38709L,38710L,38711L,38712L,
-38713L,38714L,38715L,38716L,38717L,38718L,38719L,38720L,38721L,38722L,
-38723L,38724L,38725L,38726L,38727L,38728L,38729L,38730L,38731L,38732L,
-38733L,38734L,38735L,38736L,38737L,38738L,38739L,38740L,38741L,38742L,
-38743L,38744L,38745L,38746L,38747L,38748L,38749L,38750L,38751L,38752L,
-38753L,38754L,38755L,38756L,38757L,38758L,38759L,38760L,38761L,38762L,
-38763L,38764L,38765L,38766L,38767L,38768L,38769L,38770L,38771L,38772L,
-38773L,38774L,38775L,38776L,38777L,38778L,38779L,38780L,38781L,38782L,
-38783L,38784L,38785L,38786L,38787L,38788L,38789L,38790L,38791L,38792L,
-38793L,38794L,38795L,38796L,38797L,38798L,38799L,38800L,38801L,38802L,
-38803L,38804L,38805L,38806L,38807L,38808L,38809L,38810L,38811L,38812L,
-38813L,38814L,38815L,38816L,38817L,38818L,38819L,38820L,38821L,38822L,
-38823L,38824L,38825L,38826L,38827L,38828L,38829L,38830L,38831L,38832L,
-38833L,38834L,38835L,38836L,38837L,38838L,38839L,38840L,38841L,38842L,
-38843L,38844L,38845L,38846L,38847L,38848L,38849L,38850L,38851L,38852L,
-38853L,38854L,38855L,38856L,38857L,38858L,38859L,38860L,38861L,38862L,
-38863L,38864L,38865L,38866L,38867L,38868L,38869L,38870L,38871L,38872L,
-38873L,38874L,38875L,38876L,38877L,38878L,38879L,38880L,38881L,38882L,
-38883L,38884L,38885L,38886L,38887L,38888L,38889L,38890L,38891L,38892L,
-38893L,38894L,38895L,38896L,38897L,38898L,38899L,38900L,38901L,38902L,
-38903L,38904L,38905L,38906L,38907L,38908L,38909L,38910L,38911L,38912L,
-38913L,38914L,38915L,38916L,38917L,38918L,38919L,38920L,38921L,38922L,
-38923L,38924L,38925L,38926L,38927L,38928L,38929L,38930L,38931L,38932L,
-38933L,38934L,38935L,38936L,38937L,38938L,38939L,38940L,38941L,38942L,
-38943L,38944L,38945L,38946L,38947L,38948L,38949L,38950L,38951L,38952L,
-38953L,38954L,38955L,38956L,38957L,38958L,38959L,38960L,38961L,38962L,
-38963L,38964L,38965L,38966L,38967L,38968L,38969L,38970L,38971L,38972L,
-38973L,38974L,38975L,38976L,38977L,38978L,38979L,38980L,38981L,38982L,
-38983L,38984L,38985L,38986L,38987L,38988L,38989L,38990L,38991L,38992L,
-38993L,38994L,38995L,38996L,38997L,38998L,38999L,39000L,39001L,39002L,
-39003L,39004L,39005L,39006L,39007L,39008L,39009L,39010L,39011L,39012L,
-39013L,39014L,39015L,39016L,39017L,39018L,39019L,39020L,39021L,39022L,
-39023L,39024L,39025L,39026L,39027L,39028L,39029L,39030L,39031L,39032L,
-39033L,39034L,39035L,39036L,39037L,39038L,39039L,39040L,39041L,39042L,
-39043L,39044L,39045L,39046L,39047L,39048L,39049L,39050L,39051L,39052L,
-39053L,39054L,39055L,39056L,39057L,39058L,39059L,39060L,39061L,39062L,
-39063L,39064L,39065L,39066L,39067L,39068L,39069L,39070L,39071L,39072L,
-39073L,39074L,39075L,39076L,39077L,39078L,39079L,39080L,39081L,39082L,
-39083L,39084L,39085L,39086L,39087L,39088L,39089L,39090L,39091L,39092L,
-39093L,39094L,39095L,39096L,39097L,39098L,39099L,39100L,39101L,39102L,
-39103L,39104L,39105L,39106L,39107L,39108L,39109L,39110L,39111L,39112L,
-39113L,39114L,39115L,39116L,39117L,39118L,39119L,39120L,39121L,39122L,
-39123L,39124L,39125L,39126L,39127L,39128L,39129L,39130L,39131L,39132L,
-39133L,39134L,39135L,39136L,39137L,39138L,39139L,39140L,39141L,39142L,
-39143L,39144L,39145L,39146L,39147L,39148L,39149L,39150L,39151L,39152L,
-39153L,39154L,39155L,39156L,39157L,39158L,39159L,39160L,39161L,39162L,
-39163L,39164L,39165L,39166L,39167L,39168L,39169L,39170L,39171L,39172L,
-39173L,39174L,39175L,39176L,39177L,39178L,39179L,39180L,39181L,39182L,
-39183L,39184L,39185L,39186L,39187L,39188L,39189L,39190L,39191L,39192L,
-39193L,39194L,39195L,39196L,39197L,39198L,39199L,39200L,39201L,39202L,
-39203L,39204L,39205L,39206L,39207L,39208L,39209L,39210L,39211L,39212L,
-39213L,39214L,39215L,39216L,39217L,39218L,39219L,39220L,39221L,39222L,
-39223L,39224L,39225L,39226L,39227L,39228L,39229L,39230L,39231L,39232L,
-39233L,39234L,39235L,39236L,39237L,39238L,39239L,39240L,39241L,39242L,
-39243L,39244L,39245L,39246L,39247L,39248L,39249L,39250L,39251L,39252L,
-39253L,39254L,39255L,39256L,39257L,39258L,39259L,39260L,39261L,39262L,
-39263L,39264L,39265L,39266L,39267L,39268L,39269L,39270L,39271L,39272L,
-39273L,39274L,39275L,39276L,39277L,39278L,39279L,39280L,39281L,39282L,
-39283L,39284L,39285L,39286L,39287L,39288L,39289L,39290L,39291L,39292L,
-39293L,39294L,39295L,39296L,39297L,39298L,39299L,39300L,39301L,39302L,
-39303L,39304L,39305L,39306L,39307L,39308L,39309L,39310L,39311L,39312L,
-39313L,39314L,39315L,39316L,39317L,39318L,39319L,39320L,39321L,39322L,
-39323L,39324L,39325L,39326L,39327L,39328L,39329L,39330L,39331L,39332L,
-39333L,39334L,39335L,39336L,39337L,39338L,39339L,39340L,39341L,39342L,
-39343L,39344L,39345L,39346L,39347L,39348L,39349L,39350L,39351L,39352L,
-39353L,39354L,39355L,39356L,39357L,39358L,39359L,39360L,39361L,39362L,
-39363L,39364L,39365L,39366L,39367L,39368L,39369L,39370L,39371L,39372L,
-39373L,39374L,39375L,39376L,39377L,39378L,39379L,39380L,39381L,39382L,
-39383L,39384L,39385L,39386L,39387L,39388L,39389L,39390L,39391L,39392L,
-39393L,39394L,39395L,39396L,39397L,39398L,39399L,39400L,39401L,39402L,
-39403L,39404L,39405L,39406L,39407L,39408L,39409L,39410L,39411L,39412L,
-39413L,39414L,39415L,39416L,39417L,39418L,39419L,39420L,39421L,39422L,
-39423L,39424L,39425L,39426L,39427L,39428L,39429L,39430L,39431L,39432L,
-39433L,39434L,39435L,39436L,39437L,39438L,39439L,39440L,39441L,39442L,
-39443L,39444L,39445L,39446L,39447L,39448L,39449L,39450L,39451L,39452L,
-39453L,39454L,39455L,39456L,39457L,39458L,39459L,39460L,39461L,39462L,
-39463L,39464L,39465L,39466L,39467L,39468L,39469L,39470L,39471L,39472L,
-39473L,39474L,39475L,39476L,39477L,39478L,39479L,39480L,39481L,39482L,
-39483L,39484L,39485L,39486L,39487L,39488L,39489L,39490L,39491L,39492L,
-39493L,39494L,39495L,39496L,39497L,39498L,39499L,39500L,39501L,39502L,
-39503L,39504L,39505L,39506L,39507L,39508L,39509L,39510L,39511L,39512L,
-39513L,39514L,39515L,39516L,39517L,39518L,39519L,39520L,39521L,39522L,
-39523L,39524L,39525L,39526L,39527L,39528L,39529L,39530L,39531L,39532L,
-39533L,39534L,39535L,39536L,39537L,39538L,39539L,39540L,39541L,39542L,
-39543L,39544L,39545L,39546L,39547L,39548L,39549L,39550L,39551L,39552L,
-39553L,39554L,39555L,39556L,39557L,39558L,39559L,39560L,39561L,39562L,
-39563L,39564L,39565L,39566L,39567L,39568L,39569L,39570L,39571L,39572L,
-39573L,39574L,39575L,39576L,39577L,39578L,39579L,39580L,39581L,39582L,
-39583L,39584L,39585L,39586L,39587L,39588L,39589L,39590L,39591L,39592L,
-39593L,39594L,39595L,39596L,39597L,39598L,39599L,39600L,39601L,39602L,
-39603L,39604L,39605L,39606L,39607L,39608L,39609L,39610L,39611L,39612L,
-39613L,39614L,39615L,39616L,39617L,39618L,39619L,39620L,39621L,39622L,
-39623L,39624L,39625L,39626L,39627L,39628L,39629L,39630L,39631L,39632L,
-39633L,39634L,39635L,39636L,39637L,39638L,39639L,39640L,39641L,39642L,
-39643L,39644L,39645L,39646L,39647L,39648L,39649L,39650L,39651L,39652L,
-39653L,39654L,39655L,39656L,39657L,39658L,39659L,39660L,39661L,39662L,
-39663L,39664L,39665L,39666L,39667L,39668L,39669L,39670L,39671L,39672L,
-39673L,39674L,39675L,39676L,39677L,39678L,39679L,39680L,39681L,39682L,
-39683L,39684L,39685L,39686L,39687L,39688L,39689L,39690L,39691L,39692L,
-39693L,39694L,39695L,39696L,39697L,39698L,39699L,39700L,39701L,39702L,
-39703L,39704L,39705L,39706L,39707L,39708L,39709L,39710L,39711L,39712L,
-39713L,39714L,39715L,39716L,39717L,39718L,39719L,39720L,39721L,39722L,
-39723L,39724L,39725L,39726L,39727L,39728L,39729L,39730L,39731L,39732L,
-39733L,39734L,39735L,39736L,39737L,39738L,39739L,39740L,39741L,39742L,
-39743L,39744L,39745L,39746L,39747L,39748L,39749L,39750L,39751L,39752L,
-39753L,39754L,39755L,39756L,39757L,39758L,39759L,39760L,39761L,39762L,
-39763L,39764L,39765L,39766L,39767L,39768L,39769L,39770L,39771L,39772L,
-39773L,39774L,39775L,39776L,39777L,39778L,39779L,39780L,39781L,39782L,
-39783L,39784L,39785L,39786L,39787L,39788L,39789L,39790L,39791L,39792L,
-39793L,39794L,39795L,39796L,39797L,39798L,39799L,39800L,39801L,39802L,
-39803L,39804L,39805L,39806L,39807L,39808L,39809L,39810L,39811L,39812L,
-39813L,39814L,39815L,39816L,39817L,39818L,39819L,39820L,39821L,39822L,
-39823L,39824L,39825L,39826L,39827L,39828L,39829L,39830L,39831L,39832L,
-39833L,39834L,39835L,39836L,39837L,39838L,39839L,39840L,39841L,39842L,
-39843L,39844L,39845L,39846L,39847L,39848L,39849L,39850L,39851L,39852L,
-39853L,39854L,39855L,39856L,39857L,39858L,39859L,39860L,39861L,39862L,
-39863L,39864L,39865L,39866L,39867L,39868L,39869L,39870L,39871L,39872L,
-39873L,39874L,39875L,39876L,39877L,39878L,39879L,39880L,39881L,39882L,
-39883L,39884L,39885L,39886L,39887L,39888L,39889L,39890L,39891L,39892L,
-39893L,39894L,39895L,39896L,39897L,39898L,39899L,39900L,39901L,39902L,
-39903L,39904L,39905L,39906L,39907L,39908L,39909L,39910L,39911L,39912L,
-39913L,39914L,39915L,39916L,39917L,39918L,39919L,39920L,39921L,39922L,
-39923L,39924L,39925L,39926L,39927L,39928L,39929L,39930L,39931L,39932L,
-39933L,39934L,39935L,39936L,39937L,39938L,39939L,39940L,39941L,39942L,
-39943L,39944L,39945L,39946L,39947L,39948L,39949L,39950L,39951L,39952L,
-39953L,39954L,39955L,39956L,39957L,39958L,39959L,39960L,39961L,39962L,
-39963L,39964L,39965L,39966L,39967L,39968L,39969L,39970L,39971L,39972L,
-39973L,39974L,39975L,39976L,39977L,39978L,39979L,39980L,39981L,39982L,
-39983L,39984L,39985L,39986L,39987L,39988L,39989L,39990L,39991L,39992L,
-39993L,39994L,39995L,39996L,39997L,39998L,39999L,40000L,40001L,40002L,
-40003L,40004L,40005L,40006L,40007L,40008L,40009L,40010L,40011L,40012L,
-40013L,40014L,40015L,40016L,40017L,40018L,40019L,40020L,40021L,40022L,
-40023L,40024L,40025L,40026L,40027L,40028L,40029L,40030L,40031L,40032L,
-40033L,40034L,40035L,40036L,40037L,40038L,40039L,40040L,40041L,40042L,
-40043L,40044L,40045L,40046L,40047L,40048L,40049L,40050L,40051L,40052L,
-40053L,40054L,40055L,40056L,40057L,40058L,40059L,40060L,40061L,40062L,
-40063L,40064L,40065L,40066L,40067L,40068L,40069L,40070L,40071L,40072L,
-40073L,40074L,40075L,40076L,40077L,40078L,40079L,40080L,40081L,40082L,
-40083L,40084L,40085L,40086L,40087L,40088L,40089L,40090L,40091L,40092L,
-40093L,40094L,40095L,40096L,40097L,40098L,40099L,40100L,40101L,40102L,
-40103L,40104L,40105L,40106L,40107L,40108L,40109L,40110L,40111L,40112L,
-40113L,40114L,40115L,40116L,40117L,40118L,40119L,40120L,40121L,40122L,
-40123L,40124L,40125L,40126L,40127L,40128L,40129L,40130L,40131L,40132L,
-40133L,40134L,40135L,40136L,40137L,40138L,40139L,40140L,40141L,40142L,
-40143L,40144L,40145L,40146L,40147L,40148L,40149L,40150L,40151L,40152L,
-40153L,40154L,40155L,40156L,40157L,40158L,40159L,40160L,40161L,40162L,
-40163L,40164L,40165L,40166L,40167L,40168L,40169L,40170L,40171L,40172L,
-40173L,40174L,40175L,40176L,40177L,40178L,40179L,40180L,40181L,40182L,
-40183L,40184L,40185L,40186L,40187L,40188L,40189L,40190L,40191L,40192L,
-40193L,40194L,40195L,40196L,40197L,40198L,40199L,40200L,40201L,40202L,
-40203L,40204L,40205L,40206L,40207L,40208L,40209L,40210L,40211L,40212L,
-40213L,40214L,40215L,40216L,40217L,40218L,40219L,40220L,40221L,40222L,
-40223L,40224L,40225L,40226L,40227L,40228L,40229L,40230L,40231L,40232L,
-40233L,40234L,40235L,40236L,40237L,40238L,40239L,40240L,40241L,40242L,
-40243L,40244L,40245L,40246L,40247L,40248L,40249L,40250L,40251L,40252L,
-40253L,40254L,40255L,40256L,40257L,40258L,40259L,40260L,40261L,40262L,
-40263L,40264L,40265L,40266L,40267L,40268L,40269L,40270L,40271L,40272L,
-40273L,40274L,40275L,40276L,40277L,40278L,40279L,40280L,40281L,40282L,
-40283L,40284L,40285L,40286L,40287L,40288L,40289L,40290L,40291L,40292L,
-40293L,40294L,40295L,40296L,40297L,40298L,40299L,40300L,40301L,40302L,
-40303L,40304L,40305L,40306L,40307L,40308L,40309L,40310L,40311L,40312L,
-40313L,40314L,40315L,40316L,40317L,40318L,40319L,40320L,40321L,40322L,
-40323L,40324L,40325L,40326L,40327L,40328L,40329L,40330L,40331L,40332L,
-40333L,40334L,40335L,40336L,40337L,40338L,40339L,40340L,40341L,40342L,
-40343L,40344L,40345L,40346L,40347L,40348L,40349L,40350L,40351L,40352L,
-40353L,40354L,40355L,40356L,40357L,40358L,40359L,40360L,40361L,40362L,
-40363L,40364L,40365L,40366L,40367L,40368L,40369L,40370L,40371L,40372L,
-40373L,40374L,40375L,40376L,40377L,40378L,40379L,40380L,40381L,40382L,
-40383L,40384L,40385L,40386L,40387L,40388L,40389L,40390L,40391L,40392L,
-40393L,40394L,40395L,40396L,40397L,40398L,40399L,40400L,40401L,40402L,
-40403L,40404L,40405L,40406L,40407L,40408L,40409L,40410L,40411L,40412L,
-40413L,40414L,40415L,40416L,40417L,40418L,40419L,40420L,40421L,40422L,
-40423L,40424L,40425L,40426L,40427L,40428L,40429L,40430L,40431L,40432L,
-40433L,40434L,40435L,40436L,40437L,40438L,40439L,40440L,40441L,40442L,
-40443L,40444L,40445L,40446L,40447L,40448L,40449L,40450L,40451L,40452L,
-40453L,40454L,40455L,40456L,40457L,40458L,40459L,40460L,40461L,40462L,
-40463L,40464L,40465L,40466L,40467L,40468L,40469L,40470L,40471L,40472L,
-40473L,40474L,40475L,40476L,40477L,40478L,40479L,40480L,40481L,40482L,
-40483L,40484L,40485L,40486L,40487L,40488L,40489L,40490L,40491L,40492L,
-40493L,40494L,40495L,40496L,40497L,40498L,40499L,40500L,40501L,40502L,
-40503L,40504L,40505L,40506L,40507L,40508L,40509L,40510L,40511L,40512L,
-40513L,40514L,40515L,40516L,40517L,40518L,40519L,40520L,40521L,40522L,
-40523L,40524L,40525L,40526L,40527L,40528L,40529L,40530L,40531L,40532L,
-40533L,40534L,40535L,40536L,40537L,40538L,40539L,40540L,40541L,40542L,
-40543L,40544L,40545L,40546L,40547L,40548L,40549L,40550L,40551L,40552L,
-40553L,40554L,40555L,40556L,40557L,40558L,40559L,40560L,40561L,40562L,
-40563L,40564L,40565L,40566L,40567L,40568L,40569L,40570L,40571L,40572L,
-40573L,40574L,40575L,40576L,40577L,40578L,40579L,40580L,40581L,40582L,
-40583L,40584L,40585L,40586L,40587L,40588L,40589L,40590L,40591L,40592L,
-40593L,40594L,40595L,40596L,40597L,40598L,40599L,40600L,40601L,40602L,
-40603L,40604L,40605L,40606L,40607L,40608L,40609L,40610L,40611L,40612L,
-40613L,40614L,40615L,40616L,40617L,40618L,40619L,40620L,40621L,40622L,
-40623L,40624L,40625L,40626L,40627L,40628L,40629L,40630L,40631L,40632L,
-40633L,40634L,40635L,40636L,40637L,40638L,40639L,40640L,40641L,40642L,
-40643L,40644L,40645L,40646L,40647L,40648L,40649L,40650L,40651L,40652L,
-40653L,40654L,40655L,40656L,40657L,40658L,40659L,40660L,40661L,40662L,
-40663L,40664L,40665L,40666L,40667L,40668L,40669L,40670L,40671L,40672L,
-40673L,40674L,40675L,40676L,40677L,40678L,40679L,40680L,40681L,40682L,
-40683L,40684L,40685L,40686L,40687L,40688L,40689L,40690L,40691L,40692L,
-40693L,40694L,40695L,40696L,40697L,40698L,40699L,40700L,40701L,40702L,
-40703L,40704L,40705L,40706L,40707L,40708L,40709L,40710L,40711L,40712L,
-40713L,40714L,40715L,40716L,40717L,40718L,40719L,40720L,40721L,40722L,
-40723L,40724L,40725L,40726L,40727L,40728L,40729L,40730L,40731L,40732L,
-40733L,40734L,40735L,40736L,40737L,40738L,40739L,40740L,40741L,40742L,
-40743L,40744L,40745L,40746L,40747L,40748L,40749L,40750L,40751L,40752L,
-40753L,40754L,40755L,40756L,40757L,40758L,40759L,40760L,40761L,40762L,
-40763L,40764L,40765L,40766L,40767L,40768L,40769L,40770L,40771L,40772L,
-40773L,40774L,40775L,40776L,40777L,40778L,40779L,40780L,40781L,40782L,
-40783L,40784L,40785L,40786L,40787L,40788L,40789L,40790L,40791L,40792L,
-40793L,40794L,40795L,40796L,40797L,40798L,40799L,40800L,40801L,40802L,
-40803L,40804L,40805L,40806L,40807L,40808L,40809L,40810L,40811L,40812L,
-40813L,40814L,40815L,40816L,40817L,40818L,40819L,40820L,40821L,40822L,
-40823L,40824L,40825L,40826L,40827L,40828L,40829L,40830L,40831L,40832L,
-40833L,40834L,40835L,40836L,40837L,40838L,40839L,40840L,40841L,40842L,
-40843L,40844L,40845L,40846L,40847L,40848L,40849L,40850L,40851L,40852L,
-40853L,40854L,40855L,40856L,40857L,40858L,40859L,40860L,40861L,40862L,
-40863L,40864L,40865L,40866L,40867L,40868L,40869L,40870L,40871L,40872L,
-40873L,40874L,40875L,40876L,40877L,40878L,40879L,40880L,40881L,40882L,
-40883L,40884L,40885L,40886L,40887L,40888L,40889L,40890L,40891L,40892L,
-40893L,40894L,40895L,40896L,40897L,40898L,40899L,40900L,40901L,40902L,
-40903L,40904L,40905L,40906L,40907L,40908L,40909L,40910L,40911L,40912L,
-40913L,40914L,40915L,40916L,40917L,40918L,40919L,40920L,40921L,40922L,
-40923L,40924L,40925L,40926L,40927L,40928L,40929L,40930L,40931L,40932L,
-40933L,40934L,40935L,40936L,40937L,40938L,40939L,40940L,40941L,40942L,
-40943L,40944L,40945L,40946L,40947L,40948L,40949L,40950L,40951L,40952L,
-40953L,40954L,40955L,40956L,40957L,40958L,40959L,40960L,40961L,40962L,
-40963L,40964L,40965L,40966L,40967L,40968L,40969L,40970L,40971L,40972L,
-40973L,40974L,40975L,40976L,40977L,40978L,40979L,40980L,40981L,40982L,
-40983L,40984L,40985L,40986L,40987L,40988L,40989L,40990L,40991L,40992L,
-40993L,40994L,40995L,40996L,40997L,40998L,40999L,41000L,41001L,41002L,
-41003L,41004L,41005L,41006L,41007L,41008L,41009L,41010L,41011L,41012L,
-41013L,41014L,41015L,41016L,41017L,41018L,41019L,41020L,41021L,41022L,
-41023L,41024L,41025L,41026L,41027L,41028L,41029L,41030L,41031L,41032L,
-41033L,41034L,41035L,41036L,41037L,41038L,41039L,41040L,41041L,41042L,
-41043L,41044L,41045L,41046L,41047L,41048L,41049L,41050L,41051L,41052L,
-41053L,41054L,41055L,41056L,41057L,41058L,41059L,41060L,41061L,41062L,
-41063L,41064L,41065L,41066L,41067L,41068L,41069L,41070L,41071L,41072L,
-41073L,41074L,41075L,41076L,41077L,41078L,41079L,41080L,41081L,41082L,
-41083L,41084L,41085L,41086L,41087L,41088L,41089L,41090L,41091L,41092L,
-41093L,41094L,41095L,41096L,41097L,41098L,41099L,41100L,41101L,41102L,
-41103L,41104L,41105L,41106L,41107L,41108L,41109L,41110L,41111L,41112L,
-41113L,41114L,41115L,41116L,41117L,41118L,41119L,41120L,41121L,41122L,
-41123L,41124L,41125L,41126L,41127L,41128L,41129L,41130L,41131L,41132L,
-41133L,41134L,41135L,41136L,41137L,41138L,41139L,41140L,41141L,41142L,
-41143L,41144L,41145L,41146L,41147L,41148L,41149L,41150L,41151L,41152L,
-41153L,41154L,41155L,41156L,41157L,41158L,41159L,41160L,41161L,41162L,
-41163L,41164L,41165L,41166L,41167L,41168L,41169L,41170L,41171L,41172L,
-41173L,41174L,41175L,41176L,41177L,41178L,41179L,41180L,41181L,41182L,
-41183L,41184L,41185L,41186L,41187L,41188L,41189L,41190L,41191L,41192L,
-41193L,41194L,41195L,41196L,41197L,41198L,41199L,41200L,41201L,41202L,
-41203L,41204L,41205L,41206L,41207L,41208L,41209L,41210L,41211L,41212L,
-41213L,41214L,41215L,41216L,41217L,41218L,41219L,41220L,41221L,41222L,
-41223L,41224L,41225L,41226L,41227L,41228L,41229L,41230L,41231L,41232L,
-41233L,41234L,41235L,41236L,41237L,41238L,41239L,41240L,41241L,41242L,
-41243L,41244L,41245L,41246L,41247L,41248L,41249L,41250L,41251L,41252L,
-41253L,41254L,41255L,41256L,41257L,41258L,41259L,41260L,41261L,41262L,
-41263L,41264L,41265L,41266L,41267L,41268L,41269L,41270L,41271L,41272L,
-41273L,41274L,41275L,41276L,41277L,41278L,41279L,41280L,41281L,41282L,
-41283L,41284L,41285L,41286L,41287L,41288L,41289L,41290L,41291L,41292L,
-41293L,41294L,41295L,41296L,41297L,41298L,41299L,41300L,41301L,41302L,
-41303L,41304L,41305L,41306L,41307L,41308L,41309L,41310L,41311L,41312L,
-41313L,41314L,41315L,41316L,41317L,41318L,41319L,41320L,41321L,41322L,
-41323L,41324L,41325L,41326L,41327L,41328L,41329L,41330L,41331L,41332L,
-41333L,41334L,41335L,41336L,41337L,41338L,41339L,41340L,41341L,41342L,
-41343L,41344L,41345L,41346L,41347L,41348L,41349L,41350L,41351L,41352L,
-41353L,41354L,41355L,41356L,41357L,41358L,41359L,41360L,41361L,41362L,
-41363L,41364L,41365L,41366L,41367L,41368L,41369L,41370L,41371L,41372L,
-41373L,41374L,41375L,41376L,41377L,41378L,41379L,41380L,41381L,41382L,
-41383L,41384L,41385L,41386L,41387L,41388L,41389L,41390L,41391L,41392L,
-41393L,41394L,41395L,41396L,41397L,41398L,41399L,41400L,41401L,41402L,
-41403L,41404L,41405L,41406L,41407L,41408L,41409L,41410L,41411L,41412L,
-41413L,41414L,41415L,41416L,41417L,41418L,41419L,41420L,41421L,41422L,
-41423L,41424L,41425L,41426L,41427L,41428L,41429L,41430L,41431L,41432L,
-41433L,41434L,41435L,41436L,41437L,41438L,41439L,41440L,41441L,41442L,
-41443L,41444L,41445L,41446L,41447L,41448L,41449L,41450L,41451L,41452L,
-41453L,41454L,41455L,41456L,41457L,41458L,41459L,41460L,41461L,41462L,
-41463L,41464L,41465L,41466L,41467L,41468L,41469L,41470L,41471L,41472L,
-41473L,41474L,41475L,41476L,41477L,41478L,41479L,41480L,41481L,41482L,
-41483L,41484L,41485L,41486L,41487L,41488L,41489L,41490L,41491L,41492L,
-41493L,41494L,41495L,41496L,41497L,41498L,41499L,41500L,41501L,41502L,
-41503L,41504L,41505L,41506L,41507L,41508L,41509L,41510L,41511L,41512L,
-41513L,41514L,41515L,41516L,41517L,41518L,41519L,41520L,41521L,41522L,
-41523L,41524L,41525L,41526L,41527L,41528L,41529L,41530L,41531L,41532L,
-41533L,41534L,41535L,41536L,41537L,41538L,41539L,41540L,41541L,41542L,
-41543L,41544L,41545L,41546L,41547L,41548L,41549L,41550L,41551L,41552L,
-41553L,41554L,41555L,41556L,41557L,41558L,41559L,41560L,41561L,41562L,
-41563L,41564L,41565L,41566L,41567L,41568L,41569L,41570L,41571L,41572L,
-41573L,41574L,41575L,41576L,41577L,41578L,41579L,41580L,41581L,41582L,
-41583L,41584L,41585L,41586L,41587L,41588L,41589L,41590L,41591L,41592L,
-41593L,41594L,41595L,41596L,41597L,41598L,41599L,41600L,41601L,41602L,
-41603L,41604L,41605L,41606L,41607L,41608L,41609L,41610L,41611L,41612L,
-41613L,41614L,41615L,41616L,41617L,41618L,41619L,41620L,41621L,41622L,
-41623L,41624L,41625L,41626L,41627L,41628L,41629L,41630L,41631L,41632L,
-41633L,41634L,41635L,41636L,41637L,41638L,41639L,41640L,41641L,41642L,
-41643L,41644L,41645L,41646L,41647L,41648L,41649L,41650L,41651L,41652L,
-41653L,41654L,41655L,41656L,41657L,41658L,41659L,41660L,41661L,41662L,
-41663L,41664L,41665L,41666L,41667L,41668L,41669L,41670L,41671L,41672L,
-41673L,41674L,41675L,41676L,41677L,41678L,41679L,41680L,41681L,41682L,
-41683L,41684L,41685L,41686L,41687L,41688L,41689L,41690L,41691L,41692L,
-41693L,41694L,41695L,41696L,41697L,41698L,41699L,41700L,41701L,41702L,
-41703L,41704L,41705L,41706L,41707L,41708L,41709L,41710L,41711L,41712L,
-41713L,41714L,41715L,41716L,41717L,41718L,41719L,41720L,41721L,41722L,
-41723L,41724L,41725L,41726L,41727L,41728L,41729L,41730L,41731L,41732L,
-41733L,41734L,41735L,41736L,41737L,41738L,41739L,41740L,41741L,41742L,
-41743L,41744L,41745L,41746L,41747L,41748L,41749L,41750L,41751L,41752L,
-41753L,41754L,41755L,41756L,41757L,41758L,41759L,41760L,41761L,41762L,
-41763L,41764L,41765L,41766L,41767L,41768L,41769L,41770L,41771L,41772L,
-41773L,41774L,41775L,41776L,41777L,41778L,41779L,41780L,41781L,41782L,
-41783L,41784L,41785L,41786L,41787L,41788L,41789L,41790L,41791L,41792L,
-41793L,41794L,41795L,41796L,41797L,41798L,41799L,41800L,41801L,41802L,
-41803L,41804L,41805L,41806L,41807L,41808L,41809L,41810L,41811L,41812L,
-41813L,41814L,41815L,41816L,41817L,41818L,41819L,41820L,41821L,41822L,
-41823L,41824L,41825L,41826L,41827L,41828L,41829L,41830L,41831L,41832L,
-41833L,41834L,41835L,41836L,41837L,41838L,41839L,41840L,41841L,41842L,
-41843L,41844L,41845L,41846L,41847L,41848L,41849L,41850L,41851L,41852L,
-41853L,41854L,41855L,41856L,41857L,41858L,41859L,41860L,41861L,41862L,
-41863L,41864L,41865L,41866L,41867L,41868L,41869L,41870L,41871L,41872L,
-41873L,41874L,41875L,41876L,41877L,41878L,41879L,41880L,41881L,41882L,
-41883L,41884L,41885L,41886L,41887L,41888L,41889L,41890L,41891L,41892L,
-41893L,41894L,41895L,41896L,41897L,41898L,41899L,41900L,41901L,41902L,
-41903L,41904L,41905L,41906L,41907L,41908L,41909L,41910L,41911L,41912L,
-41913L,41914L,41915L,41916L,41917L,41918L,41919L,41920L,41921L,41922L,
-41923L,41924L,41925L,41926L,41927L,41928L,41929L,41930L,41931L,41932L,
-41933L,41934L,41935L,41936L,41937L,41938L,41939L,41940L,41941L,41942L,
-41943L,41944L,41945L,41946L,41947L,41948L,41949L,41950L,41951L,41952L,
-41953L,41954L,41955L,41956L,41957L,41958L,41959L,41960L,41961L,41962L,
-41963L,41964L,41965L,41966L,41967L,41968L,41969L,41970L,41971L,41972L,
-41973L,41974L,41975L,41976L,41977L,41978L,41979L,41980L,41981L,41982L,
-41983L,41984L,41985L,41986L,41987L,41988L,41989L,41990L,41991L,41992L,
-41993L,41994L,41995L,41996L,41997L,41998L,41999L,42000L,42001L,42002L,
-42003L,42004L,42005L,42006L,42007L,42008L,42009L,42010L,42011L,42012L,
-42013L,42014L,42015L,42016L,42017L,42018L,42019L,42020L,42021L,42022L,
-42023L,42024L,42025L,42026L,42027L,42028L,42029L,42030L,42031L,42032L,
-42033L,42034L,42035L,42036L,42037L,42038L,42039L,42040L,42041L,42042L,
-42043L,42044L,42045L,42046L,42047L,42048L,42049L,42050L,42051L,42052L,
-42053L,42054L,42055L,42056L,42057L,42058L,42059L,42060L,42061L,42062L,
-42063L,42064L,42065L,42066L,42067L,42068L,42069L,42070L,42071L,42072L,
-42073L,42074L,42075L,42076L,42077L,42078L,42079L,42080L,42081L,42082L,
-42083L,42084L,42085L,42086L,42087L,42088L,42089L,42090L,42091L,42092L,
-42093L,42094L,42095L,42096L,42097L,42098L,42099L,42100L,42101L,42102L,
-42103L,42104L,42105L,42106L,42107L,42108L,42109L,42110L,42111L,42112L,
-42113L,42114L,42115L,42116L,42117L,42118L,42119L,42120L,42121L,42122L,
-42123L,42124L,42125L,42126L,42127L,42128L,42129L,42130L,42131L,42132L,
-42133L,42134L,42135L,42136L,42137L,42138L,42139L,42140L,42141L,42142L,
-42143L,42144L,42145L,42146L,42147L,42148L,42149L,42150L,42151L,42152L,
-42153L,42154L,42155L,42156L,42157L,42158L,42159L,42160L,42161L,42162L,
-42163L,42164L,42165L,42166L,42167L,42168L,42169L,42170L,42171L,42172L,
-42173L,42174L,42175L,42176L,42177L,42178L,42179L,42180L,42181L,42182L,
-42183L,42184L,42185L,42186L,42187L,42188L,42189L,42190L,42191L,42192L,
-42193L,42194L,42195L,42196L,42197L,42198L,42199L,42200L,42201L,42202L,
-42203L,42204L,42205L,42206L,42207L,42208L,42209L,42210L,42211L,42212L,
-42213L,42214L,42215L,42216L,42217L,42218L,42219L,42220L,42221L,42222L,
-42223L,42224L,42225L,42226L,42227L,42228L,42229L,42230L,42231L,42232L,
-42233L,42234L,42235L,42236L,42237L,42238L,42239L,42240L,42241L,42242L,
-42243L,42244L,42245L,42246L,42247L,42248L,42249L,42250L,42251L,42252L,
-42253L,42254L,42255L,42256L,42257L,42258L,42259L,42260L,42261L,42262L,
-42263L,42264L,42265L,42266L,42267L,42268L,42269L,42270L,42271L,42272L,
-42273L,42274L,42275L,42276L,42277L,42278L,42279L,42280L,42281L,42282L,
-42283L,42284L,42285L,42286L,42287L,42288L,42289L,42290L,42291L,42292L,
-42293L,42294L,42295L,42296L,42297L,42298L,42299L,42300L,42301L,42302L,
-42303L,42304L,42305L,42306L,42307L,42308L,42309L,42310L,42311L,42312L,
-42313L,42314L,42315L,42316L,42317L,42318L,42319L,42320L,42321L,42322L,
-42323L,42324L,42325L,42326L,42327L,42328L,42329L,42330L,42331L,42332L,
-42333L,42334L,42335L,42336L,42337L,42338L,42339L,42340L,42341L,42342L,
-42343L,42344L,42345L,42346L,42347L,42348L,42349L,42350L,42351L,42352L,
-42353L,42354L,42355L,42356L,42357L,42358L,42359L,42360L,42361L,42362L,
-42363L,42364L,42365L,42366L,42367L,42368L,42369L,42370L,42371L,42372L,
-42373L,42374L,42375L,42376L,42377L,42378L,42379L,42380L,42381L,42382L,
-42383L,42384L,42385L,42386L,42387L,42388L,42389L,42390L,42391L,42392L,
-42393L,42394L,42395L,42396L,42397L,42398L,42399L,42400L,42401L,42402L,
-42403L,42404L,42405L,42406L,42407L,42408L,42409L,42410L,42411L,42412L,
-42413L,42414L,42415L,42416L,42417L,42418L,42419L,42420L,42421L,42422L,
-42423L,42424L,42425L,42426L,42427L,42428L,42429L,42430L,42431L,42432L,
-42433L,42434L,42435L,42436L,42437L,42438L,42439L,42440L,42441L,42442L,
-42443L,42444L,42445L,42446L,42447L,42448L,42449L,42450L,42451L,42452L,
-42453L,42454L,42455L,42456L,42457L,42458L,42459L,42460L,42461L,42462L,
-42463L,42464L,42465L,42466L,42467L,42468L,42469L,42470L,42471L,42472L,
-42473L,42474L,42475L,42476L,42477L,42478L,42479L,42480L,42481L,42482L,
-42483L,42484L,42485L,42486L,42487L,42488L,42489L,42490L,42491L,42492L,
-42493L,42494L,42495L,42496L,42497L,42498L,42499L,42500L,42501L,42502L,
-42503L,42504L,42505L,42506L,42507L,42508L,42509L,42510L,42511L,42512L,
-42513L,42514L,42515L,42516L,42517L,42518L,42519L,42520L,42521L,42522L,
-42523L,42524L,42525L,42526L,42527L,42528L,42529L,42530L,42531L,42532L,
-42533L,42534L,42535L,42536L,42537L,42538L,42539L,42540L,42541L,42542L,
-42543L,42544L,42545L,42546L,42547L,42548L,42549L,42550L,42551L,42552L,
-42553L,42554L,42555L,42556L,42557L,42558L,42559L,42560L,42560L,42562L,
-42562L,42564L,42564L,42566L,42566L,42568L,42568L,42570L,42570L,42572L,
-42572L,42574L,42574L,42576L,42576L,42578L,42578L,42580L,42580L,42582L,
-42582L,42584L,42584L,42586L,42586L,42588L,42588L,42590L,42590L,42592L,
-42592L,42594L,42594L,42596L,42596L,42598L,42598L,42600L,42600L,42602L,
-42602L,42604L,42604L,42606L,42607L,42608L,42609L,42610L,42611L,42612L,
-42613L,42614L,42615L,42616L,42617L,42618L,42619L,42620L,42621L,42622L,
-42623L,42624L,42624L,42626L,42626L,42628L,42628L,42630L,42630L,42632L,
-42632L,42634L,42634L,42636L,42636L,42638L,42638L,42640L,42640L,42642L,
-42642L,42644L,42644L,42646L,42646L,42648L,42649L,42650L,42651L,42652L,
-42653L,42654L,42655L,42656L,42657L,42658L,42659L,42660L,42661L,42662L,
-42663L,42664L,42665L,42666L,42667L,42668L,42669L,42670L,42671L,42672L,
-42673L,42674L,42675L,42676L,42677L,42678L,42679L,42680L,42681L,42682L,
-42683L,42684L,42685L,42686L,42687L,42688L,42689L,42690L,42691L,42692L,
-42693L,42694L,42695L,42696L,42697L,42698L,42699L,42700L,42701L,42702L,
-42703L,42704L,42705L,42706L,42707L,42708L,42709L,42710L,42711L,42712L,
-42713L,42714L,42715L,42716L,42717L,42718L,42719L,42720L,42721L,42722L,
-42723L,42724L,42725L,42726L,42727L,42728L,42729L,42730L,42731L,42732L,
-42733L,42734L,42735L,42736L,42737L,42738L,42739L,42740L,42741L,42742L,
-42743L,42744L,42745L,42746L,42747L,42748L,42749L,42750L,42751L,42752L,
-42753L,42754L,42755L,42756L,42757L,42758L,42759L,42760L,42761L,42762L,
-42763L,42764L,42765L,42766L,42767L,42768L,42769L,42770L,42771L,42772L,
-42773L,42774L,42775L,42776L,42777L,42778L,42779L,42780L,42781L,42782L,
-42783L,42784L,42785L,42786L,42786L,42788L,42788L,42790L,42790L,42792L,
-42792L,42794L,42794L,42796L,42796L,42798L,42798L,42800L,42801L,42802L,
-42802L,42804L,42804L,42806L,42806L,42808L,42808L,42810L,42810L,42812L,
-42812L,42814L,42814L,42816L,42816L,42818L,42818L,42820L,42820L,42822L,
-42822L,42824L,42824L,42826L,42826L,42828L,42828L,42830L,42830L,42832L,
-42832L,42834L,42834L,42836L,42836L,42838L,42838L,42840L,42840L,42842L,
-42842L,42844L,42844L,42846L,42846L,42848L,42848L,42850L,42850L,42852L,
-42852L,42854L,42854L,42856L,42856L,42858L,42858L,42860L,42860L,42862L,
-42862L,42864L,42865L,42866L,42867L,42868L,42869L,42870L,42871L,42872L,
-42873L,42873L,42875L,42875L,42877L,42878L,42878L,42880L,42880L,42882L,
-42882L,42884L,42884L,42886L,42886L,42888L,42889L,42890L,42891L,42891L,
-42893L,42894L,42895L,42896L,42896L,42898L,42899L,42900L,42901L,42902L,
-42903L,42904L,42905L,42906L,42907L,42908L,42909L,42910L,42911L,42912L,
-42912L,42914L,42914L,42916L,42916L,42918L,42918L,42920L,42920L,42922L,
-42923L,42924L,42925L,42926L,42927L,42928L,42929L,42930L,42931L,42932L,
-42933L,42934L,42935L,42936L,42937L,42938L,42939L,42940L,42941L,42942L,
-42943L,42944L,42945L,42946L,42947L,42948L,42949L,42950L,42951L,42952L,
-42953L,42954L,42955L,42956L,42957L,42958L,42959L,42960L,42961L,42962L,
-42963L,42964L,42965L,42966L,42967L,42968L,42969L,42970L,42971L,42972L,
-42973L,42974L,42975L,42976L,42977L,42978L,42979L,42980L,42981L,42982L,
-42983L,42984L,42985L,42986L,42987L,42988L,42989L,42990L,42991L,42992L,
-42993L,42994L,42995L,42996L,42997L,42998L,42999L,43000L,43001L,43002L,
-43003L,43004L,43005L,43006L,43007L,43008L,43009L,43010L,43011L,43012L,
-43013L,43014L,43015L,43016L,43017L,43018L,43019L,43020L,43021L,43022L,
-43023L,43024L,43025L,43026L,43027L,43028L,43029L,43030L,43031L,43032L,
-43033L,43034L,43035L,43036L,43037L,43038L,43039L,43040L,43041L,43042L,
-43043L,43044L,43045L,43046L,43047L,43048L,43049L,43050L,43051L,43052L,
-43053L,43054L,43055L,43056L,43057L,43058L,43059L,43060L,43061L,43062L,
-43063L,43064L,43065L,43066L,43067L,43068L,43069L,43070L,43071L,43072L,
-43073L,43074L,43075L,43076L,43077L,43078L,43079L,43080L,43081L,43082L,
-43083L,43084L,43085L,43086L,43087L,43088L,43089L,43090L,43091L,43092L,
-43093L,43094L,43095L,43096L,43097L,43098L,43099L,43100L,43101L,43102L,
-43103L,43104L,43105L,43106L,43107L,43108L,43109L,43110L,43111L,43112L,
-43113L,43114L,43115L,43116L,43117L,43118L,43119L,43120L,43121L,43122L,
-43123L,43124L,43125L,43126L,43127L,43128L,43129L,43130L,43131L,43132L,
-43133L,43134L,43135L,43136L,43137L,43138L,43139L,43140L,43141L,43142L,
-43143L,43144L,43145L,43146L,43147L,43148L,43149L,43150L,43151L,43152L,
-43153L,43154L,43155L,43156L,43157L,43158L,43159L,43160L,43161L,43162L,
-43163L,43164L,43165L,43166L,43167L,43168L,43169L,43170L,43171L,43172L,
-43173L,43174L,43175L,43176L,43177L,43178L,43179L,43180L,43181L,43182L,
-43183L,43184L,43185L,43186L,43187L,43188L,43189L,43190L,43191L,43192L,
-43193L,43194L,43195L,43196L,43197L,43198L,43199L,43200L,43201L,43202L,
-43203L,43204L,43205L,43206L,43207L,43208L,43209L,43210L,43211L,43212L,
-43213L,43214L,43215L,43216L,43217L,43218L,43219L,43220L,43221L,43222L,
-43223L,43224L,43225L,43226L,43227L,43228L,43229L,43230L,43231L,43232L,
-43233L,43234L,43235L,43236L,43237L,43238L,43239L,43240L,43241L,43242L,
-43243L,43244L,43245L,43246L,43247L,43248L,43249L,43250L,43251L,43252L,
-43253L,43254L,43255L,43256L,43257L,43258L,43259L,43260L,43261L,43262L,
-43263L,43264L,43265L,43266L,43267L,43268L,43269L,43270L,43271L,43272L,
-43273L,43274L,43275L,43276L,43277L,43278L,43279L,43280L,43281L,43282L,
-43283L,43284L,43285L,43286L,43287L,43288L,43289L,43290L,43291L,43292L,
-43293L,43294L,43295L,43296L,43297L,43298L,43299L,43300L,43301L,43302L,
-43303L,43304L,43305L,43306L,43307L,43308L,43309L,43310L,43311L,43312L,
-43313L,43314L,43315L,43316L,43317L,43318L,43319L,43320L,43321L,43322L,
-43323L,43324L,43325L,43326L,43327L,43328L,43329L,43330L,43331L,43332L,
-43333L,43334L,43335L,43336L,43337L,43338L,43339L,43340L,43341L,43342L,
-43343L,43344L,43345L,43346L,43347L,43348L,43349L,43350L,43351L,43352L,
-43353L,43354L,43355L,43356L,43357L,43358L,43359L,43360L,43361L,43362L,
-43363L,43364L,43365L,43366L,43367L,43368L,43369L,43370L,43371L,43372L,
-43373L,43374L,43375L,43376L,43377L,43378L,43379L,43380L,43381L,43382L,
-43383L,43384L,43385L,43386L,43387L,43388L,43389L,43390L,43391L,43392L,
-43393L,43394L,43395L,43396L,43397L,43398L,43399L,43400L,43401L,43402L,
-43403L,43404L,43405L,43406L,43407L,43408L,43409L,43410L,43411L,43412L,
-43413L,43414L,43415L,43416L,43417L,43418L,43419L,43420L,43421L,43422L,
-43423L,43424L,43425L,43426L,43427L,43428L,43429L,43430L,43431L,43432L,
-43433L,43434L,43435L,43436L,43437L,43438L,43439L,43440L,43441L,43442L,
-43443L,43444L,43445L,43446L,43447L,43448L,43449L,43450L,43451L,43452L,
-43453L,43454L,43455L,43456L,43457L,43458L,43459L,43460L,43461L,43462L,
-43463L,43464L,43465L,43466L,43467L,43468L,43469L,43470L,43471L,43472L,
-43473L,43474L,43475L,43476L,43477L,43478L,43479L,43480L,43481L,43482L,
-43483L,43484L,43485L,43486L,43487L,43488L,43489L,43490L,43491L,43492L,
-43493L,43494L,43495L,43496L,43497L,43498L,43499L,43500L,43501L,43502L,
-43503L,43504L,43505L,43506L,43507L,43508L,43509L,43510L,43511L,43512L,
-43513L,43514L,43515L,43516L,43517L,43518L,43519L,43520L,43521L,43522L,
-43523L,43524L,43525L,43526L,43527L,43528L,43529L,43530L,43531L,43532L,
-43533L,43534L,43535L,43536L,43537L,43538L,43539L,43540L,43541L,43542L,
-43543L,43544L,43545L,43546L,43547L,43548L,43549L,43550L,43551L,43552L,
-43553L,43554L,43555L,43556L,43557L,43558L,43559L,43560L,43561L,43562L,
-43563L,43564L,43565L,43566L,43567L,43568L,43569L,43570L,43571L,43572L,
-43573L,43574L,43575L,43576L,43577L,43578L,43579L,43580L,43581L,43582L,
-43583L,43584L,43585L,43586L,43587L,43588L,43589L,43590L,43591L,43592L,
-43593L,43594L,43595L,43596L,43597L,43598L,43599L,43600L,43601L,43602L,
-43603L,43604L,43605L,43606L,43607L,43608L,43609L,43610L,43611L,43612L,
-43613L,43614L,43615L,43616L,43617L,43618L,43619L,43620L,43621L,43622L,
-43623L,43624L,43625L,43626L,43627L,43628L,43629L,43630L,43631L,43632L,
-43633L,43634L,43635L,43636L,43637L,43638L,43639L,43640L,43641L,43642L,
-43643L,43644L,43645L,43646L,43647L,43648L,43649L,43650L,43651L,43652L,
-43653L,43654L,43655L,43656L,43657L,43658L,43659L,43660L,43661L,43662L,
-43663L,43664L,43665L,43666L,43667L,43668L,43669L,43670L,43671L,43672L,
-43673L,43674L,43675L,43676L,43677L,43678L,43679L,43680L,43681L,43682L,
-43683L,43684L,43685L,43686L,43687L,43688L,43689L,43690L,43691L,43692L,
-43693L,43694L,43695L,43696L,43697L,43698L,43699L,43700L,43701L,43702L,
-43703L,43704L,43705L,43706L,43707L,43708L,43709L,43710L,43711L,43712L,
-43713L,43714L,43715L,43716L,43717L,43718L,43719L,43720L,43721L,43722L,
-43723L,43724L,43725L,43726L,43727L,43728L,43729L,43730L,43731L,43732L,
-43733L,43734L,43735L,43736L,43737L,43738L,43739L,43740L,43741L,43742L,
-43743L,43744L,43745L,43746L,43747L,43748L,43749L,43750L,43751L,43752L,
-43753L,43754L,43755L,43756L,43757L,43758L,43759L,43760L,43761L,43762L,
-43763L,43764L,43765L,43766L,43767L,43768L,43769L,43770L,43771L,43772L,
-43773L,43774L,43775L,43776L,43777L,43778L,43779L,43780L,43781L,43782L,
-43783L,43784L,43785L,43786L,43787L,43788L,43789L,43790L,43791L,43792L,
-43793L,43794L,43795L,43796L,43797L,43798L,43799L,43800L,43801L,43802L,
-43803L,43804L,43805L,43806L,43807L,43808L,43809L,43810L,43811L,43812L,
-43813L,43814L,43815L,43816L,43817L,43818L,43819L,43820L,43821L,43822L,
-43823L,43824L,43825L,43826L,43827L,43828L,43829L,43830L,43831L,43832L,
-43833L,43834L,43835L,43836L,43837L,43838L,43839L,43840L,43841L,43842L,
-43843L,43844L,43845L,43846L,43847L,43848L,43849L,43850L,43851L,43852L,
-43853L,43854L,43855L,43856L,43857L,43858L,43859L,43860L,43861L,43862L,
-43863L,43864L,43865L,43866L,43867L,43868L,43869L,43870L,43871L,43872L,
-43873L,43874L,43875L,43876L,43877L,43878L,43879L,43880L,43881L,43882L,
-43883L,43884L,43885L,43886L,43887L,43888L,43889L,43890L,43891L,43892L,
-43893L,43894L,43895L,43896L,43897L,43898L,43899L,43900L,43901L,43902L,
-43903L,43904L,43905L,43906L,43907L,43908L,43909L,43910L,43911L,43912L,
-43913L,43914L,43915L,43916L,43917L,43918L,43919L,43920L,43921L,43922L,
-43923L,43924L,43925L,43926L,43927L,43928L,43929L,43930L,43931L,43932L,
-43933L,43934L,43935L,43936L,43937L,43938L,43939L,43940L,43941L,43942L,
-43943L,43944L,43945L,43946L,43947L,43948L,43949L,43950L,43951L,43952L,
-43953L,43954L,43955L,43956L,43957L,43958L,43959L,43960L,43961L,43962L,
-43963L,43964L,43965L,43966L,43967L,43968L,43969L,43970L,43971L,43972L,
-43973L,43974L,43975L,43976L,43977L,43978L,43979L,43980L,43981L,43982L,
-43983L,43984L,43985L,43986L,43987L,43988L,43989L,43990L,43991L,43992L,
-43993L,43994L,43995L,43996L,43997L,43998L,43999L,44000L,44001L,44002L,
-44003L,44004L,44005L,44006L,44007L,44008L,44009L,44010L,44011L,44012L,
-44013L,44014L,44015L,44016L,44017L,44018L,44019L,44020L,44021L,44022L,
-44023L,44024L,44025L,44026L,44027L,44028L,44029L,44030L,44031L,44032L,
-44033L,44034L,44035L,44036L,44037L,44038L,44039L,44040L,44041L,44042L,
-44043L,44044L,44045L,44046L,44047L,44048L,44049L,44050L,44051L,44052L,
-44053L,44054L,44055L,44056L,44057L,44058L,44059L,44060L,44061L,44062L,
-44063L,44064L,44065L,44066L,44067L,44068L,44069L,44070L,44071L,44072L,
-44073L,44074L,44075L,44076L,44077L,44078L,44079L,44080L,44081L,44082L,
-44083L,44084L,44085L,44086L,44087L,44088L,44089L,44090L,44091L,44092L,
-44093L,44094L,44095L,44096L,44097L,44098L,44099L,44100L,44101L,44102L,
-44103L,44104L,44105L,44106L,44107L,44108L,44109L,44110L,44111L,44112L,
-44113L,44114L,44115L,44116L,44117L,44118L,44119L,44120L,44121L,44122L,
-44123L,44124L,44125L,44126L,44127L,44128L,44129L,44130L,44131L,44132L,
-44133L,44134L,44135L,44136L,44137L,44138L,44139L,44140L,44141L,44142L,
-44143L,44144L,44145L,44146L,44147L,44148L,44149L,44150L,44151L,44152L,
-44153L,44154L,44155L,44156L,44157L,44158L,44159L,44160L,44161L,44162L,
-44163L,44164L,44165L,44166L,44167L,44168L,44169L,44170L,44171L,44172L,
-44173L,44174L,44175L,44176L,44177L,44178L,44179L,44180L,44181L,44182L,
-44183L,44184L,44185L,44186L,44187L,44188L,44189L,44190L,44191L,44192L,
-44193L,44194L,44195L,44196L,44197L,44198L,44199L,44200L,44201L,44202L,
-44203L,44204L,44205L,44206L,44207L,44208L,44209L,44210L,44211L,44212L,
-44213L,44214L,44215L,44216L,44217L,44218L,44219L,44220L,44221L,44222L,
-44223L,44224L,44225L,44226L,44227L,44228L,44229L,44230L,44231L,44232L,
-44233L,44234L,44235L,44236L,44237L,44238L,44239L,44240L,44241L,44242L,
-44243L,44244L,44245L,44246L,44247L,44248L,44249L,44250L,44251L,44252L,
-44253L,44254L,44255L,44256L,44257L,44258L,44259L,44260L,44261L,44262L,
-44263L,44264L,44265L,44266L,44267L,44268L,44269L,44270L,44271L,44272L,
-44273L,44274L,44275L,44276L,44277L,44278L,44279L,44280L,44281L,44282L,
-44283L,44284L,44285L,44286L,44287L,44288L,44289L,44290L,44291L,44292L,
-44293L,44294L,44295L,44296L,44297L,44298L,44299L,44300L,44301L,44302L,
-44303L,44304L,44305L,44306L,44307L,44308L,44309L,44310L,44311L,44312L,
-44313L,44314L,44315L,44316L,44317L,44318L,44319L,44320L,44321L,44322L,
-44323L,44324L,44325L,44326L,44327L,44328L,44329L,44330L,44331L,44332L,
-44333L,44334L,44335L,44336L,44337L,44338L,44339L,44340L,44341L,44342L,
-44343L,44344L,44345L,44346L,44347L,44348L,44349L,44350L,44351L,44352L,
-44353L,44354L,44355L,44356L,44357L,44358L,44359L,44360L,44361L,44362L,
-44363L,44364L,44365L,44366L,44367L,44368L,44369L,44370L,44371L,44372L,
-44373L,44374L,44375L,44376L,44377L,44378L,44379L,44380L,44381L,44382L,
-44383L,44384L,44385L,44386L,44387L,44388L,44389L,44390L,44391L,44392L,
-44393L,44394L,44395L,44396L,44397L,44398L,44399L,44400L,44401L,44402L,
-44403L,44404L,44405L,44406L,44407L,44408L,44409L,44410L,44411L,44412L,
-44413L,44414L,44415L,44416L,44417L,44418L,44419L,44420L,44421L,44422L,
-44423L,44424L,44425L,44426L,44427L,44428L,44429L,44430L,44431L,44432L,
-44433L,44434L,44435L,44436L,44437L,44438L,44439L,44440L,44441L,44442L,
-44443L,44444L,44445L,44446L,44447L,44448L,44449L,44450L,44451L,44452L,
-44453L,44454L,44455L,44456L,44457L,44458L,44459L,44460L,44461L,44462L,
-44463L,44464L,44465L,44466L,44467L,44468L,44469L,44470L,44471L,44472L,
-44473L,44474L,44475L,44476L,44477L,44478L,44479L,44480L,44481L,44482L,
-44483L,44484L,44485L,44486L,44487L,44488L,44489L,44490L,44491L,44492L,
-44493L,44494L,44495L,44496L,44497L,44498L,44499L,44500L,44501L,44502L,
-44503L,44504L,44505L,44506L,44507L,44508L,44509L,44510L,44511L,44512L,
-44513L,44514L,44515L,44516L,44517L,44518L,44519L,44520L,44521L,44522L,
-44523L,44524L,44525L,44526L,44527L,44528L,44529L,44530L,44531L,44532L,
-44533L,44534L,44535L,44536L,44537L,44538L,44539L,44540L,44541L,44542L,
-44543L,44544L,44545L,44546L,44547L,44548L,44549L,44550L,44551L,44552L,
-44553L,44554L,44555L,44556L,44557L,44558L,44559L,44560L,44561L,44562L,
-44563L,44564L,44565L,44566L,44567L,44568L,44569L,44570L,44571L,44572L,
-44573L,44574L,44575L,44576L,44577L,44578L,44579L,44580L,44581L,44582L,
-44583L,44584L,44585L,44586L,44587L,44588L,44589L,44590L,44591L,44592L,
-44593L,44594L,44595L,44596L,44597L,44598L,44599L,44600L,44601L,44602L,
-44603L,44604L,44605L,44606L,44607L,44608L,44609L,44610L,44611L,44612L,
-44613L,44614L,44615L,44616L,44617L,44618L,44619L,44620L,44621L,44622L,
-44623L,44624L,44625L,44626L,44627L,44628L,44629L,44630L,44631L,44632L,
-44633L,44634L,44635L,44636L,44637L,44638L,44639L,44640L,44641L,44642L,
-44643L,44644L,44645L,44646L,44647L,44648L,44649L,44650L,44651L,44652L,
-44653L,44654L,44655L,44656L,44657L,44658L,44659L,44660L,44661L,44662L,
-44663L,44664L,44665L,44666L,44667L,44668L,44669L,44670L,44671L,44672L,
-44673L,44674L,44675L,44676L,44677L,44678L,44679L,44680L,44681L,44682L,
-44683L,44684L,44685L,44686L,44687L,44688L,44689L,44690L,44691L,44692L,
-44693L,44694L,44695L,44696L,44697L,44698L,44699L,44700L,44701L,44702L,
-44703L,44704L,44705L,44706L,44707L,44708L,44709L,44710L,44711L,44712L,
-44713L,44714L,44715L,44716L,44717L,44718L,44719L,44720L,44721L,44722L,
-44723L,44724L,44725L,44726L,44727L,44728L,44729L,44730L,44731L,44732L,
-44733L,44734L,44735L,44736L,44737L,44738L,44739L,44740L,44741L,44742L,
-44743L,44744L,44745L,44746L,44747L,44748L,44749L,44750L,44751L,44752L,
-44753L,44754L,44755L,44756L,44757L,44758L,44759L,44760L,44761L,44762L,
-44763L,44764L,44765L,44766L,44767L,44768L,44769L,44770L,44771L,44772L,
-44773L,44774L,44775L,44776L,44777L,44778L,44779L,44780L,44781L,44782L,
-44783L,44784L,44785L,44786L,44787L,44788L,44789L,44790L,44791L,44792L,
-44793L,44794L,44795L,44796L,44797L,44798L,44799L,44800L,44801L,44802L,
-44803L,44804L,44805L,44806L,44807L,44808L,44809L,44810L,44811L,44812L,
-44813L,44814L,44815L,44816L,44817L,44818L,44819L,44820L,44821L,44822L,
-44823L,44824L,44825L,44826L,44827L,44828L,44829L,44830L,44831L,44832L,
-44833L,44834L,44835L,44836L,44837L,44838L,44839L,44840L,44841L,44842L,
-44843L,44844L,44845L,44846L,44847L,44848L,44849L,44850L,44851L,44852L,
-44853L,44854L,44855L,44856L,44857L,44858L,44859L,44860L,44861L,44862L,
-44863L,44864L,44865L,44866L,44867L,44868L,44869L,44870L,44871L,44872L,
-44873L,44874L,44875L,44876L,44877L,44878L,44879L,44880L,44881L,44882L,
-44883L,44884L,44885L,44886L,44887L,44888L,44889L,44890L,44891L,44892L,
-44893L,44894L,44895L,44896L,44897L,44898L,44899L,44900L,44901L,44902L,
-44903L,44904L,44905L,44906L,44907L,44908L,44909L,44910L,44911L,44912L,
-44913L,44914L,44915L,44916L,44917L,44918L,44919L,44920L,44921L,44922L,
-44923L,44924L,44925L,44926L,44927L,44928L,44929L,44930L,44931L,44932L,
-44933L,44934L,44935L,44936L,44937L,44938L,44939L,44940L,44941L,44942L,
-44943L,44944L,44945L,44946L,44947L,44948L,44949L,44950L,44951L,44952L,
-44953L,44954L,44955L,44956L,44957L,44958L,44959L,44960L,44961L,44962L,
-44963L,44964L,44965L,44966L,44967L,44968L,44969L,44970L,44971L,44972L,
-44973L,44974L,44975L,44976L,44977L,44978L,44979L,44980L,44981L,44982L,
-44983L,44984L,44985L,44986L,44987L,44988L,44989L,44990L,44991L,44992L,
-44993L,44994L,44995L,44996L,44997L,44998L,44999L,45000L,45001L,45002L,
-45003L,45004L,45005L,45006L,45007L,45008L,45009L,45010L,45011L,45012L,
-45013L,45014L,45015L,45016L,45017L,45018L,45019L,45020L,45021L,45022L,
-45023L,45024L,45025L,45026L,45027L,45028L,45029L,45030L,45031L,45032L,
-45033L,45034L,45035L,45036L,45037L,45038L,45039L,45040L,45041L,45042L,
-45043L,45044L,45045L,45046L,45047L,45048L,45049L,45050L,45051L,45052L,
-45053L,45054L,45055L,45056L,45057L,45058L,45059L,45060L,45061L,45062L,
-45063L,45064L,45065L,45066L,45067L,45068L,45069L,45070L,45071L,45072L,
-45073L,45074L,45075L,45076L,45077L,45078L,45079L,45080L,45081L,45082L,
-45083L,45084L,45085L,45086L,45087L,45088L,45089L,45090L,45091L,45092L,
-45093L,45094L,45095L,45096L,45097L,45098L,45099L,45100L,45101L,45102L,
-45103L,45104L,45105L,45106L,45107L,45108L,45109L,45110L,45111L,45112L,
-45113L,45114L,45115L,45116L,45117L,45118L,45119L,45120L,45121L,45122L,
-45123L,45124L,45125L,45126L,45127L,45128L,45129L,45130L,45131L,45132L,
-45133L,45134L,45135L,45136L,45137L,45138L,45139L,45140L,45141L,45142L,
-45143L,45144L,45145L,45146L,45147L,45148L,45149L,45150L,45151L,45152L,
-45153L,45154L,45155L,45156L,45157L,45158L,45159L,45160L,45161L,45162L,
-45163L,45164L,45165L,45166L,45167L,45168L,45169L,45170L,45171L,45172L,
-45173L,45174L,45175L,45176L,45177L,45178L,45179L,45180L,45181L,45182L,
-45183L,45184L,45185L,45186L,45187L,45188L,45189L,45190L,45191L,45192L,
-45193L,45194L,45195L,45196L,45197L,45198L,45199L,45200L,45201L,45202L,
-45203L,45204L,45205L,45206L,45207L,45208L,45209L,45210L,45211L,45212L,
-45213L,45214L,45215L,45216L,45217L,45218L,45219L,45220L,45221L,45222L,
-45223L,45224L,45225L,45226L,45227L,45228L,45229L,45230L,45231L,45232L,
-45233L,45234L,45235L,45236L,45237L,45238L,45239L,45240L,45241L,45242L,
-45243L,45244L,45245L,45246L,45247L,45248L,45249L,45250L,45251L,45252L,
-45253L,45254L,45255L,45256L,45257L,45258L,45259L,45260L,45261L,45262L,
-45263L,45264L,45265L,45266L,45267L,45268L,45269L,45270L,45271L,45272L,
-45273L,45274L,45275L,45276L,45277L,45278L,45279L,45280L,45281L,45282L,
-45283L,45284L,45285L,45286L,45287L,45288L,45289L,45290L,45291L,45292L,
-45293L,45294L,45295L,45296L,45297L,45298L,45299L,45300L,45301L,45302L,
-45303L,45304L,45305L,45306L,45307L,45308L,45309L,45310L,45311L,45312L,
-45313L,45314L,45315L,45316L,45317L,45318L,45319L,45320L,45321L,45322L,
-45323L,45324L,45325L,45326L,45327L,45328L,45329L,45330L,45331L,45332L,
-45333L,45334L,45335L,45336L,45337L,45338L,45339L,45340L,45341L,45342L,
-45343L,45344L,45345L,45346L,45347L,45348L,45349L,45350L,45351L,45352L,
-45353L,45354L,45355L,45356L,45357L,45358L,45359L,45360L,45361L,45362L,
-45363L,45364L,45365L,45366L,45367L,45368L,45369L,45370L,45371L,45372L,
-45373L,45374L,45375L,45376L,45377L,45378L,45379L,45380L,45381L,45382L,
-45383L,45384L,45385L,45386L,45387L,45388L,45389L,45390L,45391L,45392L,
-45393L,45394L,45395L,45396L,45397L,45398L,45399L,45400L,45401L,45402L,
-45403L,45404L,45405L,45406L,45407L,45408L,45409L,45410L,45411L,45412L,
-45413L,45414L,45415L,45416L,45417L,45418L,45419L,45420L,45421L,45422L,
-45423L,45424L,45425L,45426L,45427L,45428L,45429L,45430L,45431L,45432L,
-45433L,45434L,45435L,45436L,45437L,45438L,45439L,45440L,45441L,45442L,
-45443L,45444L,45445L,45446L,45447L,45448L,45449L,45450L,45451L,45452L,
-45453L,45454L,45455L,45456L,45457L,45458L,45459L,45460L,45461L,45462L,
-45463L,45464L,45465L,45466L,45467L,45468L,45469L,45470L,45471L,45472L,
-45473L,45474L,45475L,45476L,45477L,45478L,45479L,45480L,45481L,45482L,
-45483L,45484L,45485L,45486L,45487L,45488L,45489L,45490L,45491L,45492L,
-45493L,45494L,45495L,45496L,45497L,45498L,45499L,45500L,45501L,45502L,
-45503L,45504L,45505L,45506L,45507L,45508L,45509L,45510L,45511L,45512L,
-45513L,45514L,45515L,45516L,45517L,45518L,45519L,45520L,45521L,45522L,
-45523L,45524L,45525L,45526L,45527L,45528L,45529L,45530L,45531L,45532L,
-45533L,45534L,45535L,45536L,45537L,45538L,45539L,45540L,45541L,45542L,
-45543L,45544L,45545L,45546L,45547L,45548L,45549L,45550L,45551L,45552L,
-45553L,45554L,45555L,45556L,45557L,45558L,45559L,45560L,45561L,45562L,
-45563L,45564L,45565L,45566L,45567L,45568L,45569L,45570L,45571L,45572L,
-45573L,45574L,45575L,45576L,45577L,45578L,45579L,45580L,45581L,45582L,
-45583L,45584L,45585L,45586L,45587L,45588L,45589L,45590L,45591L,45592L,
-45593L,45594L,45595L,45596L,45597L,45598L,45599L,45600L,45601L,45602L,
-45603L,45604L,45605L,45606L,45607L,45608L,45609L,45610L,45611L,45612L,
-45613L,45614L,45615L,45616L,45617L,45618L,45619L,45620L,45621L,45622L,
-45623L,45624L,45625L,45626L,45627L,45628L,45629L,45630L,45631L,45632L,
-45633L,45634L,45635L,45636L,45637L,45638L,45639L,45640L,45641L,45642L,
-45643L,45644L,45645L,45646L,45647L,45648L,45649L,45650L,45651L,45652L,
-45653L,45654L,45655L,45656L,45657L,45658L,45659L,45660L,45661L,45662L,
-45663L,45664L,45665L,45666L,45667L,45668L,45669L,45670L,45671L,45672L,
-45673L,45674L,45675L,45676L,45677L,45678L,45679L,45680L,45681L,45682L,
-45683L,45684L,45685L,45686L,45687L,45688L,45689L,45690L,45691L,45692L,
-45693L,45694L,45695L,45696L,45697L,45698L,45699L,45700L,45701L,45702L,
-45703L,45704L,45705L,45706L,45707L,45708L,45709L,45710L,45711L,45712L,
-45713L,45714L,45715L,45716L,45717L,45718L,45719L,45720L,45721L,45722L,
-45723L,45724L,45725L,45726L,45727L,45728L,45729L,45730L,45731L,45732L,
-45733L,45734L,45735L,45736L,45737L,45738L,45739L,45740L,45741L,45742L,
-45743L,45744L,45745L,45746L,45747L,45748L,45749L,45750L,45751L,45752L,
-45753L,45754L,45755L,45756L,45757L,45758L,45759L,45760L,45761L,45762L,
-45763L,45764L,45765L,45766L,45767L,45768L,45769L,45770L,45771L,45772L,
-45773L,45774L,45775L,45776L,45777L,45778L,45779L,45780L,45781L,45782L,
-45783L,45784L,45785L,45786L,45787L,45788L,45789L,45790L,45791L,45792L,
-45793L,45794L,45795L,45796L,45797L,45798L,45799L,45800L,45801L,45802L,
-45803L,45804L,45805L,45806L,45807L,45808L,45809L,45810L,45811L,45812L,
-45813L,45814L,45815L,45816L,45817L,45818L,45819L,45820L,45821L,45822L,
-45823L,45824L,45825L,45826L,45827L,45828L,45829L,45830L,45831L,45832L,
-45833L,45834L,45835L,45836L,45837L,45838L,45839L,45840L,45841L,45842L,
-45843L,45844L,45845L,45846L,45847L,45848L,45849L,45850L,45851L,45852L,
-45853L,45854L,45855L,45856L,45857L,45858L,45859L,45860L,45861L,45862L,
-45863L,45864L,45865L,45866L,45867L,45868L,45869L,45870L,45871L,45872L,
-45873L,45874L,45875L,45876L,45877L,45878L,45879L,45880L,45881L,45882L,
-45883L,45884L,45885L,45886L,45887L,45888L,45889L,45890L,45891L,45892L,
-45893L,45894L,45895L,45896L,45897L,45898L,45899L,45900L,45901L,45902L,
-45903L,45904L,45905L,45906L,45907L,45908L,45909L,45910L,45911L,45912L,
-45913L,45914L,45915L,45916L,45917L,45918L,45919L,45920L,45921L,45922L,
-45923L,45924L,45925L,45926L,45927L,45928L,45929L,45930L,45931L,45932L,
-45933L,45934L,45935L,45936L,45937L,45938L,45939L,45940L,45941L,45942L,
-45943L,45944L,45945L,45946L,45947L,45948L,45949L,45950L,45951L,45952L,
-45953L,45954L,45955L,45956L,45957L,45958L,45959L,45960L,45961L,45962L,
-45963L,45964L,45965L,45966L,45967L,45968L,45969L,45970L,45971L,45972L,
-45973L,45974L,45975L,45976L,45977L,45978L,45979L,45980L,45981L,45982L,
-45983L,45984L,45985L,45986L,45987L,45988L,45989L,45990L,45991L,45992L,
-45993L,45994L,45995L,45996L,45997L,45998L,45999L,46000L,46001L,46002L,
-46003L,46004L,46005L,46006L,46007L,46008L,46009L,46010L,46011L,46012L,
-46013L,46014L,46015L,46016L,46017L,46018L,46019L,46020L,46021L,46022L,
-46023L,46024L,46025L,46026L,46027L,46028L,46029L,46030L,46031L,46032L,
-46033L,46034L,46035L,46036L,46037L,46038L,46039L,46040L,46041L,46042L,
-46043L,46044L,46045L,46046L,46047L,46048L,46049L,46050L,46051L,46052L,
-46053L,46054L,46055L,46056L,46057L,46058L,46059L,46060L,46061L,46062L,
-46063L,46064L,46065L,46066L,46067L,46068L,46069L,46070L,46071L,46072L,
-46073L,46074L,46075L,46076L,46077L,46078L,46079L,46080L,46081L,46082L,
-46083L,46084L,46085L,46086L,46087L,46088L,46089L,46090L,46091L,46092L,
-46093L,46094L,46095L,46096L,46097L,46098L,46099L,46100L,46101L,46102L,
-46103L,46104L,46105L,46106L,46107L,46108L,46109L,46110L,46111L,46112L,
-46113L,46114L,46115L,46116L,46117L,46118L,46119L,46120L,46121L,46122L,
-46123L,46124L,46125L,46126L,46127L,46128L,46129L,46130L,46131L,46132L,
-46133L,46134L,46135L,46136L,46137L,46138L,46139L,46140L,46141L,46142L,
-46143L,46144L,46145L,46146L,46147L,46148L,46149L,46150L,46151L,46152L,
-46153L,46154L,46155L,46156L,46157L,46158L,46159L,46160L,46161L,46162L,
-46163L,46164L,46165L,46166L,46167L,46168L,46169L,46170L,46171L,46172L,
-46173L,46174L,46175L,46176L,46177L,46178L,46179L,46180L,46181L,46182L,
-46183L,46184L,46185L,46186L,46187L,46188L,46189L,46190L,46191L,46192L,
-46193L,46194L,46195L,46196L,46197L,46198L,46199L,46200L,46201L,46202L,
-46203L,46204L,46205L,46206L,46207L,46208L,46209L,46210L,46211L,46212L,
-46213L,46214L,46215L,46216L,46217L,46218L,46219L,46220L,46221L,46222L,
-46223L,46224L,46225L,46226L,46227L,46228L,46229L,46230L,46231L,46232L,
-46233L,46234L,46235L,46236L,46237L,46238L,46239L,46240L,46241L,46242L,
-46243L,46244L,46245L,46246L,46247L,46248L,46249L,46250L,46251L,46252L,
-46253L,46254L,46255L,46256L,46257L,46258L,46259L,46260L,46261L,46262L,
-46263L,46264L,46265L,46266L,46267L,46268L,46269L,46270L,46271L,46272L,
-46273L,46274L,46275L,46276L,46277L,46278L,46279L,46280L,46281L,46282L,
-46283L,46284L,46285L,46286L,46287L,46288L,46289L,46290L,46291L,46292L,
-46293L,46294L,46295L,46296L,46297L,46298L,46299L,46300L,46301L,46302L,
-46303L,46304L,46305L,46306L,46307L,46308L,46309L,46310L,46311L,46312L,
-46313L,46314L,46315L,46316L,46317L,46318L,46319L,46320L,46321L,46322L,
-46323L,46324L,46325L,46326L,46327L,46328L,46329L,46330L,46331L,46332L,
-46333L,46334L,46335L,46336L,46337L,46338L,46339L,46340L,46341L,46342L,
-46343L,46344L,46345L,46346L,46347L,46348L,46349L,46350L,46351L,46352L,
-46353L,46354L,46355L,46356L,46357L,46358L,46359L,46360L,46361L,46362L,
-46363L,46364L,46365L,46366L,46367L,46368L,46369L,46370L,46371L,46372L,
-46373L,46374L,46375L,46376L,46377L,46378L,46379L,46380L,46381L,46382L,
-46383L,46384L,46385L,46386L,46387L,46388L,46389L,46390L,46391L,46392L,
-46393L,46394L,46395L,46396L,46397L,46398L,46399L,46400L,46401L,46402L,
-46403L,46404L,46405L,46406L,46407L,46408L,46409L,46410L,46411L,46412L,
-46413L,46414L,46415L,46416L,46417L,46418L,46419L,46420L,46421L,46422L,
-46423L,46424L,46425L,46426L,46427L,46428L,46429L,46430L,46431L,46432L,
-46433L,46434L,46435L,46436L,46437L,46438L,46439L,46440L,46441L,46442L,
-46443L,46444L,46445L,46446L,46447L,46448L,46449L,46450L,46451L,46452L,
-46453L,46454L,46455L,46456L,46457L,46458L,46459L,46460L,46461L,46462L,
-46463L,46464L,46465L,46466L,46467L,46468L,46469L,46470L,46471L,46472L,
-46473L,46474L,46475L,46476L,46477L,46478L,46479L,46480L,46481L,46482L,
-46483L,46484L,46485L,46486L,46487L,46488L,46489L,46490L,46491L,46492L,
-46493L,46494L,46495L,46496L,46497L,46498L,46499L,46500L,46501L,46502L,
-46503L,46504L,46505L,46506L,46507L,46508L,46509L,46510L,46511L,46512L,
-46513L,46514L,46515L,46516L,46517L,46518L,46519L,46520L,46521L,46522L,
-46523L,46524L,46525L,46526L,46527L,46528L,46529L,46530L,46531L,46532L,
-46533L,46534L,46535L,46536L,46537L,46538L,46539L,46540L,46541L,46542L,
-46543L,46544L,46545L,46546L,46547L,46548L,46549L,46550L,46551L,46552L,
-46553L,46554L,46555L,46556L,46557L,46558L,46559L,46560L,46561L,46562L,
-46563L,46564L,46565L,46566L,46567L,46568L,46569L,46570L,46571L,46572L,
-46573L,46574L,46575L,46576L,46577L,46578L,46579L,46580L,46581L,46582L,
-46583L,46584L,46585L,46586L,46587L,46588L,46589L,46590L,46591L,46592L,
-46593L,46594L,46595L,46596L,46597L,46598L,46599L,46600L,46601L,46602L,
-46603L,46604L,46605L,46606L,46607L,46608L,46609L,46610L,46611L,46612L,
-46613L,46614L,46615L,46616L,46617L,46618L,46619L,46620L,46621L,46622L,
-46623L,46624L,46625L,46626L,46627L,46628L,46629L,46630L,46631L,46632L,
-46633L,46634L,46635L,46636L,46637L,46638L,46639L,46640L,46641L,46642L,
-46643L,46644L,46645L,46646L,46647L,46648L,46649L,46650L,46651L,46652L,
-46653L,46654L,46655L,46656L,46657L,46658L,46659L,46660L,46661L,46662L,
-46663L,46664L,46665L,46666L,46667L,46668L,46669L,46670L,46671L,46672L,
-46673L,46674L,46675L,46676L,46677L,46678L,46679L,46680L,46681L,46682L,
-46683L,46684L,46685L,46686L,46687L,46688L,46689L,46690L,46691L,46692L,
-46693L,46694L,46695L,46696L,46697L,46698L,46699L,46700L,46701L,46702L,
-46703L,46704L,46705L,46706L,46707L,46708L,46709L,46710L,46711L,46712L,
-46713L,46714L,46715L,46716L,46717L,46718L,46719L,46720L,46721L,46722L,
-46723L,46724L,46725L,46726L,46727L,46728L,46729L,46730L,46731L,46732L,
-46733L,46734L,46735L,46736L,46737L,46738L,46739L,46740L,46741L,46742L,
-46743L,46744L,46745L,46746L,46747L,46748L,46749L,46750L,46751L,46752L,
-46753L,46754L,46755L,46756L,46757L,46758L,46759L,46760L,46761L,46762L,
-46763L,46764L,46765L,46766L,46767L,46768L,46769L,46770L,46771L,46772L,
-46773L,46774L,46775L,46776L,46777L,46778L,46779L,46780L,46781L,46782L,
-46783L,46784L,46785L,46786L,46787L,46788L,46789L,46790L,46791L,46792L,
-46793L,46794L,46795L,46796L,46797L,46798L,46799L,46800L,46801L,46802L,
-46803L,46804L,46805L,46806L,46807L,46808L,46809L,46810L,46811L,46812L,
-46813L,46814L,46815L,46816L,46817L,46818L,46819L,46820L,46821L,46822L,
-46823L,46824L,46825L,46826L,46827L,46828L,46829L,46830L,46831L,46832L,
-46833L,46834L,46835L,46836L,46837L,46838L,46839L,46840L,46841L,46842L,
-46843L,46844L,46845L,46846L,46847L,46848L,46849L,46850L,46851L,46852L,
-46853L,46854L,46855L,46856L,46857L,46858L,46859L,46860L,46861L,46862L,
-46863L,46864L,46865L,46866L,46867L,46868L,46869L,46870L,46871L,46872L,
-46873L,46874L,46875L,46876L,46877L,46878L,46879L,46880L,46881L,46882L,
-46883L,46884L,46885L,46886L,46887L,46888L,46889L,46890L,46891L,46892L,
-46893L,46894L,46895L,46896L,46897L,46898L,46899L,46900L,46901L,46902L,
-46903L,46904L,46905L,46906L,46907L,46908L,46909L,46910L,46911L,46912L,
-46913L,46914L,46915L,46916L,46917L,46918L,46919L,46920L,46921L,46922L,
-46923L,46924L,46925L,46926L,46927L,46928L,46929L,46930L,46931L,46932L,
-46933L,46934L,46935L,46936L,46937L,46938L,46939L,46940L,46941L,46942L,
-46943L,46944L,46945L,46946L,46947L,46948L,46949L,46950L,46951L,46952L,
-46953L,46954L,46955L,46956L,46957L,46958L,46959L,46960L,46961L,46962L,
-46963L,46964L,46965L,46966L,46967L,46968L,46969L,46970L,46971L,46972L,
-46973L,46974L,46975L,46976L,46977L,46978L,46979L,46980L,46981L,46982L,
-46983L,46984L,46985L,46986L,46987L,46988L,46989L,46990L,46991L,46992L,
-46993L,46994L,46995L,46996L,46997L,46998L,46999L,47000L,47001L,47002L,
-47003L,47004L,47005L,47006L,47007L,47008L,47009L,47010L,47011L,47012L,
-47013L,47014L,47015L,47016L,47017L,47018L,47019L,47020L,47021L,47022L,
-47023L,47024L,47025L,47026L,47027L,47028L,47029L,47030L,47031L,47032L,
-47033L,47034L,47035L,47036L,47037L,47038L,47039L,47040L,47041L,47042L,
-47043L,47044L,47045L,47046L,47047L,47048L,47049L,47050L,47051L,47052L,
-47053L,47054L,47055L,47056L,47057L,47058L,47059L,47060L,47061L,47062L,
-47063L,47064L,47065L,47066L,47067L,47068L,47069L,47070L,47071L,47072L,
-47073L,47074L,47075L,47076L,47077L,47078L,47079L,47080L,47081L,47082L,
-47083L,47084L,47085L,47086L,47087L,47088L,47089L,47090L,47091L,47092L,
-47093L,47094L,47095L,47096L,47097L,47098L,47099L,47100L,47101L,47102L,
-47103L,47104L,47105L,47106L,47107L,47108L,47109L,47110L,47111L,47112L,
-47113L,47114L,47115L,47116L,47117L,47118L,47119L,47120L,47121L,47122L,
-47123L,47124L,47125L,47126L,47127L,47128L,47129L,47130L,47131L,47132L,
-47133L,47134L,47135L,47136L,47137L,47138L,47139L,47140L,47141L,47142L,
-47143L,47144L,47145L,47146L,47147L,47148L,47149L,47150L,47151L,47152L,
-47153L,47154L,47155L,47156L,47157L,47158L,47159L,47160L,47161L,47162L,
-47163L,47164L,47165L,47166L,47167L,47168L,47169L,47170L,47171L,47172L,
-47173L,47174L,47175L,47176L,47177L,47178L,47179L,47180L,47181L,47182L,
-47183L,47184L,47185L,47186L,47187L,47188L,47189L,47190L,47191L,47192L,
-47193L,47194L,47195L,47196L,47197L,47198L,47199L,47200L,47201L,47202L,
-47203L,47204L,47205L,47206L,47207L,47208L,47209L,47210L,47211L,47212L,
-47213L,47214L,47215L,47216L,47217L,47218L,47219L,47220L,47221L,47222L,
-47223L,47224L,47225L,47226L,47227L,47228L,47229L,47230L,47231L,47232L,
-47233L,47234L,47235L,47236L,47237L,47238L,47239L,47240L,47241L,47242L,
-47243L,47244L,47245L,47246L,47247L,47248L,47249L,47250L,47251L,47252L,
-47253L,47254L,47255L,47256L,47257L,47258L,47259L,47260L,47261L,47262L,
-47263L,47264L,47265L,47266L,47267L,47268L,47269L,47270L,47271L,47272L,
-47273L,47274L,47275L,47276L,47277L,47278L,47279L,47280L,47281L,47282L,
-47283L,47284L,47285L,47286L,47287L,47288L,47289L,47290L,47291L,47292L,
-47293L,47294L,47295L,47296L,47297L,47298L,47299L,47300L,47301L,47302L,
-47303L,47304L,47305L,47306L,47307L,47308L,47309L,47310L,47311L,47312L,
-47313L,47314L,47315L,47316L,47317L,47318L,47319L,47320L,47321L,47322L,
-47323L,47324L,47325L,47326L,47327L,47328L,47329L,47330L,47331L,47332L,
-47333L,47334L,47335L,47336L,47337L,47338L,47339L,47340L,47341L,47342L,
-47343L,47344L,47345L,47346L,47347L,47348L,47349L,47350L,47351L,47352L,
-47353L,47354L,47355L,47356L,47357L,47358L,47359L,47360L,47361L,47362L,
-47363L,47364L,47365L,47366L,47367L,47368L,47369L,47370L,47371L,47372L,
-47373L,47374L,47375L,47376L,47377L,47378L,47379L,47380L,47381L,47382L,
-47383L,47384L,47385L,47386L,47387L,47388L,47389L,47390L,47391L,47392L,
-47393L,47394L,47395L,47396L,47397L,47398L,47399L,47400L,47401L,47402L,
-47403L,47404L,47405L,47406L,47407L,47408L,47409L,47410L,47411L,47412L,
-47413L,47414L,47415L,47416L,47417L,47418L,47419L,47420L,47421L,47422L,
-47423L,47424L,47425L,47426L,47427L,47428L,47429L,47430L,47431L,47432L,
-47433L,47434L,47435L,47436L,47437L,47438L,47439L,47440L,47441L,47442L,
-47443L,47444L,47445L,47446L,47447L,47448L,47449L,47450L,47451L,47452L,
-47453L,47454L,47455L,47456L,47457L,47458L,47459L,47460L,47461L,47462L,
-47463L,47464L,47465L,47466L,47467L,47468L,47469L,47470L,47471L,47472L,
-47473L,47474L,47475L,47476L,47477L,47478L,47479L,47480L,47481L,47482L,
-47483L,47484L,47485L,47486L,47487L,47488L,47489L,47490L,47491L,47492L,
-47493L,47494L,47495L,47496L,47497L,47498L,47499L,47500L,47501L,47502L,
-47503L,47504L,47505L,47506L,47507L,47508L,47509L,47510L,47511L,47512L,
-47513L,47514L,47515L,47516L,47517L,47518L,47519L,47520L,47521L,47522L,
-47523L,47524L,47525L,47526L,47527L,47528L,47529L,47530L,47531L,47532L,
-47533L,47534L,47535L,47536L,47537L,47538L,47539L,47540L,47541L,47542L,
-47543L,47544L,47545L,47546L,47547L,47548L,47549L,47550L,47551L,47552L,
-47553L,47554L,47555L,47556L,47557L,47558L,47559L,47560L,47561L,47562L,
-47563L,47564L,47565L,47566L,47567L,47568L,47569L,47570L,47571L,47572L,
-47573L,47574L,47575L,47576L,47577L,47578L,47579L,47580L,47581L,47582L,
-47583L,47584L,47585L,47586L,47587L,47588L,47589L,47590L,47591L,47592L,
-47593L,47594L,47595L,47596L,47597L,47598L,47599L,47600L,47601L,47602L,
-47603L,47604L,47605L,47606L,47607L,47608L,47609L,47610L,47611L,47612L,
-47613L,47614L,47615L,47616L,47617L,47618L,47619L,47620L,47621L,47622L,
-47623L,47624L,47625L,47626L,47627L,47628L,47629L,47630L,47631L,47632L,
-47633L,47634L,47635L,47636L,47637L,47638L,47639L,47640L,47641L,47642L,
-47643L,47644L,47645L,47646L,47647L,47648L,47649L,47650L,47651L,47652L,
-47653L,47654L,47655L,47656L,47657L,47658L,47659L,47660L,47661L,47662L,
-47663L,47664L,47665L,47666L,47667L,47668L,47669L,47670L,47671L,47672L,
-47673L,47674L,47675L,47676L,47677L,47678L,47679L,47680L,47681L,47682L,
-47683L,47684L,47685L,47686L,47687L,47688L,47689L,47690L,47691L,47692L,
-47693L,47694L,47695L,47696L,47697L,47698L,47699L,47700L,47701L,47702L,
-47703L,47704L,47705L,47706L,47707L,47708L,47709L,47710L,47711L,47712L,
-47713L,47714L,47715L,47716L,47717L,47718L,47719L,47720L,47721L,47722L,
-47723L,47724L,47725L,47726L,47727L,47728L,47729L,47730L,47731L,47732L,
-47733L,47734L,47735L,47736L,47737L,47738L,47739L,47740L,47741L,47742L,
-47743L,47744L,47745L,47746L,47747L,47748L,47749L,47750L,47751L,47752L,
-47753L,47754L,47755L,47756L,47757L,47758L,47759L,47760L,47761L,47762L,
-47763L,47764L,47765L,47766L,47767L,47768L,47769L,47770L,47771L,47772L,
-47773L,47774L,47775L,47776L,47777L,47778L,47779L,47780L,47781L,47782L,
-47783L,47784L,47785L,47786L,47787L,47788L,47789L,47790L,47791L,47792L,
-47793L,47794L,47795L,47796L,47797L,47798L,47799L,47800L,47801L,47802L,
-47803L,47804L,47805L,47806L,47807L,47808L,47809L,47810L,47811L,47812L,
-47813L,47814L,47815L,47816L,47817L,47818L,47819L,47820L,47821L,47822L,
-47823L,47824L,47825L,47826L,47827L,47828L,47829L,47830L,47831L,47832L,
-47833L,47834L,47835L,47836L,47837L,47838L,47839L,47840L,47841L,47842L,
-47843L,47844L,47845L,47846L,47847L,47848L,47849L,47850L,47851L,47852L,
-47853L,47854L,47855L,47856L,47857L,47858L,47859L,47860L,47861L,47862L,
-47863L,47864L,47865L,47866L,47867L,47868L,47869L,47870L,47871L,47872L,
-47873L,47874L,47875L,47876L,47877L,47878L,47879L,47880L,47881L,47882L,
-47883L,47884L,47885L,47886L,47887L,47888L,47889L,47890L,47891L,47892L,
-47893L,47894L,47895L,47896L,47897L,47898L,47899L,47900L,47901L,47902L,
-47903L,47904L,47905L,47906L,47907L,47908L,47909L,47910L,47911L,47912L,
-47913L,47914L,47915L,47916L,47917L,47918L,47919L,47920L,47921L,47922L,
-47923L,47924L,47925L,47926L,47927L,47928L,47929L,47930L,47931L,47932L,
-47933L,47934L,47935L,47936L,47937L,47938L,47939L,47940L,47941L,47942L,
-47943L,47944L,47945L,47946L,47947L,47948L,47949L,47950L,47951L,47952L,
-47953L,47954L,47955L,47956L,47957L,47958L,47959L,47960L,47961L,47962L,
-47963L,47964L,47965L,47966L,47967L,47968L,47969L,47970L,47971L,47972L,
-47973L,47974L,47975L,47976L,47977L,47978L,47979L,47980L,47981L,47982L,
-47983L,47984L,47985L,47986L,47987L,47988L,47989L,47990L,47991L,47992L,
-47993L,47994L,47995L,47996L,47997L,47998L,47999L,48000L,48001L,48002L,
-48003L,48004L,48005L,48006L,48007L,48008L,48009L,48010L,48011L,48012L,
-48013L,48014L,48015L,48016L,48017L,48018L,48019L,48020L,48021L,48022L,
-48023L,48024L,48025L,48026L,48027L,48028L,48029L,48030L,48031L,48032L,
-48033L,48034L,48035L,48036L,48037L,48038L,48039L,48040L,48041L,48042L,
-48043L,48044L,48045L,48046L,48047L,48048L,48049L,48050L,48051L,48052L,
-48053L,48054L,48055L,48056L,48057L,48058L,48059L,48060L,48061L,48062L,
-48063L,48064L,48065L,48066L,48067L,48068L,48069L,48070L,48071L,48072L,
-48073L,48074L,48075L,48076L,48077L,48078L,48079L,48080L,48081L,48082L,
-48083L,48084L,48085L,48086L,48087L,48088L,48089L,48090L,48091L,48092L,
-48093L,48094L,48095L,48096L,48097L,48098L,48099L,48100L,48101L,48102L,
-48103L,48104L,48105L,48106L,48107L,48108L,48109L,48110L,48111L,48112L,
-48113L,48114L,48115L,48116L,48117L,48118L,48119L,48120L,48121L,48122L,
-48123L,48124L,48125L,48126L,48127L,48128L,48129L,48130L,48131L,48132L,
-48133L,48134L,48135L,48136L,48137L,48138L,48139L,48140L,48141L,48142L,
-48143L,48144L,48145L,48146L,48147L,48148L,48149L,48150L,48151L,48152L,
-48153L,48154L,48155L,48156L,48157L,48158L,48159L,48160L,48161L,48162L,
-48163L,48164L,48165L,48166L,48167L,48168L,48169L,48170L,48171L,48172L,
-48173L,48174L,48175L,48176L,48177L,48178L,48179L,48180L,48181L,48182L,
-48183L,48184L,48185L,48186L,48187L,48188L,48189L,48190L,48191L,48192L,
-48193L,48194L,48195L,48196L,48197L,48198L,48199L,48200L,48201L,48202L,
-48203L,48204L,48205L,48206L,48207L,48208L,48209L,48210L,48211L,48212L,
-48213L,48214L,48215L,48216L,48217L,48218L,48219L,48220L,48221L,48222L,
-48223L,48224L,48225L,48226L,48227L,48228L,48229L,48230L,48231L,48232L,
-48233L,48234L,48235L,48236L,48237L,48238L,48239L,48240L,48241L,48242L,
-48243L,48244L,48245L,48246L,48247L,48248L,48249L,48250L,48251L,48252L,
-48253L,48254L,48255L,48256L,48257L,48258L,48259L,48260L,48261L,48262L,
-48263L,48264L,48265L,48266L,48267L,48268L,48269L,48270L,48271L,48272L,
-48273L,48274L,48275L,48276L,48277L,48278L,48279L,48280L,48281L,48282L,
-48283L,48284L,48285L,48286L,48287L,48288L,48289L,48290L,48291L,48292L,
-48293L,48294L,48295L,48296L,48297L,48298L,48299L,48300L,48301L,48302L,
-48303L,48304L,48305L,48306L,48307L,48308L,48309L,48310L,48311L,48312L,
-48313L,48314L,48315L,48316L,48317L,48318L,48319L,48320L,48321L,48322L,
-48323L,48324L,48325L,48326L,48327L,48328L,48329L,48330L,48331L,48332L,
-48333L,48334L,48335L,48336L,48337L,48338L,48339L,48340L,48341L,48342L,
-48343L,48344L,48345L,48346L,48347L,48348L,48349L,48350L,48351L,48352L,
-48353L,48354L,48355L,48356L,48357L,48358L,48359L,48360L,48361L,48362L,
-48363L,48364L,48365L,48366L,48367L,48368L,48369L,48370L,48371L,48372L,
-48373L,48374L,48375L,48376L,48377L,48378L,48379L,48380L,48381L,48382L,
-48383L,48384L,48385L,48386L,48387L,48388L,48389L,48390L,48391L,48392L,
-48393L,48394L,48395L,48396L,48397L,48398L,48399L,48400L,48401L,48402L,
-48403L,48404L,48405L,48406L,48407L,48408L,48409L,48410L,48411L,48412L,
-48413L,48414L,48415L,48416L,48417L,48418L,48419L,48420L,48421L,48422L,
-48423L,48424L,48425L,48426L,48427L,48428L,48429L,48430L,48431L,48432L,
-48433L,48434L,48435L,48436L,48437L,48438L,48439L,48440L,48441L,48442L,
-48443L,48444L,48445L,48446L,48447L,48448L,48449L,48450L,48451L,48452L,
-48453L,48454L,48455L,48456L,48457L,48458L,48459L,48460L,48461L,48462L,
-48463L,48464L,48465L,48466L,48467L,48468L,48469L,48470L,48471L,48472L,
-48473L,48474L,48475L,48476L,48477L,48478L,48479L,48480L,48481L,48482L,
-48483L,48484L,48485L,48486L,48487L,48488L,48489L,48490L,48491L,48492L,
-48493L,48494L,48495L,48496L,48497L,48498L,48499L,48500L,48501L,48502L,
-48503L,48504L,48505L,48506L,48507L,48508L,48509L,48510L,48511L,48512L,
-48513L,48514L,48515L,48516L,48517L,48518L,48519L,48520L,48521L,48522L,
-48523L,48524L,48525L,48526L,48527L,48528L,48529L,48530L,48531L,48532L,
-48533L,48534L,48535L,48536L,48537L,48538L,48539L,48540L,48541L,48542L,
-48543L,48544L,48545L,48546L,48547L,48548L,48549L,48550L,48551L,48552L,
-48553L,48554L,48555L,48556L,48557L,48558L,48559L,48560L,48561L,48562L,
-48563L,48564L,48565L,48566L,48567L,48568L,48569L,48570L,48571L,48572L,
-48573L,48574L,48575L,48576L,48577L,48578L,48579L,48580L,48581L,48582L,
-48583L,48584L,48585L,48586L,48587L,48588L,48589L,48590L,48591L,48592L,
-48593L,48594L,48595L,48596L,48597L,48598L,48599L,48600L,48601L,48602L,
-48603L,48604L,48605L,48606L,48607L,48608L,48609L,48610L,48611L,48612L,
-48613L,48614L,48615L,48616L,48617L,48618L,48619L,48620L,48621L,48622L,
-48623L,48624L,48625L,48626L,48627L,48628L,48629L,48630L,48631L,48632L,
-48633L,48634L,48635L,48636L,48637L,48638L,48639L,48640L,48641L,48642L,
-48643L,48644L,48645L,48646L,48647L,48648L,48649L,48650L,48651L,48652L,
-48653L,48654L,48655L,48656L,48657L,48658L,48659L,48660L,48661L,48662L,
-48663L,48664L,48665L,48666L,48667L,48668L,48669L,48670L,48671L,48672L,
-48673L,48674L,48675L,48676L,48677L,48678L,48679L,48680L,48681L,48682L,
-48683L,48684L,48685L,48686L,48687L,48688L,48689L,48690L,48691L,48692L,
-48693L,48694L,48695L,48696L,48697L,48698L,48699L,48700L,48701L,48702L,
-48703L,48704L,48705L,48706L,48707L,48708L,48709L,48710L,48711L,48712L,
-48713L,48714L,48715L,48716L,48717L,48718L,48719L,48720L,48721L,48722L,
-48723L,48724L,48725L,48726L,48727L,48728L,48729L,48730L,48731L,48732L,
-48733L,48734L,48735L,48736L,48737L,48738L,48739L,48740L,48741L,48742L,
-48743L,48744L,48745L,48746L,48747L,48748L,48749L,48750L,48751L,48752L,
-48753L,48754L,48755L,48756L,48757L,48758L,48759L,48760L,48761L,48762L,
-48763L,48764L,48765L,48766L,48767L,48768L,48769L,48770L,48771L,48772L,
-48773L,48774L,48775L,48776L,48777L,48778L,48779L,48780L,48781L,48782L,
-48783L,48784L,48785L,48786L,48787L,48788L,48789L,48790L,48791L,48792L,
-48793L,48794L,48795L,48796L,48797L,48798L,48799L,48800L,48801L,48802L,
-48803L,48804L,48805L,48806L,48807L,48808L,48809L,48810L,48811L,48812L,
-48813L,48814L,48815L,48816L,48817L,48818L,48819L,48820L,48821L,48822L,
-48823L,48824L,48825L,48826L,48827L,48828L,48829L,48830L,48831L,48832L,
-48833L,48834L,48835L,48836L,48837L,48838L,48839L,48840L,48841L,48842L,
-48843L,48844L,48845L,48846L,48847L,48848L,48849L,48850L,48851L,48852L,
-48853L,48854L,48855L,48856L,48857L,48858L,48859L,48860L,48861L,48862L,
-48863L,48864L,48865L,48866L,48867L,48868L,48869L,48870L,48871L,48872L,
-48873L,48874L,48875L,48876L,48877L,48878L,48879L,48880L,48881L,48882L,
-48883L,48884L,48885L,48886L,48887L,48888L,48889L,48890L,48891L,48892L,
-48893L,48894L,48895L,48896L,48897L,48898L,48899L,48900L,48901L,48902L,
-48903L,48904L,48905L,48906L,48907L,48908L,48909L,48910L,48911L,48912L,
-48913L,48914L,48915L,48916L,48917L,48918L,48919L,48920L,48921L,48922L,
-48923L,48924L,48925L,48926L,48927L,48928L,48929L,48930L,48931L,48932L,
-48933L,48934L,48935L,48936L,48937L,48938L,48939L,48940L,48941L,48942L,
-48943L,48944L,48945L,48946L,48947L,48948L,48949L,48950L,48951L,48952L,
-48953L,48954L,48955L,48956L,48957L,48958L,48959L,48960L,48961L,48962L,
-48963L,48964L,48965L,48966L,48967L,48968L,48969L,48970L,48971L,48972L,
-48973L,48974L,48975L,48976L,48977L,48978L,48979L,48980L,48981L,48982L,
-48983L,48984L,48985L,48986L,48987L,48988L,48989L,48990L,48991L,48992L,
-48993L,48994L,48995L,48996L,48997L,48998L,48999L,49000L,49001L,49002L,
-49003L,49004L,49005L,49006L,49007L,49008L,49009L,49010L,49011L,49012L,
-49013L,49014L,49015L,49016L,49017L,49018L,49019L,49020L,49021L,49022L,
-49023L,49024L,49025L,49026L,49027L,49028L,49029L,49030L,49031L,49032L,
-49033L,49034L,49035L,49036L,49037L,49038L,49039L,49040L,49041L,49042L,
-49043L,49044L,49045L,49046L,49047L,49048L,49049L,49050L,49051L,49052L,
-49053L,49054L,49055L,49056L,49057L,49058L,49059L,49060L,49061L,49062L,
-49063L,49064L,49065L,49066L,49067L,49068L,49069L,49070L,49071L,49072L,
-49073L,49074L,49075L,49076L,49077L,49078L,49079L,49080L,49081L,49082L,
-49083L,49084L,49085L,49086L,49087L,49088L,49089L,49090L,49091L,49092L,
-49093L,49094L,49095L,49096L,49097L,49098L,49099L,49100L,49101L,49102L,
-49103L,49104L,49105L,49106L,49107L,49108L,49109L,49110L,49111L,49112L,
-49113L,49114L,49115L,49116L,49117L,49118L,49119L,49120L,49121L,49122L,
-49123L,49124L,49125L,49126L,49127L,49128L,49129L,49130L,49131L,49132L,
-49133L,49134L,49135L,49136L,49137L,49138L,49139L,49140L,49141L,49142L,
-49143L,49144L,49145L,49146L,49147L,49148L,49149L,49150L,49151L,49152L,
-49153L,49154L,49155L,49156L,49157L,49158L,49159L,49160L,49161L,49162L,
-49163L,49164L,49165L,49166L,49167L,49168L,49169L,49170L,49171L,49172L,
-49173L,49174L,49175L,49176L,49177L,49178L,49179L,49180L,49181L,49182L,
-49183L,49184L,49185L,49186L,49187L,49188L,49189L,49190L,49191L,49192L,
-49193L,49194L,49195L,49196L,49197L,49198L,49199L,49200L,49201L,49202L,
-49203L,49204L,49205L,49206L,49207L,49208L,49209L,49210L,49211L,49212L,
-49213L,49214L,49215L,49216L,49217L,49218L,49219L,49220L,49221L,49222L,
-49223L,49224L,49225L,49226L,49227L,49228L,49229L,49230L,49231L,49232L,
-49233L,49234L,49235L,49236L,49237L,49238L,49239L,49240L,49241L,49242L,
-49243L,49244L,49245L,49246L,49247L,49248L,49249L,49250L,49251L,49252L,
-49253L,49254L,49255L,49256L,49257L,49258L,49259L,49260L,49261L,49262L,
-49263L,49264L,49265L,49266L,49267L,49268L,49269L,49270L,49271L,49272L,
-49273L,49274L,49275L,49276L,49277L,49278L,49279L,49280L,49281L,49282L,
-49283L,49284L,49285L,49286L,49287L,49288L,49289L,49290L,49291L,49292L,
-49293L,49294L,49295L,49296L,49297L,49298L,49299L,49300L,49301L,49302L,
-49303L,49304L,49305L,49306L,49307L,49308L,49309L,49310L,49311L,49312L,
-49313L,49314L,49315L,49316L,49317L,49318L,49319L,49320L,49321L,49322L,
-49323L,49324L,49325L,49326L,49327L,49328L,49329L,49330L,49331L,49332L,
-49333L,49334L,49335L,49336L,49337L,49338L,49339L,49340L,49341L,49342L,
-49343L,49344L,49345L,49346L,49347L,49348L,49349L,49350L,49351L,49352L,
-49353L,49354L,49355L,49356L,49357L,49358L,49359L,49360L,49361L,49362L,
-49363L,49364L,49365L,49366L,49367L,49368L,49369L,49370L,49371L,49372L,
-49373L,49374L,49375L,49376L,49377L,49378L,49379L,49380L,49381L,49382L,
-49383L,49384L,49385L,49386L,49387L,49388L,49389L,49390L,49391L,49392L,
-49393L,49394L,49395L,49396L,49397L,49398L,49399L,49400L,49401L,49402L,
-49403L,49404L,49405L,49406L,49407L,49408L,49409L,49410L,49411L,49412L,
-49413L,49414L,49415L,49416L,49417L,49418L,49419L,49420L,49421L,49422L,
-49423L,49424L,49425L,49426L,49427L,49428L,49429L,49430L,49431L,49432L,
-49433L,49434L,49435L,49436L,49437L,49438L,49439L,49440L,49441L,49442L,
-49443L,49444L,49445L,49446L,49447L,49448L,49449L,49450L,49451L,49452L,
-49453L,49454L,49455L,49456L,49457L,49458L,49459L,49460L,49461L,49462L,
-49463L,49464L,49465L,49466L,49467L,49468L,49469L,49470L,49471L,49472L,
-49473L,49474L,49475L,49476L,49477L,49478L,49479L,49480L,49481L,49482L,
-49483L,49484L,49485L,49486L,49487L,49488L,49489L,49490L,49491L,49492L,
-49493L,49494L,49495L,49496L,49497L,49498L,49499L,49500L,49501L,49502L,
-49503L,49504L,49505L,49506L,49507L,49508L,49509L,49510L,49511L,49512L,
-49513L,49514L,49515L,49516L,49517L,49518L,49519L,49520L,49521L,49522L,
-49523L,49524L,49525L,49526L,49527L,49528L,49529L,49530L,49531L,49532L,
-49533L,49534L,49535L,49536L,49537L,49538L,49539L,49540L,49541L,49542L,
-49543L,49544L,49545L,49546L,49547L,49548L,49549L,49550L,49551L,49552L,
-49553L,49554L,49555L,49556L,49557L,49558L,49559L,49560L,49561L,49562L,
-49563L,49564L,49565L,49566L,49567L,49568L,49569L,49570L,49571L,49572L,
-49573L,49574L,49575L,49576L,49577L,49578L,49579L,49580L,49581L,49582L,
-49583L,49584L,49585L,49586L,49587L,49588L,49589L,49590L,49591L,49592L,
-49593L,49594L,49595L,49596L,49597L,49598L,49599L,49600L,49601L,49602L,
-49603L,49604L,49605L,49606L,49607L,49608L,49609L,49610L,49611L,49612L,
-49613L,49614L,49615L,49616L,49617L,49618L,49619L,49620L,49621L,49622L,
-49623L,49624L,49625L,49626L,49627L,49628L,49629L,49630L,49631L,49632L,
-49633L,49634L,49635L,49636L,49637L,49638L,49639L,49640L,49641L,49642L,
-49643L,49644L,49645L,49646L,49647L,49648L,49649L,49650L,49651L,49652L,
-49653L,49654L,49655L,49656L,49657L,49658L,49659L,49660L,49661L,49662L,
-49663L,49664L,49665L,49666L,49667L,49668L,49669L,49670L,49671L,49672L,
-49673L,49674L,49675L,49676L,49677L,49678L,49679L,49680L,49681L,49682L,
-49683L,49684L,49685L,49686L,49687L,49688L,49689L,49690L,49691L,49692L,
-49693L,49694L,49695L,49696L,49697L,49698L,49699L,49700L,49701L,49702L,
-49703L,49704L,49705L,49706L,49707L,49708L,49709L,49710L,49711L,49712L,
-49713L,49714L,49715L,49716L,49717L,49718L,49719L,49720L,49721L,49722L,
-49723L,49724L,49725L,49726L,49727L,49728L,49729L,49730L,49731L,49732L,
-49733L,49734L,49735L,49736L,49737L,49738L,49739L,49740L,49741L,49742L,
-49743L,49744L,49745L,49746L,49747L,49748L,49749L,49750L,49751L,49752L,
-49753L,49754L,49755L,49756L,49757L,49758L,49759L,49760L,49761L,49762L,
-49763L,49764L,49765L,49766L,49767L,49768L,49769L,49770L,49771L,49772L,
-49773L,49774L,49775L,49776L,49777L,49778L,49779L,49780L,49781L,49782L,
-49783L,49784L,49785L,49786L,49787L,49788L,49789L,49790L,49791L,49792L,
-49793L,49794L,49795L,49796L,49797L,49798L,49799L,49800L,49801L,49802L,
-49803L,49804L,49805L,49806L,49807L,49808L,49809L,49810L,49811L,49812L,
-49813L,49814L,49815L,49816L,49817L,49818L,49819L,49820L,49821L,49822L,
-49823L,49824L,49825L,49826L,49827L,49828L,49829L,49830L,49831L,49832L,
-49833L,49834L,49835L,49836L,49837L,49838L,49839L,49840L,49841L,49842L,
-49843L,49844L,49845L,49846L,49847L,49848L,49849L,49850L,49851L,49852L,
-49853L,49854L,49855L,49856L,49857L,49858L,49859L,49860L,49861L,49862L,
-49863L,49864L,49865L,49866L,49867L,49868L,49869L,49870L,49871L,49872L,
-49873L,49874L,49875L,49876L,49877L,49878L,49879L,49880L,49881L,49882L,
-49883L,49884L,49885L,49886L,49887L,49888L,49889L,49890L,49891L,49892L,
-49893L,49894L,49895L,49896L,49897L,49898L,49899L,49900L,49901L,49902L,
-49903L,49904L,49905L,49906L,49907L,49908L,49909L,49910L,49911L,49912L,
-49913L,49914L,49915L,49916L,49917L,49918L,49919L,49920L,49921L,49922L,
-49923L,49924L,49925L,49926L,49927L,49928L,49929L,49930L,49931L,49932L,
-49933L,49934L,49935L,49936L,49937L,49938L,49939L,49940L,49941L,49942L,
-49943L,49944L,49945L,49946L,49947L,49948L,49949L,49950L,49951L,49952L,
-49953L,49954L,49955L,49956L,49957L,49958L,49959L,49960L,49961L,49962L,
-49963L,49964L,49965L,49966L,49967L,49968L,49969L,49970L,49971L,49972L,
-49973L,49974L,49975L,49976L,49977L,49978L,49979L,49980L,49981L,49982L,
-49983L,49984L,49985L,49986L,49987L,49988L,49989L,49990L,49991L,49992L,
-49993L,49994L,49995L,49996L,49997L,49998L,49999L,50000L,50001L,50002L,
-50003L,50004L,50005L,50006L,50007L,50008L,50009L,50010L,50011L,50012L,
-50013L,50014L,50015L,50016L,50017L,50018L,50019L,50020L,50021L,50022L,
-50023L,50024L,50025L,50026L,50027L,50028L,50029L,50030L,50031L,50032L,
-50033L,50034L,50035L,50036L,50037L,50038L,50039L,50040L,50041L,50042L,
-50043L,50044L,50045L,50046L,50047L,50048L,50049L,50050L,50051L,50052L,
-50053L,50054L,50055L,50056L,50057L,50058L,50059L,50060L,50061L,50062L,
-50063L,50064L,50065L,50066L,50067L,50068L,50069L,50070L,50071L,50072L,
-50073L,50074L,50075L,50076L,50077L,50078L,50079L,50080L,50081L,50082L,
-50083L,50084L,50085L,50086L,50087L,50088L,50089L,50090L,50091L,50092L,
-50093L,50094L,50095L,50096L,50097L,50098L,50099L,50100L,50101L,50102L,
-50103L,50104L,50105L,50106L,50107L,50108L,50109L,50110L,50111L,50112L,
-50113L,50114L,50115L,50116L,50117L,50118L,50119L,50120L,50121L,50122L,
-50123L,50124L,50125L,50126L,50127L,50128L,50129L,50130L,50131L,50132L,
-50133L,50134L,50135L,50136L,50137L,50138L,50139L,50140L,50141L,50142L,
-50143L,50144L,50145L,50146L,50147L,50148L,50149L,50150L,50151L,50152L,
-50153L,50154L,50155L,50156L,50157L,50158L,50159L,50160L,50161L,50162L,
-50163L,50164L,50165L,50166L,50167L,50168L,50169L,50170L,50171L,50172L,
-50173L,50174L,50175L,50176L,50177L,50178L,50179L,50180L,50181L,50182L,
-50183L,50184L,50185L,50186L,50187L,50188L,50189L,50190L,50191L,50192L,
-50193L,50194L,50195L,50196L,50197L,50198L,50199L,50200L,50201L,50202L,
-50203L,50204L,50205L,50206L,50207L,50208L,50209L,50210L,50211L,50212L,
-50213L,50214L,50215L,50216L,50217L,50218L,50219L,50220L,50221L,50222L,
-50223L,50224L,50225L,50226L,50227L,50228L,50229L,50230L,50231L,50232L,
-50233L,50234L,50235L,50236L,50237L,50238L,50239L,50240L,50241L,50242L,
-50243L,50244L,50245L,50246L,50247L,50248L,50249L,50250L,50251L,50252L,
-50253L,50254L,50255L,50256L,50257L,50258L,50259L,50260L,50261L,50262L,
-50263L,50264L,50265L,50266L,50267L,50268L,50269L,50270L,50271L,50272L,
-50273L,50274L,50275L,50276L,50277L,50278L,50279L,50280L,50281L,50282L,
-50283L,50284L,50285L,50286L,50287L,50288L,50289L,50290L,50291L,50292L,
-50293L,50294L,50295L,50296L,50297L,50298L,50299L,50300L,50301L,50302L,
-50303L,50304L,50305L,50306L,50307L,50308L,50309L,50310L,50311L,50312L,
-50313L,50314L,50315L,50316L,50317L,50318L,50319L,50320L,50321L,50322L,
-50323L,50324L,50325L,50326L,50327L,50328L,50329L,50330L,50331L,50332L,
-50333L,50334L,50335L,50336L,50337L,50338L,50339L,50340L,50341L,50342L,
-50343L,50344L,50345L,50346L,50347L,50348L,50349L,50350L,50351L,50352L,
-50353L,50354L,50355L,50356L,50357L,50358L,50359L,50360L,50361L,50362L,
-50363L,50364L,50365L,50366L,50367L,50368L,50369L,50370L,50371L,50372L,
-50373L,50374L,50375L,50376L,50377L,50378L,50379L,50380L,50381L,50382L,
-50383L,50384L,50385L,50386L,50387L,50388L,50389L,50390L,50391L,50392L,
-50393L,50394L,50395L,50396L,50397L,50398L,50399L,50400L,50401L,50402L,
-50403L,50404L,50405L,50406L,50407L,50408L,50409L,50410L,50411L,50412L,
-50413L,50414L,50415L,50416L,50417L,50418L,50419L,50420L,50421L,50422L,
-50423L,50424L,50425L,50426L,50427L,50428L,50429L,50430L,50431L,50432L,
-50433L,50434L,50435L,50436L,50437L,50438L,50439L,50440L,50441L,50442L,
-50443L,50444L,50445L,50446L,50447L,50448L,50449L,50450L,50451L,50452L,
-50453L,50454L,50455L,50456L,50457L,50458L,50459L,50460L,50461L,50462L,
-50463L,50464L,50465L,50466L,50467L,50468L,50469L,50470L,50471L,50472L,
-50473L,50474L,50475L,50476L,50477L,50478L,50479L,50480L,50481L,50482L,
-50483L,50484L,50485L,50486L,50487L,50488L,50489L,50490L,50491L,50492L,
-50493L,50494L,50495L,50496L,50497L,50498L,50499L,50500L,50501L,50502L,
-50503L,50504L,50505L,50506L,50507L,50508L,50509L,50510L,50511L,50512L,
-50513L,50514L,50515L,50516L,50517L,50518L,50519L,50520L,50521L,50522L,
-50523L,50524L,50525L,50526L,50527L,50528L,50529L,50530L,50531L,50532L,
-50533L,50534L,50535L,50536L,50537L,50538L,50539L,50540L,50541L,50542L,
-50543L,50544L,50545L,50546L,50547L,50548L,50549L,50550L,50551L,50552L,
-50553L,50554L,50555L,50556L,50557L,50558L,50559L,50560L,50561L,50562L,
-50563L,50564L,50565L,50566L,50567L,50568L,50569L,50570L,50571L,50572L,
-50573L,50574L,50575L,50576L,50577L,50578L,50579L,50580L,50581L,50582L,
-50583L,50584L,50585L,50586L,50587L,50588L,50589L,50590L,50591L,50592L,
-50593L,50594L,50595L,50596L,50597L,50598L,50599L,50600L,50601L,50602L,
-50603L,50604L,50605L,50606L,50607L,50608L,50609L,50610L,50611L,50612L,
-50613L,50614L,50615L,50616L,50617L,50618L,50619L,50620L,50621L,50622L,
-50623L,50624L,50625L,50626L,50627L,50628L,50629L,50630L,50631L,50632L,
-50633L,50634L,50635L,50636L,50637L,50638L,50639L,50640L,50641L,50642L,
-50643L,50644L,50645L,50646L,50647L,50648L,50649L,50650L,50651L,50652L,
-50653L,50654L,50655L,50656L,50657L,50658L,50659L,50660L,50661L,50662L,
-50663L,50664L,50665L,50666L,50667L,50668L,50669L,50670L,50671L,50672L,
-50673L,50674L,50675L,50676L,50677L,50678L,50679L,50680L,50681L,50682L,
-50683L,50684L,50685L,50686L,50687L,50688L,50689L,50690L,50691L,50692L,
-50693L,50694L,50695L,50696L,50697L,50698L,50699L,50700L,50701L,50702L,
-50703L,50704L,50705L,50706L,50707L,50708L,50709L,50710L,50711L,50712L,
-50713L,50714L,50715L,50716L,50717L,50718L,50719L,50720L,50721L,50722L,
-50723L,50724L,50725L,50726L,50727L,50728L,50729L,50730L,50731L,50732L,
-50733L,50734L,50735L,50736L,50737L,50738L,50739L,50740L,50741L,50742L,
-50743L,50744L,50745L,50746L,50747L,50748L,50749L,50750L,50751L,50752L,
-50753L,50754L,50755L,50756L,50757L,50758L,50759L,50760L,50761L,50762L,
-50763L,50764L,50765L,50766L,50767L,50768L,50769L,50770L,50771L,50772L,
-50773L,50774L,50775L,50776L,50777L,50778L,50779L,50780L,50781L,50782L,
-50783L,50784L,50785L,50786L,50787L,50788L,50789L,50790L,50791L,50792L,
-50793L,50794L,50795L,50796L,50797L,50798L,50799L,50800L,50801L,50802L,
-50803L,50804L,50805L,50806L,50807L,50808L,50809L,50810L,50811L,50812L,
-50813L,50814L,50815L,50816L,50817L,50818L,50819L,50820L,50821L,50822L,
-50823L,50824L,50825L,50826L,50827L,50828L,50829L,50830L,50831L,50832L,
-50833L,50834L,50835L,50836L,50837L,50838L,50839L,50840L,50841L,50842L,
-50843L,50844L,50845L,50846L,50847L,50848L,50849L,50850L,50851L,50852L,
-50853L,50854L,50855L,50856L,50857L,50858L,50859L,50860L,50861L,50862L,
-50863L,50864L,50865L,50866L,50867L,50868L,50869L,50870L,50871L,50872L,
-50873L,50874L,50875L,50876L,50877L,50878L,50879L,50880L,50881L,50882L,
-50883L,50884L,50885L,50886L,50887L,50888L,50889L,50890L,50891L,50892L,
-50893L,50894L,50895L,50896L,50897L,50898L,50899L,50900L,50901L,50902L,
-50903L,50904L,50905L,50906L,50907L,50908L,50909L,50910L,50911L,50912L,
-50913L,50914L,50915L,50916L,50917L,50918L,50919L,50920L,50921L,50922L,
-50923L,50924L,50925L,50926L,50927L,50928L,50929L,50930L,50931L,50932L,
-50933L,50934L,50935L,50936L,50937L,50938L,50939L,50940L,50941L,50942L,
-50943L,50944L,50945L,50946L,50947L,50948L,50949L,50950L,50951L,50952L,
-50953L,50954L,50955L,50956L,50957L,50958L,50959L,50960L,50961L,50962L,
-50963L,50964L,50965L,50966L,50967L,50968L,50969L,50970L,50971L,50972L,
-50973L,50974L,50975L,50976L,50977L,50978L,50979L,50980L,50981L,50982L,
-50983L,50984L,50985L,50986L,50987L,50988L,50989L,50990L,50991L,50992L,
-50993L,50994L,50995L,50996L,50997L,50998L,50999L,51000L,51001L,51002L,
-51003L,51004L,51005L,51006L,51007L,51008L,51009L,51010L,51011L,51012L,
-51013L,51014L,51015L,51016L,51017L,51018L,51019L,51020L,51021L,51022L,
-51023L,51024L,51025L,51026L,51027L,51028L,51029L,51030L,51031L,51032L,
-51033L,51034L,51035L,51036L,51037L,51038L,51039L,51040L,51041L,51042L,
-51043L,51044L,51045L,51046L,51047L,51048L,51049L,51050L,51051L,51052L,
-51053L,51054L,51055L,51056L,51057L,51058L,51059L,51060L,51061L,51062L,
-51063L,51064L,51065L,51066L,51067L,51068L,51069L,51070L,51071L,51072L,
-51073L,51074L,51075L,51076L,51077L,51078L,51079L,51080L,51081L,51082L,
-51083L,51084L,51085L,51086L,51087L,51088L,51089L,51090L,51091L,51092L,
-51093L,51094L,51095L,51096L,51097L,51098L,51099L,51100L,51101L,51102L,
-51103L,51104L,51105L,51106L,51107L,51108L,51109L,51110L,51111L,51112L,
-51113L,51114L,51115L,51116L,51117L,51118L,51119L,51120L,51121L,51122L,
-51123L,51124L,51125L,51126L,51127L,51128L,51129L,51130L,51131L,51132L,
-51133L,51134L,51135L,51136L,51137L,51138L,51139L,51140L,51141L,51142L,
-51143L,51144L,51145L,51146L,51147L,51148L,51149L,51150L,51151L,51152L,
-51153L,51154L,51155L,51156L,51157L,51158L,51159L,51160L,51161L,51162L,
-51163L,51164L,51165L,51166L,51167L,51168L,51169L,51170L,51171L,51172L,
-51173L,51174L,51175L,51176L,51177L,51178L,51179L,51180L,51181L,51182L,
-51183L,51184L,51185L,51186L,51187L,51188L,51189L,51190L,51191L,51192L,
-51193L,51194L,51195L,51196L,51197L,51198L,51199L,51200L,51201L,51202L,
-51203L,51204L,51205L,51206L,51207L,51208L,51209L,51210L,51211L,51212L,
-51213L,51214L,51215L,51216L,51217L,51218L,51219L,51220L,51221L,51222L,
-51223L,51224L,51225L,51226L,51227L,51228L,51229L,51230L,51231L,51232L,
-51233L,51234L,51235L,51236L,51237L,51238L,51239L,51240L,51241L,51242L,
-51243L,51244L,51245L,51246L,51247L,51248L,51249L,51250L,51251L,51252L,
-51253L,51254L,51255L,51256L,51257L,51258L,51259L,51260L,51261L,51262L,
-51263L,51264L,51265L,51266L,51267L,51268L,51269L,51270L,51271L,51272L,
-51273L,51274L,51275L,51276L,51277L,51278L,51279L,51280L,51281L,51282L,
-51283L,51284L,51285L,51286L,51287L,51288L,51289L,51290L,51291L,51292L,
-51293L,51294L,51295L,51296L,51297L,51298L,51299L,51300L,51301L,51302L,
-51303L,51304L,51305L,51306L,51307L,51308L,51309L,51310L,51311L,51312L,
-51313L,51314L,51315L,51316L,51317L,51318L,51319L,51320L,51321L,51322L,
-51323L,51324L,51325L,51326L,51327L,51328L,51329L,51330L,51331L,51332L,
-51333L,51334L,51335L,51336L,51337L,51338L,51339L,51340L,51341L,51342L,
-51343L,51344L,51345L,51346L,51347L,51348L,51349L,51350L,51351L,51352L,
-51353L,51354L,51355L,51356L,51357L,51358L,51359L,51360L,51361L,51362L,
-51363L,51364L,51365L,51366L,51367L,51368L,51369L,51370L,51371L,51372L,
-51373L,51374L,51375L,51376L,51377L,51378L,51379L,51380L,51381L,51382L,
-51383L,51384L,51385L,51386L,51387L,51388L,51389L,51390L,51391L,51392L,
-51393L,51394L,51395L,51396L,51397L,51398L,51399L,51400L,51401L,51402L,
-51403L,51404L,51405L,51406L,51407L,51408L,51409L,51410L,51411L,51412L,
-51413L,51414L,51415L,51416L,51417L,51418L,51419L,51420L,51421L,51422L,
-51423L,51424L,51425L,51426L,51427L,51428L,51429L,51430L,51431L,51432L,
-51433L,51434L,51435L,51436L,51437L,51438L,51439L,51440L,51441L,51442L,
-51443L,51444L,51445L,51446L,51447L,51448L,51449L,51450L,51451L,51452L,
-51453L,51454L,51455L,51456L,51457L,51458L,51459L,51460L,51461L,51462L,
-51463L,51464L,51465L,51466L,51467L,51468L,51469L,51470L,51471L,51472L,
-51473L,51474L,51475L,51476L,51477L,51478L,51479L,51480L,51481L,51482L,
-51483L,51484L,51485L,51486L,51487L,51488L,51489L,51490L,51491L,51492L,
-51493L,51494L,51495L,51496L,51497L,51498L,51499L,51500L,51501L,51502L,
-51503L,51504L,51505L,51506L,51507L,51508L,51509L,51510L,51511L,51512L,
-51513L,51514L,51515L,51516L,51517L,51518L,51519L,51520L,51521L,51522L,
-51523L,51524L,51525L,51526L,51527L,51528L,51529L,51530L,51531L,51532L,
-51533L,51534L,51535L,51536L,51537L,51538L,51539L,51540L,51541L,51542L,
-51543L,51544L,51545L,51546L,51547L,51548L,51549L,51550L,51551L,51552L,
-51553L,51554L,51555L,51556L,51557L,51558L,51559L,51560L,51561L,51562L,
-51563L,51564L,51565L,51566L,51567L,51568L,51569L,51570L,51571L,51572L,
-51573L,51574L,51575L,51576L,51577L,51578L,51579L,51580L,51581L,51582L,
-51583L,51584L,51585L,51586L,51587L,51588L,51589L,51590L,51591L,51592L,
-51593L,51594L,51595L,51596L,51597L,51598L,51599L,51600L,51601L,51602L,
-51603L,51604L,51605L,51606L,51607L,51608L,51609L,51610L,51611L,51612L,
-51613L,51614L,51615L,51616L,51617L,51618L,51619L,51620L,51621L,51622L,
-51623L,51624L,51625L,51626L,51627L,51628L,51629L,51630L,51631L,51632L,
-51633L,51634L,51635L,51636L,51637L,51638L,51639L,51640L,51641L,51642L,
-51643L,51644L,51645L,51646L,51647L,51648L,51649L,51650L,51651L,51652L,
-51653L,51654L,51655L,51656L,51657L,51658L,51659L,51660L,51661L,51662L,
-51663L,51664L,51665L,51666L,51667L,51668L,51669L,51670L,51671L,51672L,
-51673L,51674L,51675L,51676L,51677L,51678L,51679L,51680L,51681L,51682L,
-51683L,51684L,51685L,51686L,51687L,51688L,51689L,51690L,51691L,51692L,
-51693L,51694L,51695L,51696L,51697L,51698L,51699L,51700L,51701L,51702L,
-51703L,51704L,51705L,51706L,51707L,51708L,51709L,51710L,51711L,51712L,
-51713L,51714L,51715L,51716L,51717L,51718L,51719L,51720L,51721L,51722L,
-51723L,51724L,51725L,51726L,51727L,51728L,51729L,51730L,51731L,51732L,
-51733L,51734L,51735L,51736L,51737L,51738L,51739L,51740L,51741L,51742L,
-51743L,51744L,51745L,51746L,51747L,51748L,51749L,51750L,51751L,51752L,
-51753L,51754L,51755L,51756L,51757L,51758L,51759L,51760L,51761L,51762L,
-51763L,51764L,51765L,51766L,51767L,51768L,51769L,51770L,51771L,51772L,
-51773L,51774L,51775L,51776L,51777L,51778L,51779L,51780L,51781L,51782L,
-51783L,51784L,51785L,51786L,51787L,51788L,51789L,51790L,51791L,51792L,
-51793L,51794L,51795L,51796L,51797L,51798L,51799L,51800L,51801L,51802L,
-51803L,51804L,51805L,51806L,51807L,51808L,51809L,51810L,51811L,51812L,
-51813L,51814L,51815L,51816L,51817L,51818L,51819L,51820L,51821L,51822L,
-51823L,51824L,51825L,51826L,51827L,51828L,51829L,51830L,51831L,51832L,
-51833L,51834L,51835L,51836L,51837L,51838L,51839L,51840L,51841L,51842L,
-51843L,51844L,51845L,51846L,51847L,51848L,51849L,51850L,51851L,51852L,
-51853L,51854L,51855L,51856L,51857L,51858L,51859L,51860L,51861L,51862L,
-51863L,51864L,51865L,51866L,51867L,51868L,51869L,51870L,51871L,51872L,
-51873L,51874L,51875L,51876L,51877L,51878L,51879L,51880L,51881L,51882L,
-51883L,51884L,51885L,51886L,51887L,51888L,51889L,51890L,51891L,51892L,
-51893L,51894L,51895L,51896L,51897L,51898L,51899L,51900L,51901L,51902L,
-51903L,51904L,51905L,51906L,51907L,51908L,51909L,51910L,51911L,51912L,
-51913L,51914L,51915L,51916L,51917L,51918L,51919L,51920L,51921L,51922L,
-51923L,51924L,51925L,51926L,51927L,51928L,51929L,51930L,51931L,51932L,
-51933L,51934L,51935L,51936L,51937L,51938L,51939L,51940L,51941L,51942L,
-51943L,51944L,51945L,51946L,51947L,51948L,51949L,51950L,51951L,51952L,
-51953L,51954L,51955L,51956L,51957L,51958L,51959L,51960L,51961L,51962L,
-51963L,51964L,51965L,51966L,51967L,51968L,51969L,51970L,51971L,51972L,
-51973L,51974L,51975L,51976L,51977L,51978L,51979L,51980L,51981L,51982L,
-51983L,51984L,51985L,51986L,51987L,51988L,51989L,51990L,51991L,51992L,
-51993L,51994L,51995L,51996L,51997L,51998L,51999L,52000L,52001L,52002L,
-52003L,52004L,52005L,52006L,52007L,52008L,52009L,52010L,52011L,52012L,
-52013L,52014L,52015L,52016L,52017L,52018L,52019L,52020L,52021L,52022L,
-52023L,52024L,52025L,52026L,52027L,52028L,52029L,52030L,52031L,52032L,
-52033L,52034L,52035L,52036L,52037L,52038L,52039L,52040L,52041L,52042L,
-52043L,52044L,52045L,52046L,52047L,52048L,52049L,52050L,52051L,52052L,
-52053L,52054L,52055L,52056L,52057L,52058L,52059L,52060L,52061L,52062L,
-52063L,52064L,52065L,52066L,52067L,52068L,52069L,52070L,52071L,52072L,
-52073L,52074L,52075L,52076L,52077L,52078L,52079L,52080L,52081L,52082L,
-52083L,52084L,52085L,52086L,52087L,52088L,52089L,52090L,52091L,52092L,
-52093L,52094L,52095L,52096L,52097L,52098L,52099L,52100L,52101L,52102L,
-52103L,52104L,52105L,52106L,52107L,52108L,52109L,52110L,52111L,52112L,
-52113L,52114L,52115L,52116L,52117L,52118L,52119L,52120L,52121L,52122L,
-52123L,52124L,52125L,52126L,52127L,52128L,52129L,52130L,52131L,52132L,
-52133L,52134L,52135L,52136L,52137L,52138L,52139L,52140L,52141L,52142L,
-52143L,52144L,52145L,52146L,52147L,52148L,52149L,52150L,52151L,52152L,
-52153L,52154L,52155L,52156L,52157L,52158L,52159L,52160L,52161L,52162L,
-52163L,52164L,52165L,52166L,52167L,52168L,52169L,52170L,52171L,52172L,
-52173L,52174L,52175L,52176L,52177L,52178L,52179L,52180L,52181L,52182L,
-52183L,52184L,52185L,52186L,52187L,52188L,52189L,52190L,52191L,52192L,
-52193L,52194L,52195L,52196L,52197L,52198L,52199L,52200L,52201L,52202L,
-52203L,52204L,52205L,52206L,52207L,52208L,52209L,52210L,52211L,52212L,
-52213L,52214L,52215L,52216L,52217L,52218L,52219L,52220L,52221L,52222L,
-52223L,52224L,52225L,52226L,52227L,52228L,52229L,52230L,52231L,52232L,
-52233L,52234L,52235L,52236L,52237L,52238L,52239L,52240L,52241L,52242L,
-52243L,52244L,52245L,52246L,52247L,52248L,52249L,52250L,52251L,52252L,
-52253L,52254L,52255L,52256L,52257L,52258L,52259L,52260L,52261L,52262L,
-52263L,52264L,52265L,52266L,52267L,52268L,52269L,52270L,52271L,52272L,
-52273L,52274L,52275L,52276L,52277L,52278L,52279L,52280L,52281L,52282L,
-52283L,52284L,52285L,52286L,52287L,52288L,52289L,52290L,52291L,52292L,
-52293L,52294L,52295L,52296L,52297L,52298L,52299L,52300L,52301L,52302L,
-52303L,52304L,52305L,52306L,52307L,52308L,52309L,52310L,52311L,52312L,
-52313L,52314L,52315L,52316L,52317L,52318L,52319L,52320L,52321L,52322L,
-52323L,52324L,52325L,52326L,52327L,52328L,52329L,52330L,52331L,52332L,
-52333L,52334L,52335L,52336L,52337L,52338L,52339L,52340L,52341L,52342L,
-52343L,52344L,52345L,52346L,52347L,52348L,52349L,52350L,52351L,52352L,
-52353L,52354L,52355L,52356L,52357L,52358L,52359L,52360L,52361L,52362L,
-52363L,52364L,52365L,52366L,52367L,52368L,52369L,52370L,52371L,52372L,
-52373L,52374L,52375L,52376L,52377L,52378L,52379L,52380L,52381L,52382L,
-52383L,52384L,52385L,52386L,52387L,52388L,52389L,52390L,52391L,52392L,
-52393L,52394L,52395L,52396L,52397L,52398L,52399L,52400L,52401L,52402L,
-52403L,52404L,52405L,52406L,52407L,52408L,52409L,52410L,52411L,52412L,
-52413L,52414L,52415L,52416L,52417L,52418L,52419L,52420L,52421L,52422L,
-52423L,52424L,52425L,52426L,52427L,52428L,52429L,52430L,52431L,52432L,
-52433L,52434L,52435L,52436L,52437L,52438L,52439L,52440L,52441L,52442L,
-52443L,52444L,52445L,52446L,52447L,52448L,52449L,52450L,52451L,52452L,
-52453L,52454L,52455L,52456L,52457L,52458L,52459L,52460L,52461L,52462L,
-52463L,52464L,52465L,52466L,52467L,52468L,52469L,52470L,52471L,52472L,
-52473L,52474L,52475L,52476L,52477L,52478L,52479L,52480L,52481L,52482L,
-52483L,52484L,52485L,52486L,52487L,52488L,52489L,52490L,52491L,52492L,
-52493L,52494L,52495L,52496L,52497L,52498L,52499L,52500L,52501L,52502L,
-52503L,52504L,52505L,52506L,52507L,52508L,52509L,52510L,52511L,52512L,
-52513L,52514L,52515L,52516L,52517L,52518L,52519L,52520L,52521L,52522L,
-52523L,52524L,52525L,52526L,52527L,52528L,52529L,52530L,52531L,52532L,
-52533L,52534L,52535L,52536L,52537L,52538L,52539L,52540L,52541L,52542L,
-52543L,52544L,52545L,52546L,52547L,52548L,52549L,52550L,52551L,52552L,
-52553L,52554L,52555L,52556L,52557L,52558L,52559L,52560L,52561L,52562L,
-52563L,52564L,52565L,52566L,52567L,52568L,52569L,52570L,52571L,52572L,
-52573L,52574L,52575L,52576L,52577L,52578L,52579L,52580L,52581L,52582L,
-52583L,52584L,52585L,52586L,52587L,52588L,52589L,52590L,52591L,52592L,
-52593L,52594L,52595L,52596L,52597L,52598L,52599L,52600L,52601L,52602L,
-52603L,52604L,52605L,52606L,52607L,52608L,52609L,52610L,52611L,52612L,
-52613L,52614L,52615L,52616L,52617L,52618L,52619L,52620L,52621L,52622L,
-52623L,52624L,52625L,52626L,52627L,52628L,52629L,52630L,52631L,52632L,
-52633L,52634L,52635L,52636L,52637L,52638L,52639L,52640L,52641L,52642L,
-52643L,52644L,52645L,52646L,52647L,52648L,52649L,52650L,52651L,52652L,
-52653L,52654L,52655L,52656L,52657L,52658L,52659L,52660L,52661L,52662L,
-52663L,52664L,52665L,52666L,52667L,52668L,52669L,52670L,52671L,52672L,
-52673L,52674L,52675L,52676L,52677L,52678L,52679L,52680L,52681L,52682L,
-52683L,52684L,52685L,52686L,52687L,52688L,52689L,52690L,52691L,52692L,
-52693L,52694L,52695L,52696L,52697L,52698L,52699L,52700L,52701L,52702L,
-52703L,52704L,52705L,52706L,52707L,52708L,52709L,52710L,52711L,52712L,
-52713L,52714L,52715L,52716L,52717L,52718L,52719L,52720L,52721L,52722L,
-52723L,52724L,52725L,52726L,52727L,52728L,52729L,52730L,52731L,52732L,
-52733L,52734L,52735L,52736L,52737L,52738L,52739L,52740L,52741L,52742L,
-52743L,52744L,52745L,52746L,52747L,52748L,52749L,52750L,52751L,52752L,
-52753L,52754L,52755L,52756L,52757L,52758L,52759L,52760L,52761L,52762L,
-52763L,52764L,52765L,52766L,52767L,52768L,52769L,52770L,52771L,52772L,
-52773L,52774L,52775L,52776L,52777L,52778L,52779L,52780L,52781L,52782L,
-52783L,52784L,52785L,52786L,52787L,52788L,52789L,52790L,52791L,52792L,
-52793L,52794L,52795L,52796L,52797L,52798L,52799L,52800L,52801L,52802L,
-52803L,52804L,52805L,52806L,52807L,52808L,52809L,52810L,52811L,52812L,
-52813L,52814L,52815L,52816L,52817L,52818L,52819L,52820L,52821L,52822L,
-52823L,52824L,52825L,52826L,52827L,52828L,52829L,52830L,52831L,52832L,
-52833L,52834L,52835L,52836L,52837L,52838L,52839L,52840L,52841L,52842L,
-52843L,52844L,52845L,52846L,52847L,52848L,52849L,52850L,52851L,52852L,
-52853L,52854L,52855L,52856L,52857L,52858L,52859L,52860L,52861L,52862L,
-52863L,52864L,52865L,52866L,52867L,52868L,52869L,52870L,52871L,52872L,
-52873L,52874L,52875L,52876L,52877L,52878L,52879L,52880L,52881L,52882L,
-52883L,52884L,52885L,52886L,52887L,52888L,52889L,52890L,52891L,52892L,
-52893L,52894L,52895L,52896L,52897L,52898L,52899L,52900L,52901L,52902L,
-52903L,52904L,52905L,52906L,52907L,52908L,52909L,52910L,52911L,52912L,
-52913L,52914L,52915L,52916L,52917L,52918L,52919L,52920L,52921L,52922L,
-52923L,52924L,52925L,52926L,52927L,52928L,52929L,52930L,52931L,52932L,
-52933L,52934L,52935L,52936L,52937L,52938L,52939L,52940L,52941L,52942L,
-52943L,52944L,52945L,52946L,52947L,52948L,52949L,52950L,52951L,52952L,
-52953L,52954L,52955L,52956L,52957L,52958L,52959L,52960L,52961L,52962L,
-52963L,52964L,52965L,52966L,52967L,52968L,52969L,52970L,52971L,52972L,
-52973L,52974L,52975L,52976L,52977L,52978L,52979L,52980L,52981L,52982L,
-52983L,52984L,52985L,52986L,52987L,52988L,52989L,52990L,52991L,52992L,
-52993L,52994L,52995L,52996L,52997L,52998L,52999L,53000L,53001L,53002L,
-53003L,53004L,53005L,53006L,53007L,53008L,53009L,53010L,53011L,53012L,
-53013L,53014L,53015L,53016L,53017L,53018L,53019L,53020L,53021L,53022L,
-53023L,53024L,53025L,53026L,53027L,53028L,53029L,53030L,53031L,53032L,
-53033L,53034L,53035L,53036L,53037L,53038L,53039L,53040L,53041L,53042L,
-53043L,53044L,53045L,53046L,53047L,53048L,53049L,53050L,53051L,53052L,
-53053L,53054L,53055L,53056L,53057L,53058L,53059L,53060L,53061L,53062L,
-53063L,53064L,53065L,53066L,53067L,53068L,53069L,53070L,53071L,53072L,
-53073L,53074L,53075L,53076L,53077L,53078L,53079L,53080L,53081L,53082L,
-53083L,53084L,53085L,53086L,53087L,53088L,53089L,53090L,53091L,53092L,
-53093L,53094L,53095L,53096L,53097L,53098L,53099L,53100L,53101L,53102L,
-53103L,53104L,53105L,53106L,53107L,53108L,53109L,53110L,53111L,53112L,
-53113L,53114L,53115L,53116L,53117L,53118L,53119L,53120L,53121L,53122L,
-53123L,53124L,53125L,53126L,53127L,53128L,53129L,53130L,53131L,53132L,
-53133L,53134L,53135L,53136L,53137L,53138L,53139L,53140L,53141L,53142L,
-53143L,53144L,53145L,53146L,53147L,53148L,53149L,53150L,53151L,53152L,
-53153L,53154L,53155L,53156L,53157L,53158L,53159L,53160L,53161L,53162L,
-53163L,53164L,53165L,53166L,53167L,53168L,53169L,53170L,53171L,53172L,
-53173L,53174L,53175L,53176L,53177L,53178L,53179L,53180L,53181L,53182L,
-53183L,53184L,53185L,53186L,53187L,53188L,53189L,53190L,53191L,53192L,
-53193L,53194L,53195L,53196L,53197L,53198L,53199L,53200L,53201L,53202L,
-53203L,53204L,53205L,53206L,53207L,53208L,53209L,53210L,53211L,53212L,
-53213L,53214L,53215L,53216L,53217L,53218L,53219L,53220L,53221L,53222L,
-53223L,53224L,53225L,53226L,53227L,53228L,53229L,53230L,53231L,53232L,
-53233L,53234L,53235L,53236L,53237L,53238L,53239L,53240L,53241L,53242L,
-53243L,53244L,53245L,53246L,53247L,53248L,53249L,53250L,53251L,53252L,
-53253L,53254L,53255L,53256L,53257L,53258L,53259L,53260L,53261L,53262L,
-53263L,53264L,53265L,53266L,53267L,53268L,53269L,53270L,53271L,53272L,
-53273L,53274L,53275L,53276L,53277L,53278L,53279L,53280L,53281L,53282L,
-53283L,53284L,53285L,53286L,53287L,53288L,53289L,53290L,53291L,53292L,
-53293L,53294L,53295L,53296L,53297L,53298L,53299L,53300L,53301L,53302L,
-53303L,53304L,53305L,53306L,53307L,53308L,53309L,53310L,53311L,53312L,
-53313L,53314L,53315L,53316L,53317L,53318L,53319L,53320L,53321L,53322L,
-53323L,53324L,53325L,53326L,53327L,53328L,53329L,53330L,53331L,53332L,
-53333L,53334L,53335L,53336L,53337L,53338L,53339L,53340L,53341L,53342L,
-53343L,53344L,53345L,53346L,53347L,53348L,53349L,53350L,53351L,53352L,
-53353L,53354L,53355L,53356L,53357L,53358L,53359L,53360L,53361L,53362L,
-53363L,53364L,53365L,53366L,53367L,53368L,53369L,53370L,53371L,53372L,
-53373L,53374L,53375L,53376L,53377L,53378L,53379L,53380L,53381L,53382L,
-53383L,53384L,53385L,53386L,53387L,53388L,53389L,53390L,53391L,53392L,
-53393L,53394L,53395L,53396L,53397L,53398L,53399L,53400L,53401L,53402L,
-53403L,53404L,53405L,53406L,53407L,53408L,53409L,53410L,53411L,53412L,
-53413L,53414L,53415L,53416L,53417L,53418L,53419L,53420L,53421L,53422L,
-53423L,53424L,53425L,53426L,53427L,53428L,53429L,53430L,53431L,53432L,
-53433L,53434L,53435L,53436L,53437L,53438L,53439L,53440L,53441L,53442L,
-53443L,53444L,53445L,53446L,53447L,53448L,53449L,53450L,53451L,53452L,
-53453L,53454L,53455L,53456L,53457L,53458L,53459L,53460L,53461L,53462L,
-53463L,53464L,53465L,53466L,53467L,53468L,53469L,53470L,53471L,53472L,
-53473L,53474L,53475L,53476L,53477L,53478L,53479L,53480L,53481L,53482L,
-53483L,53484L,53485L,53486L,53487L,53488L,53489L,53490L,53491L,53492L,
-53493L,53494L,53495L,53496L,53497L,53498L,53499L,53500L,53501L,53502L,
-53503L,53504L,53505L,53506L,53507L,53508L,53509L,53510L,53511L,53512L,
-53513L,53514L,53515L,53516L,53517L,53518L,53519L,53520L,53521L,53522L,
-53523L,53524L,53525L,53526L,53527L,53528L,53529L,53530L,53531L,53532L,
-53533L,53534L,53535L,53536L,53537L,53538L,53539L,53540L,53541L,53542L,
-53543L,53544L,53545L,53546L,53547L,53548L,53549L,53550L,53551L,53552L,
-53553L,53554L,53555L,53556L,53557L,53558L,53559L,53560L,53561L,53562L,
-53563L,53564L,53565L,53566L,53567L,53568L,53569L,53570L,53571L,53572L,
-53573L,53574L,53575L,53576L,53577L,53578L,53579L,53580L,53581L,53582L,
-53583L,53584L,53585L,53586L,53587L,53588L,53589L,53590L,53591L,53592L,
-53593L,53594L,53595L,53596L,53597L,53598L,53599L,53600L,53601L,53602L,
-53603L,53604L,53605L,53606L,53607L,53608L,53609L,53610L,53611L,53612L,
-53613L,53614L,53615L,53616L,53617L,53618L,53619L,53620L,53621L,53622L,
-53623L,53624L,53625L,53626L,53627L,53628L,53629L,53630L,53631L,53632L,
-53633L,53634L,53635L,53636L,53637L,53638L,53639L,53640L,53641L,53642L,
-53643L,53644L,53645L,53646L,53647L,53648L,53649L,53650L,53651L,53652L,
-53653L,53654L,53655L,53656L,53657L,53658L,53659L,53660L,53661L,53662L,
-53663L,53664L,53665L,53666L,53667L,53668L,53669L,53670L,53671L,53672L,
-53673L,53674L,53675L,53676L,53677L,53678L,53679L,53680L,53681L,53682L,
-53683L,53684L,53685L,53686L,53687L,53688L,53689L,53690L,53691L,53692L,
-53693L,53694L,53695L,53696L,53697L,53698L,53699L,53700L,53701L,53702L,
-53703L,53704L,53705L,53706L,53707L,53708L,53709L,53710L,53711L,53712L,
-53713L,53714L,53715L,53716L,53717L,53718L,53719L,53720L,53721L,53722L,
-53723L,53724L,53725L,53726L,53727L,53728L,53729L,53730L,53731L,53732L,
-53733L,53734L,53735L,53736L,53737L,53738L,53739L,53740L,53741L,53742L,
-53743L,53744L,53745L,53746L,53747L,53748L,53749L,53750L,53751L,53752L,
-53753L,53754L,53755L,53756L,53757L,53758L,53759L,53760L,53761L,53762L,
-53763L,53764L,53765L,53766L,53767L,53768L,53769L,53770L,53771L,53772L,
-53773L,53774L,53775L,53776L,53777L,53778L,53779L,53780L,53781L,53782L,
-53783L,53784L,53785L,53786L,53787L,53788L,53789L,53790L,53791L,53792L,
-53793L,53794L,53795L,53796L,53797L,53798L,53799L,53800L,53801L,53802L,
-53803L,53804L,53805L,53806L,53807L,53808L,53809L,53810L,53811L,53812L,
-53813L,53814L,53815L,53816L,53817L,53818L,53819L,53820L,53821L,53822L,
-53823L,53824L,53825L,53826L,53827L,53828L,53829L,53830L,53831L,53832L,
-53833L,53834L,53835L,53836L,53837L,53838L,53839L,53840L,53841L,53842L,
-53843L,53844L,53845L,53846L,53847L,53848L,53849L,53850L,53851L,53852L,
-53853L,53854L,53855L,53856L,53857L,53858L,53859L,53860L,53861L,53862L,
-53863L,53864L,53865L,53866L,53867L,53868L,53869L,53870L,53871L,53872L,
-53873L,53874L,53875L,53876L,53877L,53878L,53879L,53880L,53881L,53882L,
-53883L,53884L,53885L,53886L,53887L,53888L,53889L,53890L,53891L,53892L,
-53893L,53894L,53895L,53896L,53897L,53898L,53899L,53900L,53901L,53902L,
-53903L,53904L,53905L,53906L,53907L,53908L,53909L,53910L,53911L,53912L,
-53913L,53914L,53915L,53916L,53917L,53918L,53919L,53920L,53921L,53922L,
-53923L,53924L,53925L,53926L,53927L,53928L,53929L,53930L,53931L,53932L,
-53933L,53934L,53935L,53936L,53937L,53938L,53939L,53940L,53941L,53942L,
-53943L,53944L,53945L,53946L,53947L,53948L,53949L,53950L,53951L,53952L,
-53953L,53954L,53955L,53956L,53957L,53958L,53959L,53960L,53961L,53962L,
-53963L,53964L,53965L,53966L,53967L,53968L,53969L,53970L,53971L,53972L,
-53973L,53974L,53975L,53976L,53977L,53978L,53979L,53980L,53981L,53982L,
-53983L,53984L,53985L,53986L,53987L,53988L,53989L,53990L,53991L,53992L,
-53993L,53994L,53995L,53996L,53997L,53998L,53999L,54000L,54001L,54002L,
-54003L,54004L,54005L,54006L,54007L,54008L,54009L,54010L,54011L,54012L,
-54013L,54014L,54015L,54016L,54017L,54018L,54019L,54020L,54021L,54022L,
-54023L,54024L,54025L,54026L,54027L,54028L,54029L,54030L,54031L,54032L,
-54033L,54034L,54035L,54036L,54037L,54038L,54039L,54040L,54041L,54042L,
-54043L,54044L,54045L,54046L,54047L,54048L,54049L,54050L,54051L,54052L,
-54053L,54054L,54055L,54056L,54057L,54058L,54059L,54060L,54061L,54062L,
-54063L,54064L,54065L,54066L,54067L,54068L,54069L,54070L,54071L,54072L,
-54073L,54074L,54075L,54076L,54077L,54078L,54079L,54080L,54081L,54082L,
-54083L,54084L,54085L,54086L,54087L,54088L,54089L,54090L,54091L,54092L,
-54093L,54094L,54095L,54096L,54097L,54098L,54099L,54100L,54101L,54102L,
-54103L,54104L,54105L,54106L,54107L,54108L,54109L,54110L,54111L,54112L,
-54113L,54114L,54115L,54116L,54117L,54118L,54119L,54120L,54121L,54122L,
-54123L,54124L,54125L,54126L,54127L,54128L,54129L,54130L,54131L,54132L,
-54133L,54134L,54135L,54136L,54137L,54138L,54139L,54140L,54141L,54142L,
-54143L,54144L,54145L,54146L,54147L,54148L,54149L,54150L,54151L,54152L,
-54153L,54154L,54155L,54156L,54157L,54158L,54159L,54160L,54161L,54162L,
-54163L,54164L,54165L,54166L,54167L,54168L,54169L,54170L,54171L,54172L,
-54173L,54174L,54175L,54176L,54177L,54178L,54179L,54180L,54181L,54182L,
-54183L,54184L,54185L,54186L,54187L,54188L,54189L,54190L,54191L,54192L,
-54193L,54194L,54195L,54196L,54197L,54198L,54199L,54200L,54201L,54202L,
-54203L,54204L,54205L,54206L,54207L,54208L,54209L,54210L,54211L,54212L,
-54213L,54214L,54215L,54216L,54217L,54218L,54219L,54220L,54221L,54222L,
-54223L,54224L,54225L,54226L,54227L,54228L,54229L,54230L,54231L,54232L,
-54233L,54234L,54235L,54236L,54237L,54238L,54239L,54240L,54241L,54242L,
-54243L,54244L,54245L,54246L,54247L,54248L,54249L,54250L,54251L,54252L,
-54253L,54254L,54255L,54256L,54257L,54258L,54259L,54260L,54261L,54262L,
-54263L,54264L,54265L,54266L,54267L,54268L,54269L,54270L,54271L,54272L,
-54273L,54274L,54275L,54276L,54277L,54278L,54279L,54280L,54281L,54282L,
-54283L,54284L,54285L,54286L,54287L,54288L,54289L,54290L,54291L,54292L,
-54293L,54294L,54295L,54296L,54297L,54298L,54299L,54300L,54301L,54302L,
-54303L,54304L,54305L,54306L,54307L,54308L,54309L,54310L,54311L,54312L,
-54313L,54314L,54315L,54316L,54317L,54318L,54319L,54320L,54321L,54322L,
-54323L,54324L,54325L,54326L,54327L,54328L,54329L,54330L,54331L,54332L,
-54333L,54334L,54335L,54336L,54337L,54338L,54339L,54340L,54341L,54342L,
-54343L,54344L,54345L,54346L,54347L,54348L,54349L,54350L,54351L,54352L,
-54353L,54354L,54355L,54356L,54357L,54358L,54359L,54360L,54361L,54362L,
-54363L,54364L,54365L,54366L,54367L,54368L,54369L,54370L,54371L,54372L,
-54373L,54374L,54375L,54376L,54377L,54378L,54379L,54380L,54381L,54382L,
-54383L,54384L,54385L,54386L,54387L,54388L,54389L,54390L,54391L,54392L,
-54393L,54394L,54395L,54396L,54397L,54398L,54399L,54400L,54401L,54402L,
-54403L,54404L,54405L,54406L,54407L,54408L,54409L,54410L,54411L,54412L,
-54413L,54414L,54415L,54416L,54417L,54418L,54419L,54420L,54421L,54422L,
-54423L,54424L,54425L,54426L,54427L,54428L,54429L,54430L,54431L,54432L,
-54433L,54434L,54435L,54436L,54437L,54438L,54439L,54440L,54441L,54442L,
-54443L,54444L,54445L,54446L,54447L,54448L,54449L,54450L,54451L,54452L,
-54453L,54454L,54455L,54456L,54457L,54458L,54459L,54460L,54461L,54462L,
-54463L,54464L,54465L,54466L,54467L,54468L,54469L,54470L,54471L,54472L,
-54473L,54474L,54475L,54476L,54477L,54478L,54479L,54480L,54481L,54482L,
-54483L,54484L,54485L,54486L,54487L,54488L,54489L,54490L,54491L,54492L,
-54493L,54494L,54495L,54496L,54497L,54498L,54499L,54500L,54501L,54502L,
-54503L,54504L,54505L,54506L,54507L,54508L,54509L,54510L,54511L,54512L,
-54513L,54514L,54515L,54516L,54517L,54518L,54519L,54520L,54521L,54522L,
-54523L,54524L,54525L,54526L,54527L,54528L,54529L,54530L,54531L,54532L,
-54533L,54534L,54535L,54536L,54537L,54538L,54539L,54540L,54541L,54542L,
-54543L,54544L,54545L,54546L,54547L,54548L,54549L,54550L,54551L,54552L,
-54553L,54554L,54555L,54556L,54557L,54558L,54559L,54560L,54561L,54562L,
-54563L,54564L,54565L,54566L,54567L,54568L,54569L,54570L,54571L,54572L,
-54573L,54574L,54575L,54576L,54577L,54578L,54579L,54580L,54581L,54582L,
-54583L,54584L,54585L,54586L,54587L,54588L,54589L,54590L,54591L,54592L,
-54593L,54594L,54595L,54596L,54597L,54598L,54599L,54600L,54601L,54602L,
-54603L,54604L,54605L,54606L,54607L,54608L,54609L,54610L,54611L,54612L,
-54613L,54614L,54615L,54616L,54617L,54618L,54619L,54620L,54621L,54622L,
-54623L,54624L,54625L,54626L,54627L,54628L,54629L,54630L,54631L,54632L,
-54633L,54634L,54635L,54636L,54637L,54638L,54639L,54640L,54641L,54642L,
-54643L,54644L,54645L,54646L,54647L,54648L,54649L,54650L,54651L,54652L,
-54653L,54654L,54655L,54656L,54657L,54658L,54659L,54660L,54661L,54662L,
-54663L,54664L,54665L,54666L,54667L,54668L,54669L,54670L,54671L,54672L,
-54673L,54674L,54675L,54676L,54677L,54678L,54679L,54680L,54681L,54682L,
-54683L,54684L,54685L,54686L,54687L,54688L,54689L,54690L,54691L,54692L,
-54693L,54694L,54695L,54696L,54697L,54698L,54699L,54700L,54701L,54702L,
-54703L,54704L,54705L,54706L,54707L,54708L,54709L,54710L,54711L,54712L,
-54713L,54714L,54715L,54716L,54717L,54718L,54719L,54720L,54721L,54722L,
-54723L,54724L,54725L,54726L,54727L,54728L,54729L,54730L,54731L,54732L,
-54733L,54734L,54735L,54736L,54737L,54738L,54739L,54740L,54741L,54742L,
-54743L,54744L,54745L,54746L,54747L,54748L,54749L,54750L,54751L,54752L,
-54753L,54754L,54755L,54756L,54757L,54758L,54759L,54760L,54761L,54762L,
-54763L,54764L,54765L,54766L,54767L,54768L,54769L,54770L,54771L,54772L,
-54773L,54774L,54775L,54776L,54777L,54778L,54779L,54780L,54781L,54782L,
-54783L,54784L,54785L,54786L,54787L,54788L,54789L,54790L,54791L,54792L,
-54793L,54794L,54795L,54796L,54797L,54798L,54799L,54800L,54801L,54802L,
-54803L,54804L,54805L,54806L,54807L,54808L,54809L,54810L,54811L,54812L,
-54813L,54814L,54815L,54816L,54817L,54818L,54819L,54820L,54821L,54822L,
-54823L,54824L,54825L,54826L,54827L,54828L,54829L,54830L,54831L,54832L,
-54833L,54834L,54835L,54836L,54837L,54838L,54839L,54840L,54841L,54842L,
-54843L,54844L,54845L,54846L,54847L,54848L,54849L,54850L,54851L,54852L,
-54853L,54854L,54855L,54856L,54857L,54858L,54859L,54860L,54861L,54862L,
-54863L,54864L,54865L,54866L,54867L,54868L,54869L,54870L,54871L,54872L,
-54873L,54874L,54875L,54876L,54877L,54878L,54879L,54880L,54881L,54882L,
-54883L,54884L,54885L,54886L,54887L,54888L,54889L,54890L,54891L,54892L,
-54893L,54894L,54895L,54896L,54897L,54898L,54899L,54900L,54901L,54902L,
-54903L,54904L,54905L,54906L,54907L,54908L,54909L,54910L,54911L,54912L,
-54913L,54914L,54915L,54916L,54917L,54918L,54919L,54920L,54921L,54922L,
-54923L,54924L,54925L,54926L,54927L,54928L,54929L,54930L,54931L,54932L,
-54933L,54934L,54935L,54936L,54937L,54938L,54939L,54940L,54941L,54942L,
-54943L,54944L,54945L,54946L,54947L,54948L,54949L,54950L,54951L,54952L,
-54953L,54954L,54955L,54956L,54957L,54958L,54959L,54960L,54961L,54962L,
-54963L,54964L,54965L,54966L,54967L,54968L,54969L,54970L,54971L,54972L,
-54973L,54974L,54975L,54976L,54977L,54978L,54979L,54980L,54981L,54982L,
-54983L,54984L,54985L,54986L,54987L,54988L,54989L,54990L,54991L,54992L,
-54993L,54994L,54995L,54996L,54997L,54998L,54999L,55000L,55001L,55002L,
-55003L,55004L,55005L,55006L,55007L,55008L,55009L,55010L,55011L,55012L,
-55013L,55014L,55015L,55016L,55017L,55018L,55019L,55020L,55021L,55022L,
-55023L,55024L,55025L,55026L,55027L,55028L,55029L,55030L,55031L,55032L,
-55033L,55034L,55035L,55036L,55037L,55038L,55039L,55040L,55041L,55042L,
-55043L,55044L,55045L,55046L,55047L,55048L,55049L,55050L,55051L,55052L,
-55053L,55054L,55055L,55056L,55057L,55058L,55059L,55060L,55061L,55062L,
-55063L,55064L,55065L,55066L,55067L,55068L,55069L,55070L,55071L,55072L,
-55073L,55074L,55075L,55076L,55077L,55078L,55079L,55080L,55081L,55082L,
-55083L,55084L,55085L,55086L,55087L,55088L,55089L,55090L,55091L,55092L,
-55093L,55094L,55095L,55096L,55097L,55098L,55099L,55100L,55101L,55102L,
-55103L,55104L,55105L,55106L,55107L,55108L,55109L,55110L,55111L,55112L,
-55113L,55114L,55115L,55116L,55117L,55118L,55119L,55120L,55121L,55122L,
-55123L,55124L,55125L,55126L,55127L,55128L,55129L,55130L,55131L,55132L,
-55133L,55134L,55135L,55136L,55137L,55138L,55139L,55140L,55141L,55142L,
-55143L,55144L,55145L,55146L,55147L,55148L,55149L,55150L,55151L,55152L,
-55153L,55154L,55155L,55156L,55157L,55158L,55159L,55160L,55161L,55162L,
-55163L,55164L,55165L,55166L,55167L,55168L,55169L,55170L,55171L,55172L,
-55173L,55174L,55175L,55176L,55177L,55178L,55179L,55180L,55181L,55182L,
-55183L,55184L,55185L,55186L,55187L,55188L,55189L,55190L,55191L,55192L,
-55193L,55194L,55195L,55196L,55197L,55198L,55199L,55200L,55201L,55202L,
-55203L,55204L,55205L,55206L,55207L,55208L,55209L,55210L,55211L,55212L,
-55213L,55214L,55215L,55216L,55217L,55218L,55219L,55220L,55221L,55222L,
-55223L,55224L,55225L,55226L,55227L,55228L,55229L,55230L,55231L,55232L,
-55233L,55234L,55235L,55236L,55237L,55238L,55239L,55240L,55241L,55242L,
-55243L,55244L,55245L,55246L,55247L,55248L,55249L,55250L,55251L,55252L,
-55253L,55254L,55255L,55256L,55257L,55258L,55259L,55260L,55261L,55262L,
-55263L,55264L,55265L,55266L,55267L,55268L,55269L,55270L,55271L,55272L,
-55273L,55274L,55275L,55276L,55277L,55278L,55279L,55280L,55281L,55282L,
-55283L,55284L,55285L,55286L,55287L,55288L,55289L,55290L,55291L,55292L,
-55293L,55294L,55295L,55296L,55297L,55298L,55299L,55300L,55301L,55302L,
-55303L,55304L,55305L,55306L,55307L,55308L,55309L,55310L,55311L,55312L,
-55313L,55314L,55315L,55316L,55317L,55318L,55319L,55320L,55321L,55322L,
-55323L,55324L,55325L,55326L,55327L,55328L,55329L,55330L,55331L,55332L,
-55333L,55334L,55335L,55336L,55337L,55338L,55339L,55340L,55341L,55342L,
-55343L,55344L,55345L,55346L,55347L,55348L,55349L,55350L,55351L,55352L,
-55353L,55354L,55355L,55356L,55357L,55358L,55359L,55360L,55361L,55362L,
-55363L,55364L,55365L,55366L,55367L,55368L,55369L,55370L,55371L,55372L,
-55373L,55374L,55375L,55376L,55377L,55378L,55379L,55380L,55381L,55382L,
-55383L,55384L,55385L,55386L,55387L,55388L,55389L,55390L,55391L,55392L,
-55393L,55394L,55395L,55396L,55397L,55398L,55399L,55400L,55401L,55402L,
-55403L,55404L,55405L,55406L,55407L,55408L,55409L,55410L,55411L,55412L,
-55413L,55414L,55415L,55416L,55417L,55418L,55419L,55420L,55421L,55422L,
-55423L,55424L,55425L,55426L,55427L,55428L,55429L,55430L,55431L,55432L,
-55433L,55434L,55435L,55436L,55437L,55438L,55439L,55440L,55441L,55442L,
-55443L,55444L,55445L,55446L,55447L,55448L,55449L,55450L,55451L,55452L,
-55453L,55454L,55455L,55456L,55457L,55458L,55459L,55460L,55461L,55462L,
-55463L,55464L,55465L,55466L,55467L,55468L,55469L,55470L,55471L,55472L,
-55473L,55474L,55475L,55476L,55477L,55478L,55479L,55480L,55481L,55482L,
-55483L,55484L,55485L,55486L,55487L,55488L,55489L,55490L,55491L,55492L,
-55493L,55494L,55495L,55496L,55497L,55498L,55499L,55500L,55501L,55502L,
-55503L,55504L,55505L,55506L,55507L,55508L,55509L,55510L,55511L,55512L,
-55513L,55514L,55515L,55516L,55517L,55518L,55519L,55520L,55521L,55522L,
-55523L,55524L,55525L,55526L,55527L,55528L,55529L,55530L,55531L,55532L,
-55533L,55534L,55535L,55536L,55537L,55538L,55539L,55540L,55541L,55542L,
-55543L,55544L,55545L,55546L,55547L,55548L,55549L,55550L,55551L,55552L,
-55553L,55554L,55555L,55556L,55557L,55558L,55559L,55560L,55561L,55562L,
-55563L,55564L,55565L,55566L,55567L,55568L,55569L,55570L,55571L,55572L,
-55573L,55574L,55575L,55576L,55577L,55578L,55579L,55580L,55581L,55582L,
-55583L,55584L,55585L,55586L,55587L,55588L,55589L,55590L,55591L,55592L,
-55593L,55594L,55595L,55596L,55597L,55598L,55599L,55600L,55601L,55602L,
-55603L,55604L,55605L,55606L,55607L,55608L,55609L,55610L,55611L,55612L,
-55613L,55614L,55615L,55616L,55617L,55618L,55619L,55620L,55621L,55622L,
-55623L,55624L,55625L,55626L,55627L,55628L,55629L,55630L,55631L,55632L,
-55633L,55634L,55635L,55636L,55637L,55638L,55639L,55640L,55641L,55642L,
-55643L,55644L,55645L,55646L,55647L,55648L,55649L,55650L,55651L,55652L,
-55653L,55654L,55655L,55656L,55657L,55658L,55659L,55660L,55661L,55662L,
-55663L,55664L,55665L,55666L,55667L,55668L,55669L,55670L,55671L,55672L,
-55673L,55674L,55675L,55676L,55677L,55678L,55679L,55680L,55681L,55682L,
-55683L,55684L,55685L,55686L,55687L,55688L,55689L,55690L,55691L,55692L,
-55693L,55694L,55695L,55696L,55697L,55698L,55699L,55700L,55701L,55702L,
-55703L,55704L,55705L,55706L,55707L,55708L,55709L,55710L,55711L,55712L,
-55713L,55714L,55715L,55716L,55717L,55718L,55719L,55720L,55721L,55722L,
-55723L,55724L,55725L,55726L,55727L,55728L,55729L,55730L,55731L,55732L,
-55733L,55734L,55735L,55736L,55737L,55738L,55739L,55740L,55741L,55742L,
-55743L,55744L,55745L,55746L,55747L,55748L,55749L,55750L,55751L,55752L,
-55753L,55754L,55755L,55756L,55757L,55758L,55759L,55760L,55761L,55762L,
-55763L,55764L,55765L,55766L,55767L,55768L,55769L,55770L,55771L,55772L,
-55773L,55774L,55775L,55776L,55777L,55778L,55779L,55780L,55781L,55782L,
-55783L,55784L,55785L,55786L,55787L,55788L,55789L,55790L,55791L,55792L,
-55793L,55794L,55795L,55796L,55797L,55798L,55799L,55800L,55801L,55802L,
-55803L,55804L,55805L,55806L,55807L,55808L,55809L,55810L,55811L,55812L,
-55813L,55814L,55815L,55816L,55817L,55818L,55819L,55820L,55821L,55822L,
-55823L,55824L,55825L,55826L,55827L,55828L,55829L,55830L,55831L,55832L,
-55833L,55834L,55835L,55836L,55837L,55838L,55839L,55840L,55841L,55842L,
-55843L,55844L,55845L,55846L,55847L,55848L,55849L,55850L,55851L,55852L,
-55853L,55854L,55855L,55856L,55857L,55858L,55859L,55860L,55861L,55862L,
-55863L,55864L,55865L,55866L,55867L,55868L,55869L,55870L,55871L,55872L,
-55873L,55874L,55875L,55876L,55877L,55878L,55879L,55880L,55881L,55882L,
-55883L,55884L,55885L,55886L,55887L,55888L,55889L,55890L,55891L,55892L,
-55893L,55894L,55895L,55896L,55897L,55898L,55899L,55900L,55901L,55902L,
-55903L,55904L,55905L,55906L,55907L,55908L,55909L,55910L,55911L,55912L,
-55913L,55914L,55915L,55916L,55917L,55918L,55919L,55920L,55921L,55922L,
-55923L,55924L,55925L,55926L,55927L,55928L,55929L,55930L,55931L,55932L,
-55933L,55934L,55935L,55936L,55937L,55938L,55939L,55940L,55941L,55942L,
-55943L,55944L,55945L,55946L,55947L,55948L,55949L,55950L,55951L,55952L,
-55953L,55954L,55955L,55956L,55957L,55958L,55959L,55960L,55961L,55962L,
-55963L,55964L,55965L,55966L,55967L,55968L,55969L,55970L,55971L,55972L,
-55973L,55974L,55975L,55976L,55977L,55978L,55979L,55980L,55981L,55982L,
-55983L,55984L,55985L,55986L,55987L,55988L,55989L,55990L,55991L,55992L,
-55993L,55994L,55995L,55996L,55997L,55998L,55999L,56000L,56001L,56002L,
-56003L,56004L,56005L,56006L,56007L,56008L,56009L,56010L,56011L,56012L,
-56013L,56014L,56015L,56016L,56017L,56018L,56019L,56020L,56021L,56022L,
-56023L,56024L,56025L,56026L,56027L,56028L,56029L,56030L,56031L,56032L,
-56033L,56034L,56035L,56036L,56037L,56038L,56039L,56040L,56041L,56042L,
-56043L,56044L,56045L,56046L,56047L,56048L,56049L,56050L,56051L,56052L,
-56053L,56054L,56055L,56056L,56057L,56058L,56059L,56060L,56061L,56062L,
-56063L,56064L,56065L,56066L,56067L,56068L,56069L,56070L,56071L,56072L,
-56073L,56074L,56075L,56076L,56077L,56078L,56079L,56080L,56081L,56082L,
-56083L,56084L,56085L,56086L,56087L,56088L,56089L,56090L,56091L,56092L,
-56093L,56094L,56095L,56096L,56097L,56098L,56099L,56100L,56101L,56102L,
-56103L,56104L,56105L,56106L,56107L,56108L,56109L,56110L,56111L,56112L,
-56113L,56114L,56115L,56116L,56117L,56118L,56119L,56120L,56121L,56122L,
-56123L,56124L,56125L,56126L,56127L,56128L,56129L,56130L,56131L,56132L,
-56133L,56134L,56135L,56136L,56137L,56138L,56139L,56140L,56141L,56142L,
-56143L,56144L,56145L,56146L,56147L,56148L,56149L,56150L,56151L,56152L,
-56153L,56154L,56155L,56156L,56157L,56158L,56159L,56160L,56161L,56162L,
-56163L,56164L,56165L,56166L,56167L,56168L,56169L,56170L,56171L,56172L,
-56173L,56174L,56175L,56176L,56177L,56178L,56179L,56180L,56181L,56182L,
-56183L,56184L,56185L,56186L,56187L,56188L,56189L,56190L,56191L,56192L,
-56193L,56194L,56195L,56196L,56197L,56198L,56199L,56200L,56201L,56202L,
-56203L,56204L,56205L,56206L,56207L,56208L,56209L,56210L,56211L,56212L,
-56213L,56214L,56215L,56216L,56217L,56218L,56219L,56220L,56221L,56222L,
-56223L,56224L,56225L,56226L,56227L,56228L,56229L,56230L,56231L,56232L,
-56233L,56234L,56235L,56236L,56237L,56238L,56239L,56240L,56241L,56242L,
-56243L,56244L,56245L,56246L,56247L,56248L,56249L,56250L,56251L,56252L,
-56253L,56254L,56255L,56256L,56257L,56258L,56259L,56260L,56261L,56262L,
-56263L,56264L,56265L,56266L,56267L,56268L,56269L,56270L,56271L,56272L,
-56273L,56274L,56275L,56276L,56277L,56278L,56279L,56280L,56281L,56282L,
-56283L,56284L,56285L,56286L,56287L,56288L,56289L,56290L,56291L,56292L,
-56293L,56294L,56295L,56296L,56297L,56298L,56299L,56300L,56301L,56302L,
-56303L,56304L,56305L,56306L,56307L,56308L,56309L,56310L,56311L,56312L,
-56313L,56314L,56315L,56316L,56317L,56318L,56319L,56320L,56321L,56322L,
-56323L,56324L,56325L,56326L,56327L,56328L,56329L,56330L,56331L,56332L,
-56333L,56334L,56335L,56336L,56337L,56338L,56339L,56340L,56341L,56342L,
-56343L,56344L,56345L,56346L,56347L,56348L,56349L,56350L,56351L,56352L,
-56353L,56354L,56355L,56356L,56357L,56358L,56359L,56360L,56361L,56362L,
-56363L,56364L,56365L,56366L,56367L,56368L,56369L,56370L,56371L,56372L,
-56373L,56374L,56375L,56376L,56377L,56378L,56379L,56380L,56381L,56382L,
-56383L,56384L,56385L,56386L,56387L,56388L,56389L,56390L,56391L,56392L,
-56393L,56394L,56395L,56396L,56397L,56398L,56399L,56400L,56401L,56402L,
-56403L,56404L,56405L,56406L,56407L,56408L,56409L,56410L,56411L,56412L,
-56413L,56414L,56415L,56416L,56417L,56418L,56419L,56420L,56421L,56422L,
-56423L,56424L,56425L,56426L,56427L,56428L,56429L,56430L,56431L,56432L,
-56433L,56434L,56435L,56436L,56437L,56438L,56439L,56440L,56441L,56442L,
-56443L,56444L,56445L,56446L,56447L,56448L,56449L,56450L,56451L,56452L,
-56453L,56454L,56455L,56456L,56457L,56458L,56459L,56460L,56461L,56462L,
-56463L,56464L,56465L,56466L,56467L,56468L,56469L,56470L,56471L,56472L,
-56473L,56474L,56475L,56476L,56477L,56478L,56479L,56480L,56481L,56482L,
-56483L,56484L,56485L,56486L,56487L,56488L,56489L,56490L,56491L,56492L,
-56493L,56494L,56495L,56496L,56497L,56498L,56499L,56500L,56501L,56502L,
-56503L,56504L,56505L,56506L,56507L,56508L,56509L,56510L,56511L,56512L,
-56513L,56514L,56515L,56516L,56517L,56518L,56519L,56520L,56521L,56522L,
-56523L,56524L,56525L,56526L,56527L,56528L,56529L,56530L,56531L,56532L,
-56533L,56534L,56535L,56536L,56537L,56538L,56539L,56540L,56541L,56542L,
-56543L,56544L,56545L,56546L,56547L,56548L,56549L,56550L,56551L,56552L,
-56553L,56554L,56555L,56556L,56557L,56558L,56559L,56560L,56561L,56562L,
-56563L,56564L,56565L,56566L,56567L,56568L,56569L,56570L,56571L,56572L,
-56573L,56574L,56575L,56576L,56577L,56578L,56579L,56580L,56581L,56582L,
-56583L,56584L,56585L,56586L,56587L,56588L,56589L,56590L,56591L,56592L,
-56593L,56594L,56595L,56596L,56597L,56598L,56599L,56600L,56601L,56602L,
-56603L,56604L,56605L,56606L,56607L,56608L,56609L,56610L,56611L,56612L,
-56613L,56614L,56615L,56616L,56617L,56618L,56619L,56620L,56621L,56622L,
-56623L,56624L,56625L,56626L,56627L,56628L,56629L,56630L,56631L,56632L,
-56633L,56634L,56635L,56636L,56637L,56638L,56639L,56640L,56641L,56642L,
-56643L,56644L,56645L,56646L,56647L,56648L,56649L,56650L,56651L,56652L,
-56653L,56654L,56655L,56656L,56657L,56658L,56659L,56660L,56661L,56662L,
-56663L,56664L,56665L,56666L,56667L,56668L,56669L,56670L,56671L,56672L,
-56673L,56674L,56675L,56676L,56677L,56678L,56679L,56680L,56681L,56682L,
-56683L,56684L,56685L,56686L,56687L,56688L,56689L,56690L,56691L,56692L,
-56693L,56694L,56695L,56696L,56697L,56698L,56699L,56700L,56701L,56702L,
-56703L,56704L,56705L,56706L,56707L,56708L,56709L,56710L,56711L,56712L,
-56713L,56714L,56715L,56716L,56717L,56718L,56719L,56720L,56721L,56722L,
-56723L,56724L,56725L,56726L,56727L,56728L,56729L,56730L,56731L,56732L,
-56733L,56734L,56735L,56736L,56737L,56738L,56739L,56740L,56741L,56742L,
-56743L,56744L,56745L,56746L,56747L,56748L,56749L,56750L,56751L,56752L,
-56753L,56754L,56755L,56756L,56757L,56758L,56759L,56760L,56761L,56762L,
-56763L,56764L,56765L,56766L,56767L,56768L,56769L,56770L,56771L,56772L,
-56773L,56774L,56775L,56776L,56777L,56778L,56779L,56780L,56781L,56782L,
-56783L,56784L,56785L,56786L,56787L,56788L,56789L,56790L,56791L,56792L,
-56793L,56794L,56795L,56796L,56797L,56798L,56799L,56800L,56801L,56802L,
-56803L,56804L,56805L,56806L,56807L,56808L,56809L,56810L,56811L,56812L,
-56813L,56814L,56815L,56816L,56817L,56818L,56819L,56820L,56821L,56822L,
-56823L,56824L,56825L,56826L,56827L,56828L,56829L,56830L,56831L,56832L,
-56833L,56834L,56835L,56836L,56837L,56838L,56839L,56840L,56841L,56842L,
-56843L,56844L,56845L,56846L,56847L,56848L,56849L,56850L,56851L,56852L,
-56853L,56854L,56855L,56856L,56857L,56858L,56859L,56860L,56861L,56862L,
-56863L,56864L,56865L,56866L,56867L,56868L,56869L,56870L,56871L,56872L,
-56873L,56874L,56875L,56876L,56877L,56878L,56879L,56880L,56881L,56882L,
-56883L,56884L,56885L,56886L,56887L,56888L,56889L,56890L,56891L,56892L,
-56893L,56894L,56895L,56896L,56897L,56898L,56899L,56900L,56901L,56902L,
-56903L,56904L,56905L,56906L,56907L,56908L,56909L,56910L,56911L,56912L,
-56913L,56914L,56915L,56916L,56917L,56918L,56919L,56920L,56921L,56922L,
-56923L,56924L,56925L,56926L,56927L,56928L,56929L,56930L,56931L,56932L,
-56933L,56934L,56935L,56936L,56937L,56938L,56939L,56940L,56941L,56942L,
-56943L,56944L,56945L,56946L,56947L,56948L,56949L,56950L,56951L,56952L,
-56953L,56954L,56955L,56956L,56957L,56958L,56959L,56960L,56961L,56962L,
-56963L,56964L,56965L,56966L,56967L,56968L,56969L,56970L,56971L,56972L,
-56973L,56974L,56975L,56976L,56977L,56978L,56979L,56980L,56981L,56982L,
-56983L,56984L,56985L,56986L,56987L,56988L,56989L,56990L,56991L,56992L,
-56993L,56994L,56995L,56996L,56997L,56998L,56999L,57000L,57001L,57002L,
-57003L,57004L,57005L,57006L,57007L,57008L,57009L,57010L,57011L,57012L,
-57013L,57014L,57015L,57016L,57017L,57018L,57019L,57020L,57021L,57022L,
-57023L,57024L,57025L,57026L,57027L,57028L,57029L,57030L,57031L,57032L,
-57033L,57034L,57035L,57036L,57037L,57038L,57039L,57040L,57041L,57042L,
-57043L,57044L,57045L,57046L,57047L,57048L,57049L,57050L,57051L,57052L,
-57053L,57054L,57055L,57056L,57057L,57058L,57059L,57060L,57061L,57062L,
-57063L,57064L,57065L,57066L,57067L,57068L,57069L,57070L,57071L,57072L,
-57073L,57074L,57075L,57076L,57077L,57078L,57079L,57080L,57081L,57082L,
-57083L,57084L,57085L,57086L,57087L,57088L,57089L,57090L,57091L,57092L,
-57093L,57094L,57095L,57096L,57097L,57098L,57099L,57100L,57101L,57102L,
-57103L,57104L,57105L,57106L,57107L,57108L,57109L,57110L,57111L,57112L,
-57113L,57114L,57115L,57116L,57117L,57118L,57119L,57120L,57121L,57122L,
-57123L,57124L,57125L,57126L,57127L,57128L,57129L,57130L,57131L,57132L,
-57133L,57134L,57135L,57136L,57137L,57138L,57139L,57140L,57141L,57142L,
-57143L,57144L,57145L,57146L,57147L,57148L,57149L,57150L,57151L,57152L,
-57153L,57154L,57155L,57156L,57157L,57158L,57159L,57160L,57161L,57162L,
-57163L,57164L,57165L,57166L,57167L,57168L,57169L,57170L,57171L,57172L,
-57173L,57174L,57175L,57176L,57177L,57178L,57179L,57180L,57181L,57182L,
-57183L,57184L,57185L,57186L,57187L,57188L,57189L,57190L,57191L,57192L,
-57193L,57194L,57195L,57196L,57197L,57198L,57199L,57200L,57201L,57202L,
-57203L,57204L,57205L,57206L,57207L,57208L,57209L,57210L,57211L,57212L,
-57213L,57214L,57215L,57216L,57217L,57218L,57219L,57220L,57221L,57222L,
-57223L,57224L,57225L,57226L,57227L,57228L,57229L,57230L,57231L,57232L,
-57233L,57234L,57235L,57236L,57237L,57238L,57239L,57240L,57241L,57242L,
-57243L,57244L,57245L,57246L,57247L,57248L,57249L,57250L,57251L,57252L,
-57253L,57254L,57255L,57256L,57257L,57258L,57259L,57260L,57261L,57262L,
-57263L,57264L,57265L,57266L,57267L,57268L,57269L,57270L,57271L,57272L,
-57273L,57274L,57275L,57276L,57277L,57278L,57279L,57280L,57281L,57282L,
-57283L,57284L,57285L,57286L,57287L,57288L,57289L,57290L,57291L,57292L,
-57293L,57294L,57295L,57296L,57297L,57298L,57299L,57300L,57301L,57302L,
-57303L,57304L,57305L,57306L,57307L,57308L,57309L,57310L,57311L,57312L,
-57313L,57314L,57315L,57316L,57317L,57318L,57319L,57320L,57321L,57322L,
-57323L,57324L,57325L,57326L,57327L,57328L,57329L,57330L,57331L,57332L,
-57333L,57334L,57335L,57336L,57337L,57338L,57339L,57340L,57341L,57342L,
-57343L,57344L,57345L,57346L,57347L,57348L,57349L,57350L,57351L,57352L,
-57353L,57354L,57355L,57356L,57357L,57358L,57359L,57360L,57361L,57362L,
-57363L,57364L,57365L,57366L,57367L,57368L,57369L,57370L,57371L,57372L,
-57373L,57374L,57375L,57376L,57377L,57378L,57379L,57380L,57381L,57382L,
-57383L,57384L,57385L,57386L,57387L,57388L,57389L,57390L,57391L,57392L,
-57393L,57394L,57395L,57396L,57397L,57398L,57399L,57400L,57401L,57402L,
-57403L,57404L,57405L,57406L,57407L,57408L,57409L,57410L,57411L,57412L,
-57413L,57414L,57415L,57416L,57417L,57418L,57419L,57420L,57421L,57422L,
-57423L,57424L,57425L,57426L,57427L,57428L,57429L,57430L,57431L,57432L,
-57433L,57434L,57435L,57436L,57437L,57438L,57439L,57440L,57441L,57442L,
-57443L,57444L,57445L,57446L,57447L,57448L,57449L,57450L,57451L,57452L,
-57453L,57454L,57455L,57456L,57457L,57458L,57459L,57460L,57461L,57462L,
-57463L,57464L,57465L,57466L,57467L,57468L,57469L,57470L,57471L,57472L,
-57473L,57474L,57475L,57476L,57477L,57478L,57479L,57480L,57481L,57482L,
-57483L,57484L,57485L,57486L,57487L,57488L,57489L,57490L,57491L,57492L,
-57493L,57494L,57495L,57496L,57497L,57498L,57499L,57500L,57501L,57502L,
-57503L,57504L,57505L,57506L,57507L,57508L,57509L,57510L,57511L,57512L,
-57513L,57514L,57515L,57516L,57517L,57518L,57519L,57520L,57521L,57522L,
-57523L,57524L,57525L,57526L,57527L,57528L,57529L,57530L,57531L,57532L,
-57533L,57534L,57535L,57536L,57537L,57538L,57539L,57540L,57541L,57542L,
-57543L,57544L,57545L,57546L,57547L,57548L,57549L,57550L,57551L,57552L,
-57553L,57554L,57555L,57556L,57557L,57558L,57559L,57560L,57561L,57562L,
-57563L,57564L,57565L,57566L,57567L,57568L,57569L,57570L,57571L,57572L,
-57573L,57574L,57575L,57576L,57577L,57578L,57579L,57580L,57581L,57582L,
-57583L,57584L,57585L,57586L,57587L,57588L,57589L,57590L,57591L,57592L,
-57593L,57594L,57595L,57596L,57597L,57598L,57599L,57600L,57601L,57602L,
-57603L,57604L,57605L,57606L,57607L,57608L,57609L,57610L,57611L,57612L,
-57613L,57614L,57615L,57616L,57617L,57618L,57619L,57620L,57621L,57622L,
-57623L,57624L,57625L,57626L,57627L,57628L,57629L,57630L,57631L,57632L,
-57633L,57634L,57635L,57636L,57637L,57638L,57639L,57640L,57641L,57642L,
-57643L,57644L,57645L,57646L,57647L,57648L,57649L,57650L,57651L,57652L,
-57653L,57654L,57655L,57656L,57657L,57658L,57659L,57660L,57661L,57662L,
-57663L,57664L,57665L,57666L,57667L,57668L,57669L,57670L,57671L,57672L,
-57673L,57674L,57675L,57676L,57677L,57678L,57679L,57680L,57681L,57682L,
-57683L,57684L,57685L,57686L,57687L,57688L,57689L,57690L,57691L,57692L,
-57693L,57694L,57695L,57696L,57697L,57698L,57699L,57700L,57701L,57702L,
-57703L,57704L,57705L,57706L,57707L,57708L,57709L,57710L,57711L,57712L,
-57713L,57714L,57715L,57716L,57717L,57718L,57719L,57720L,57721L,57722L,
-57723L,57724L,57725L,57726L,57727L,57728L,57729L,57730L,57731L,57732L,
-57733L,57734L,57735L,57736L,57737L,57738L,57739L,57740L,57741L,57742L,
-57743L,57744L,57745L,57746L,57747L,57748L,57749L,57750L,57751L,57752L,
-57753L,57754L,57755L,57756L,57757L,57758L,57759L,57760L,57761L,57762L,
-57763L,57764L,57765L,57766L,57767L,57768L,57769L,57770L,57771L,57772L,
-57773L,57774L,57775L,57776L,57777L,57778L,57779L,57780L,57781L,57782L,
-57783L,57784L,57785L,57786L,57787L,57788L,57789L,57790L,57791L,57792L,
-57793L,57794L,57795L,57796L,57797L,57798L,57799L,57800L,57801L,57802L,
-57803L,57804L,57805L,57806L,57807L,57808L,57809L,57810L,57811L,57812L,
-57813L,57814L,57815L,57816L,57817L,57818L,57819L,57820L,57821L,57822L,
-57823L,57824L,57825L,57826L,57827L,57828L,57829L,57830L,57831L,57832L,
-57833L,57834L,57835L,57836L,57837L,57838L,57839L,57840L,57841L,57842L,
-57843L,57844L,57845L,57846L,57847L,57848L,57849L,57850L,57851L,57852L,
-57853L,57854L,57855L,57856L,57857L,57858L,57859L,57860L,57861L,57862L,
-57863L,57864L,57865L,57866L,57867L,57868L,57869L,57870L,57871L,57872L,
-57873L,57874L,57875L,57876L,57877L,57878L,57879L,57880L,57881L,57882L,
-57883L,57884L,57885L,57886L,57887L,57888L,57889L,57890L,57891L,57892L,
-57893L,57894L,57895L,57896L,57897L,57898L,57899L,57900L,57901L,57902L,
-57903L,57904L,57905L,57906L,57907L,57908L,57909L,57910L,57911L,57912L,
-57913L,57914L,57915L,57916L,57917L,57918L,57919L,57920L,57921L,57922L,
-57923L,57924L,57925L,57926L,57927L,57928L,57929L,57930L,57931L,57932L,
-57933L,57934L,57935L,57936L,57937L,57938L,57939L,57940L,57941L,57942L,
-57943L,57944L,57945L,57946L,57947L,57948L,57949L,57950L,57951L,57952L,
-57953L,57954L,57955L,57956L,57957L,57958L,57959L,57960L,57961L,57962L,
-57963L,57964L,57965L,57966L,57967L,57968L,57969L,57970L,57971L,57972L,
-57973L,57974L,57975L,57976L,57977L,57978L,57979L,57980L,57981L,57982L,
-57983L,57984L,57985L,57986L,57987L,57988L,57989L,57990L,57991L,57992L,
-57993L,57994L,57995L,57996L,57997L,57998L,57999L,58000L,58001L,58002L,
-58003L,58004L,58005L,58006L,58007L,58008L,58009L,58010L,58011L,58012L,
-58013L,58014L,58015L,58016L,58017L,58018L,58019L,58020L,58021L,58022L,
-58023L,58024L,58025L,58026L,58027L,58028L,58029L,58030L,58031L,58032L,
-58033L,58034L,58035L,58036L,58037L,58038L,58039L,58040L,58041L,58042L,
-58043L,58044L,58045L,58046L,58047L,58048L,58049L,58050L,58051L,58052L,
-58053L,58054L,58055L,58056L,58057L,58058L,58059L,58060L,58061L,58062L,
-58063L,58064L,58065L,58066L,58067L,58068L,58069L,58070L,58071L,58072L,
-58073L,58074L,58075L,58076L,58077L,58078L,58079L,58080L,58081L,58082L,
-58083L,58084L,58085L,58086L,58087L,58088L,58089L,58090L,58091L,58092L,
-58093L,58094L,58095L,58096L,58097L,58098L,58099L,58100L,58101L,58102L,
-58103L,58104L,58105L,58106L,58107L,58108L,58109L,58110L,58111L,58112L,
-58113L,58114L,58115L,58116L,58117L,58118L,58119L,58120L,58121L,58122L,
-58123L,58124L,58125L,58126L,58127L,58128L,58129L,58130L,58131L,58132L,
-58133L,58134L,58135L,58136L,58137L,58138L,58139L,58140L,58141L,58142L,
-58143L,58144L,58145L,58146L,58147L,58148L,58149L,58150L,58151L,58152L,
-58153L,58154L,58155L,58156L,58157L,58158L,58159L,58160L,58161L,58162L,
-58163L,58164L,58165L,58166L,58167L,58168L,58169L,58170L,58171L,58172L,
-58173L,58174L,58175L,58176L,58177L,58178L,58179L,58180L,58181L,58182L,
-58183L,58184L,58185L,58186L,58187L,58188L,58189L,58190L,58191L,58192L,
-58193L,58194L,58195L,58196L,58197L,58198L,58199L,58200L,58201L,58202L,
-58203L,58204L,58205L,58206L,58207L,58208L,58209L,58210L,58211L,58212L,
-58213L,58214L,58215L,58216L,58217L,58218L,58219L,58220L,58221L,58222L,
-58223L,58224L,58225L,58226L,58227L,58228L,58229L,58230L,58231L,58232L,
-58233L,58234L,58235L,58236L,58237L,58238L,58239L,58240L,58241L,58242L,
-58243L,58244L,58245L,58246L,58247L,58248L,58249L,58250L,58251L,58252L,
-58253L,58254L,58255L,58256L,58257L,58258L,58259L,58260L,58261L,58262L,
-58263L,58264L,58265L,58266L,58267L,58268L,58269L,58270L,58271L,58272L,
-58273L,58274L,58275L,58276L,58277L,58278L,58279L,58280L,58281L,58282L,
-58283L,58284L,58285L,58286L,58287L,58288L,58289L,58290L,58291L,58292L,
-58293L,58294L,58295L,58296L,58297L,58298L,58299L,58300L,58301L,58302L,
-58303L,58304L,58305L,58306L,58307L,58308L,58309L,58310L,58311L,58312L,
-58313L,58314L,58315L,58316L,58317L,58318L,58319L,58320L,58321L,58322L,
-58323L,58324L,58325L,58326L,58327L,58328L,58329L,58330L,58331L,58332L,
-58333L,58334L,58335L,58336L,58337L,58338L,58339L,58340L,58341L,58342L,
-58343L,58344L,58345L,58346L,58347L,58348L,58349L,58350L,58351L,58352L,
-58353L,58354L,58355L,58356L,58357L,58358L,58359L,58360L,58361L,58362L,
-58363L,58364L,58365L,58366L,58367L,58368L,58369L,58370L,58371L,58372L,
-58373L,58374L,58375L,58376L,58377L,58378L,58379L,58380L,58381L,58382L,
-58383L,58384L,58385L,58386L,58387L,58388L,58389L,58390L,58391L,58392L,
-58393L,58394L,58395L,58396L,58397L,58398L,58399L,58400L,58401L,58402L,
-58403L,58404L,58405L,58406L,58407L,58408L,58409L,58410L,58411L,58412L,
-58413L,58414L,58415L,58416L,58417L,58418L,58419L,58420L,58421L,58422L,
-58423L,58424L,58425L,58426L,58427L,58428L,58429L,58430L,58431L,58432L,
-58433L,58434L,58435L,58436L,58437L,58438L,58439L,58440L,58441L,58442L,
-58443L,58444L,58445L,58446L,58447L,58448L,58449L,58450L,58451L,58452L,
-58453L,58454L,58455L,58456L,58457L,58458L,58459L,58460L,58461L,58462L,
-58463L,58464L,58465L,58466L,58467L,58468L,58469L,58470L,58471L,58472L,
-58473L,58474L,58475L,58476L,58477L,58478L,58479L,58480L,58481L,58482L,
-58483L,58484L,58485L,58486L,58487L,58488L,58489L,58490L,58491L,58492L,
-58493L,58494L,58495L,58496L,58497L,58498L,58499L,58500L,58501L,58502L,
-58503L,58504L,58505L,58506L,58507L,58508L,58509L,58510L,58511L,58512L,
-58513L,58514L,58515L,58516L,58517L,58518L,58519L,58520L,58521L,58522L,
-58523L,58524L,58525L,58526L,58527L,58528L,58529L,58530L,58531L,58532L,
-58533L,58534L,58535L,58536L,58537L,58538L,58539L,58540L,58541L,58542L,
-58543L,58544L,58545L,58546L,58547L,58548L,58549L,58550L,58551L,58552L,
-58553L,58554L,58555L,58556L,58557L,58558L,58559L,58560L,58561L,58562L,
-58563L,58564L,58565L,58566L,58567L,58568L,58569L,58570L,58571L,58572L,
-58573L,58574L,58575L,58576L,58577L,58578L,58579L,58580L,58581L,58582L,
-58583L,58584L,58585L,58586L,58587L,58588L,58589L,58590L,58591L,58592L,
-58593L,58594L,58595L,58596L,58597L,58598L,58599L,58600L,58601L,58602L,
-58603L,58604L,58605L,58606L,58607L,58608L,58609L,58610L,58611L,58612L,
-58613L,58614L,58615L,58616L,58617L,58618L,58619L,58620L,58621L,58622L,
-58623L,58624L,58625L,58626L,58627L,58628L,58629L,58630L,58631L,58632L,
-58633L,58634L,58635L,58636L,58637L,58638L,58639L,58640L,58641L,58642L,
-58643L,58644L,58645L,58646L,58647L,58648L,58649L,58650L,58651L,58652L,
-58653L,58654L,58655L,58656L,58657L,58658L,58659L,58660L,58661L,58662L,
-58663L,58664L,58665L,58666L,58667L,58668L,58669L,58670L,58671L,58672L,
-58673L,58674L,58675L,58676L,58677L,58678L,58679L,58680L,58681L,58682L,
-58683L,58684L,58685L,58686L,58687L,58688L,58689L,58690L,58691L,58692L,
-58693L,58694L,58695L,58696L,58697L,58698L,58699L,58700L,58701L,58702L,
-58703L,58704L,58705L,58706L,58707L,58708L,58709L,58710L,58711L,58712L,
-58713L,58714L,58715L,58716L,58717L,58718L,58719L,58720L,58721L,58722L,
-58723L,58724L,58725L,58726L,58727L,58728L,58729L,58730L,58731L,58732L,
-58733L,58734L,58735L,58736L,58737L,58738L,58739L,58740L,58741L,58742L,
-58743L,58744L,58745L,58746L,58747L,58748L,58749L,58750L,58751L,58752L,
-58753L,58754L,58755L,58756L,58757L,58758L,58759L,58760L,58761L,58762L,
-58763L,58764L,58765L,58766L,58767L,58768L,58769L,58770L,58771L,58772L,
-58773L,58774L,58775L,58776L,58777L,58778L,58779L,58780L,58781L,58782L,
-58783L,58784L,58785L,58786L,58787L,58788L,58789L,58790L,58791L,58792L,
-58793L,58794L,58795L,58796L,58797L,58798L,58799L,58800L,58801L,58802L,
-58803L,58804L,58805L,58806L,58807L,58808L,58809L,58810L,58811L,58812L,
-58813L,58814L,58815L,58816L,58817L,58818L,58819L,58820L,58821L,58822L,
-58823L,58824L,58825L,58826L,58827L,58828L,58829L,58830L,58831L,58832L,
-58833L,58834L,58835L,58836L,58837L,58838L,58839L,58840L,58841L,58842L,
-58843L,58844L,58845L,58846L,58847L,58848L,58849L,58850L,58851L,58852L,
-58853L,58854L,58855L,58856L,58857L,58858L,58859L,58860L,58861L,58862L,
-58863L,58864L,58865L,58866L,58867L,58868L,58869L,58870L,58871L,58872L,
-58873L,58874L,58875L,58876L,58877L,58878L,58879L,58880L,58881L,58882L,
-58883L,58884L,58885L,58886L,58887L,58888L,58889L,58890L,58891L,58892L,
-58893L,58894L,58895L,58896L,58897L,58898L,58899L,58900L,58901L,58902L,
-58903L,58904L,58905L,58906L,58907L,58908L,58909L,58910L,58911L,58912L,
-58913L,58914L,58915L,58916L,58917L,58918L,58919L,58920L,58921L,58922L,
-58923L,58924L,58925L,58926L,58927L,58928L,58929L,58930L,58931L,58932L,
-58933L,58934L,58935L,58936L,58937L,58938L,58939L,58940L,58941L,58942L,
-58943L,58944L,58945L,58946L,58947L,58948L,58949L,58950L,58951L,58952L,
-58953L,58954L,58955L,58956L,58957L,58958L,58959L,58960L,58961L,58962L,
-58963L,58964L,58965L,58966L,58967L,58968L,58969L,58970L,58971L,58972L,
-58973L,58974L,58975L,58976L,58977L,58978L,58979L,58980L,58981L,58982L,
-58983L,58984L,58985L,58986L,58987L,58988L,58989L,58990L,58991L,58992L,
-58993L,58994L,58995L,58996L,58997L,58998L,58999L,59000L,59001L,59002L,
-59003L,59004L,59005L,59006L,59007L,59008L,59009L,59010L,59011L,59012L,
-59013L,59014L,59015L,59016L,59017L,59018L,59019L,59020L,59021L,59022L,
-59023L,59024L,59025L,59026L,59027L,59028L,59029L,59030L,59031L,59032L,
-59033L,59034L,59035L,59036L,59037L,59038L,59039L,59040L,59041L,59042L,
-59043L,59044L,59045L,59046L,59047L,59048L,59049L,59050L,59051L,59052L,
-59053L,59054L,59055L,59056L,59057L,59058L,59059L,59060L,59061L,59062L,
-59063L,59064L,59065L,59066L,59067L,59068L,59069L,59070L,59071L,59072L,
-59073L,59074L,59075L,59076L,59077L,59078L,59079L,59080L,59081L,59082L,
-59083L,59084L,59085L,59086L,59087L,59088L,59089L,59090L,59091L,59092L,
-59093L,59094L,59095L,59096L,59097L,59098L,59099L,59100L,59101L,59102L,
-59103L,59104L,59105L,59106L,59107L,59108L,59109L,59110L,59111L,59112L,
-59113L,59114L,59115L,59116L,59117L,59118L,59119L,59120L,59121L,59122L,
-59123L,59124L,59125L,59126L,59127L,59128L,59129L,59130L,59131L,59132L,
-59133L,59134L,59135L,59136L,59137L,59138L,59139L,59140L,59141L,59142L,
-59143L,59144L,59145L,59146L,59147L,59148L,59149L,59150L,59151L,59152L,
-59153L,59154L,59155L,59156L,59157L,59158L,59159L,59160L,59161L,59162L,
-59163L,59164L,59165L,59166L,59167L,59168L,59169L,59170L,59171L,59172L,
-59173L,59174L,59175L,59176L,59177L,59178L,59179L,59180L,59181L,59182L,
-59183L,59184L,59185L,59186L,59187L,59188L,59189L,59190L,59191L,59192L,
-59193L,59194L,59195L,59196L,59197L,59198L,59199L,59200L,59201L,59202L,
-59203L,59204L,59205L,59206L,59207L,59208L,59209L,59210L,59211L,59212L,
-59213L,59214L,59215L,59216L,59217L,59218L,59219L,59220L,59221L,59222L,
-59223L,59224L,59225L,59226L,59227L,59228L,59229L,59230L,59231L,59232L,
-59233L,59234L,59235L,59236L,59237L,59238L,59239L,59240L,59241L,59242L,
-59243L,59244L,59245L,59246L,59247L,59248L,59249L,59250L,59251L,59252L,
-59253L,59254L,59255L,59256L,59257L,59258L,59259L,59260L,59261L,59262L,
-59263L,59264L,59265L,59266L,59267L,59268L,59269L,59270L,59271L,59272L,
-59273L,59274L,59275L,59276L,59277L,59278L,59279L,59280L,59281L,59282L,
-59283L,59284L,59285L,59286L,59287L,59288L,59289L,59290L,59291L,59292L,
-59293L,59294L,59295L,59296L,59297L,59298L,59299L,59300L,59301L,59302L,
-59303L,59304L,59305L,59306L,59307L,59308L,59309L,59310L,59311L,59312L,
-59313L,59314L,59315L,59316L,59317L,59318L,59319L,59320L,59321L,59322L,
-59323L,59324L,59325L,59326L,59327L,59328L,59329L,59330L,59331L,59332L,
-59333L,59334L,59335L,59336L,59337L,59338L,59339L,59340L,59341L,59342L,
-59343L,59344L,59345L,59346L,59347L,59348L,59349L,59350L,59351L,59352L,
-59353L,59354L,59355L,59356L,59357L,59358L,59359L,59360L,59361L,59362L,
-59363L,59364L,59365L,59366L,59367L,59368L,59369L,59370L,59371L,59372L,
-59373L,59374L,59375L,59376L,59377L,59378L,59379L,59380L,59381L,59382L,
-59383L,59384L,59385L,59386L,59387L,59388L,59389L,59390L,59391L,59392L,
-59393L,59394L,59395L,59396L,59397L,59398L,59399L,59400L,59401L,59402L,
-59403L,59404L,59405L,59406L,59407L,59408L,59409L,59410L,59411L,59412L,
-59413L,59414L,59415L,59416L,59417L,59418L,59419L,59420L,59421L,59422L,
-59423L,59424L,59425L,59426L,59427L,59428L,59429L,59430L,59431L,59432L,
-59433L,59434L,59435L,59436L,59437L,59438L,59439L,59440L,59441L,59442L,
-59443L,59444L,59445L,59446L,59447L,59448L,59449L,59450L,59451L,59452L,
-59453L,59454L,59455L,59456L,59457L,59458L,59459L,59460L,59461L,59462L,
-59463L,59464L,59465L,59466L,59467L,59468L,59469L,59470L,59471L,59472L,
-59473L,59474L,59475L,59476L,59477L,59478L,59479L,59480L,59481L,59482L,
-59483L,59484L,59485L,59486L,59487L,59488L,59489L,59490L,59491L,59492L,
-59493L,59494L,59495L,59496L,59497L,59498L,59499L,59500L,59501L,59502L,
-59503L,59504L,59505L,59506L,59507L,59508L,59509L,59510L,59511L,59512L,
-59513L,59514L,59515L,59516L,59517L,59518L,59519L,59520L,59521L,59522L,
-59523L,59524L,59525L,59526L,59527L,59528L,59529L,59530L,59531L,59532L,
-59533L,59534L,59535L,59536L,59537L,59538L,59539L,59540L,59541L,59542L,
-59543L,59544L,59545L,59546L,59547L,59548L,59549L,59550L,59551L,59552L,
-59553L,59554L,59555L,59556L,59557L,59558L,59559L,59560L,59561L,59562L,
-59563L,59564L,59565L,59566L,59567L,59568L,59569L,59570L,59571L,59572L,
-59573L,59574L,59575L,59576L,59577L,59578L,59579L,59580L,59581L,59582L,
-59583L,59584L,59585L,59586L,59587L,59588L,59589L,59590L,59591L,59592L,
-59593L,59594L,59595L,59596L,59597L,59598L,59599L,59600L,59601L,59602L,
-59603L,59604L,59605L,59606L,59607L,59608L,59609L,59610L,59611L,59612L,
-59613L,59614L,59615L,59616L,59617L,59618L,59619L,59620L,59621L,59622L,
-59623L,59624L,59625L,59626L,59627L,59628L,59629L,59630L,59631L,59632L,
-59633L,59634L,59635L,59636L,59637L,59638L,59639L,59640L,59641L,59642L,
-59643L,59644L,59645L,59646L,59647L,59648L,59649L,59650L,59651L,59652L,
-59653L,59654L,59655L,59656L,59657L,59658L,59659L,59660L,59661L,59662L,
-59663L,59664L,59665L,59666L,59667L,59668L,59669L,59670L,59671L,59672L,
-59673L,59674L,59675L,59676L,59677L,59678L,59679L,59680L,59681L,59682L,
-59683L,59684L,59685L,59686L,59687L,59688L,59689L,59690L,59691L,59692L,
-59693L,59694L,59695L,59696L,59697L,59698L,59699L,59700L,59701L,59702L,
-59703L,59704L,59705L,59706L,59707L,59708L,59709L,59710L,59711L,59712L,
-59713L,59714L,59715L,59716L,59717L,59718L,59719L,59720L,59721L,59722L,
-59723L,59724L,59725L,59726L,59727L,59728L,59729L,59730L,59731L,59732L,
-59733L,59734L,59735L,59736L,59737L,59738L,59739L,59740L,59741L,59742L,
-59743L,59744L,59745L,59746L,59747L,59748L,59749L,59750L,59751L,59752L,
-59753L,59754L,59755L,59756L,59757L,59758L,59759L,59760L,59761L,59762L,
-59763L,59764L,59765L,59766L,59767L,59768L,59769L,59770L,59771L,59772L,
-59773L,59774L,59775L,59776L,59777L,59778L,59779L,59780L,59781L,59782L,
-59783L,59784L,59785L,59786L,59787L,59788L,59789L,59790L,59791L,59792L,
-59793L,59794L,59795L,59796L,59797L,59798L,59799L,59800L,59801L,59802L,
-59803L,59804L,59805L,59806L,59807L,59808L,59809L,59810L,59811L,59812L,
-59813L,59814L,59815L,59816L,59817L,59818L,59819L,59820L,59821L,59822L,
-59823L,59824L,59825L,59826L,59827L,59828L,59829L,59830L,59831L,59832L,
-59833L,59834L,59835L,59836L,59837L,59838L,59839L,59840L,59841L,59842L,
-59843L,59844L,59845L,59846L,59847L,59848L,59849L,59850L,59851L,59852L,
-59853L,59854L,59855L,59856L,59857L,59858L,59859L,59860L,59861L,59862L,
-59863L,59864L,59865L,59866L,59867L,59868L,59869L,59870L,59871L,59872L,
-59873L,59874L,59875L,59876L,59877L,59878L,59879L,59880L,59881L,59882L,
-59883L,59884L,59885L,59886L,59887L,59888L,59889L,59890L,59891L,59892L,
-59893L,59894L,59895L,59896L,59897L,59898L,59899L,59900L,59901L,59902L,
-59903L,59904L,59905L,59906L,59907L,59908L,59909L,59910L,59911L,59912L,
-59913L,59914L,59915L,59916L,59917L,59918L,59919L,59920L,59921L,59922L,
-59923L,59924L,59925L,59926L,59927L,59928L,59929L,59930L,59931L,59932L,
-59933L,59934L,59935L,59936L,59937L,59938L,59939L,59940L,59941L,59942L,
-59943L,59944L,59945L,59946L,59947L,59948L,59949L,59950L,59951L,59952L,
-59953L,59954L,59955L,59956L,59957L,59958L,59959L,59960L,59961L,59962L,
-59963L,59964L,59965L,59966L,59967L,59968L,59969L,59970L,59971L,59972L,
-59973L,59974L,59975L,59976L,59977L,59978L,59979L,59980L,59981L,59982L,
-59983L,59984L,59985L,59986L,59987L,59988L,59989L,59990L,59991L,59992L,
-59993L,59994L,59995L,59996L,59997L,59998L,59999L,60000L,60001L,60002L,
-60003L,60004L,60005L,60006L,60007L,60008L,60009L,60010L,60011L,60012L,
-60013L,60014L,60015L,60016L,60017L,60018L,60019L,60020L,60021L,60022L,
-60023L,60024L,60025L,60026L,60027L,60028L,60029L,60030L,60031L,60032L,
-60033L,60034L,60035L,60036L,60037L,60038L,60039L,60040L,60041L,60042L,
-60043L,60044L,60045L,60046L,60047L,60048L,60049L,60050L,60051L,60052L,
-60053L,60054L,60055L,60056L,60057L,60058L,60059L,60060L,60061L,60062L,
-60063L,60064L,60065L,60066L,60067L,60068L,60069L,60070L,60071L,60072L,
-60073L,60074L,60075L,60076L,60077L,60078L,60079L,60080L,60081L,60082L,
-60083L,60084L,60085L,60086L,60087L,60088L,60089L,60090L,60091L,60092L,
-60093L,60094L,60095L,60096L,60097L,60098L,60099L,60100L,60101L,60102L,
-60103L,60104L,60105L,60106L,60107L,60108L,60109L,60110L,60111L,60112L,
-60113L,60114L,60115L,60116L,60117L,60118L,60119L,60120L,60121L,60122L,
-60123L,60124L,60125L,60126L,60127L,60128L,60129L,60130L,60131L,60132L,
-60133L,60134L,60135L,60136L,60137L,60138L,60139L,60140L,60141L,60142L,
-60143L,60144L,60145L,60146L,60147L,60148L,60149L,60150L,60151L,60152L,
-60153L,60154L,60155L,60156L,60157L,60158L,60159L,60160L,60161L,60162L,
-60163L,60164L,60165L,60166L,60167L,60168L,60169L,60170L,60171L,60172L,
-60173L,60174L,60175L,60176L,60177L,60178L,60179L,60180L,60181L,60182L,
-60183L,60184L,60185L,60186L,60187L,60188L,60189L,60190L,60191L,60192L,
-60193L,60194L,60195L,60196L,60197L,60198L,60199L,60200L,60201L,60202L,
-60203L,60204L,60205L,60206L,60207L,60208L,60209L,60210L,60211L,60212L,
-60213L,60214L,60215L,60216L,60217L,60218L,60219L,60220L,60221L,60222L,
-60223L,60224L,60225L,60226L,60227L,60228L,60229L,60230L,60231L,60232L,
-60233L,60234L,60235L,60236L,60237L,60238L,60239L,60240L,60241L,60242L,
-60243L,60244L,60245L,60246L,60247L,60248L,60249L,60250L,60251L,60252L,
-60253L,60254L,60255L,60256L,60257L,60258L,60259L,60260L,60261L,60262L,
-60263L,60264L,60265L,60266L,60267L,60268L,60269L,60270L,60271L,60272L,
-60273L,60274L,60275L,60276L,60277L,60278L,60279L,60280L,60281L,60282L,
-60283L,60284L,60285L,60286L,60287L,60288L,60289L,60290L,60291L,60292L,
-60293L,60294L,60295L,60296L,60297L,60298L,60299L,60300L,60301L,60302L,
-60303L,60304L,60305L,60306L,60307L,60308L,60309L,60310L,60311L,60312L,
-60313L,60314L,60315L,60316L,60317L,60318L,60319L,60320L,60321L,60322L,
-60323L,60324L,60325L,60326L,60327L,60328L,60329L,60330L,60331L,60332L,
-60333L,60334L,60335L,60336L,60337L,60338L,60339L,60340L,60341L,60342L,
-60343L,60344L,60345L,60346L,60347L,60348L,60349L,60350L,60351L,60352L,
-60353L,60354L,60355L,60356L,60357L,60358L,60359L,60360L,60361L,60362L,
-60363L,60364L,60365L,60366L,60367L,60368L,60369L,60370L,60371L,60372L,
-60373L,60374L,60375L,60376L,60377L,60378L,60379L,60380L,60381L,60382L,
-60383L,60384L,60385L,60386L,60387L,60388L,60389L,60390L,60391L,60392L,
-60393L,60394L,60395L,60396L,60397L,60398L,60399L,60400L,60401L,60402L,
-60403L,60404L,60405L,60406L,60407L,60408L,60409L,60410L,60411L,60412L,
-60413L,60414L,60415L,60416L,60417L,60418L,60419L,60420L,60421L,60422L,
-60423L,60424L,60425L,60426L,60427L,60428L,60429L,60430L,60431L,60432L,
-60433L,60434L,60435L,60436L,60437L,60438L,60439L,60440L,60441L,60442L,
-60443L,60444L,60445L,60446L,60447L,60448L,60449L,60450L,60451L,60452L,
-60453L,60454L,60455L,60456L,60457L,60458L,60459L,60460L,60461L,60462L,
-60463L,60464L,60465L,60466L,60467L,60468L,60469L,60470L,60471L,60472L,
-60473L,60474L,60475L,60476L,60477L,60478L,60479L,60480L,60481L,60482L,
-60483L,60484L,60485L,60486L,60487L,60488L,60489L,60490L,60491L,60492L,
-60493L,60494L,60495L,60496L,60497L,60498L,60499L,60500L,60501L,60502L,
-60503L,60504L,60505L,60506L,60507L,60508L,60509L,60510L,60511L,60512L,
-60513L,60514L,60515L,60516L,60517L,60518L,60519L,60520L,60521L,60522L,
-60523L,60524L,60525L,60526L,60527L,60528L,60529L,60530L,60531L,60532L,
-60533L,60534L,60535L,60536L,60537L,60538L,60539L,60540L,60541L,60542L,
-60543L,60544L,60545L,60546L,60547L,60548L,60549L,60550L,60551L,60552L,
-60553L,60554L,60555L,60556L,60557L,60558L,60559L,60560L,60561L,60562L,
-60563L,60564L,60565L,60566L,60567L,60568L,60569L,60570L,60571L,60572L,
-60573L,60574L,60575L,60576L,60577L,60578L,60579L,60580L,60581L,60582L,
-60583L,60584L,60585L,60586L,60587L,60588L,60589L,60590L,60591L,60592L,
-60593L,60594L,60595L,60596L,60597L,60598L,60599L,60600L,60601L,60602L,
-60603L,60604L,60605L,60606L,60607L,60608L,60609L,60610L,60611L,60612L,
-60613L,60614L,60615L,60616L,60617L,60618L,60619L,60620L,60621L,60622L,
-60623L,60624L,60625L,60626L,60627L,60628L,60629L,60630L,60631L,60632L,
-60633L,60634L,60635L,60636L,60637L,60638L,60639L,60640L,60641L,60642L,
-60643L,60644L,60645L,60646L,60647L,60648L,60649L,60650L,60651L,60652L,
-60653L,60654L,60655L,60656L,60657L,60658L,60659L,60660L,60661L,60662L,
-60663L,60664L,60665L,60666L,60667L,60668L,60669L,60670L,60671L,60672L,
-60673L,60674L,60675L,60676L,60677L,60678L,60679L,60680L,60681L,60682L,
-60683L,60684L,60685L,60686L,60687L,60688L,60689L,60690L,60691L,60692L,
-60693L,60694L,60695L,60696L,60697L,60698L,60699L,60700L,60701L,60702L,
-60703L,60704L,60705L,60706L,60707L,60708L,60709L,60710L,60711L,60712L,
-60713L,60714L,60715L,60716L,60717L,60718L,60719L,60720L,60721L,60722L,
-60723L,60724L,60725L,60726L,60727L,60728L,60729L,60730L,60731L,60732L,
-60733L,60734L,60735L,60736L,60737L,60738L,60739L,60740L,60741L,60742L,
-60743L,60744L,60745L,60746L,60747L,60748L,60749L,60750L,60751L,60752L,
-60753L,60754L,60755L,60756L,60757L,60758L,60759L,60760L,60761L,60762L,
-60763L,60764L,60765L,60766L,60767L,60768L,60769L,60770L,60771L,60772L,
-60773L,60774L,60775L,60776L,60777L,60778L,60779L,60780L,60781L,60782L,
-60783L,60784L,60785L,60786L,60787L,60788L,60789L,60790L,60791L,60792L,
-60793L,60794L,60795L,60796L,60797L,60798L,60799L,60800L,60801L,60802L,
-60803L,60804L,60805L,60806L,60807L,60808L,60809L,60810L,60811L,60812L,
-60813L,60814L,60815L,60816L,60817L,60818L,60819L,60820L,60821L,60822L,
-60823L,60824L,60825L,60826L,60827L,60828L,60829L,60830L,60831L,60832L,
-60833L,60834L,60835L,60836L,60837L,60838L,60839L,60840L,60841L,60842L,
-60843L,60844L,60845L,60846L,60847L,60848L,60849L,60850L,60851L,60852L,
-60853L,60854L,60855L,60856L,60857L,60858L,60859L,60860L,60861L,60862L,
-60863L,60864L,60865L,60866L,60867L,60868L,60869L,60870L,60871L,60872L,
-60873L,60874L,60875L,60876L,60877L,60878L,60879L,60880L,60881L,60882L,
-60883L,60884L,60885L,60886L,60887L,60888L,60889L,60890L,60891L,60892L,
-60893L,60894L,60895L,60896L,60897L,60898L,60899L,60900L,60901L,60902L,
-60903L,60904L,60905L,60906L,60907L,60908L,60909L,60910L,60911L,60912L,
-60913L,60914L,60915L,60916L,60917L,60918L,60919L,60920L,60921L,60922L,
-60923L,60924L,60925L,60926L,60927L,60928L,60929L,60930L,60931L,60932L,
-60933L,60934L,60935L,60936L,60937L,60938L,60939L,60940L,60941L,60942L,
-60943L,60944L,60945L,60946L,60947L,60948L,60949L,60950L,60951L,60952L,
-60953L,60954L,60955L,60956L,60957L,60958L,60959L,60960L,60961L,60962L,
-60963L,60964L,60965L,60966L,60967L,60968L,60969L,60970L,60971L,60972L,
-60973L,60974L,60975L,60976L,60977L,60978L,60979L,60980L,60981L,60982L,
-60983L,60984L,60985L,60986L,60987L,60988L,60989L,60990L,60991L,60992L,
-60993L,60994L,60995L,60996L,60997L,60998L,60999L,61000L,61001L,61002L,
-61003L,61004L,61005L,61006L,61007L,61008L,61009L,61010L,61011L,61012L,
-61013L,61014L,61015L,61016L,61017L,61018L,61019L,61020L,61021L,61022L,
-61023L,61024L,61025L,61026L,61027L,61028L,61029L,61030L,61031L,61032L,
-61033L,61034L,61035L,61036L,61037L,61038L,61039L,61040L,61041L,61042L,
-61043L,61044L,61045L,61046L,61047L,61048L,61049L,61050L,61051L,61052L,
-61053L,61054L,61055L,61056L,61057L,61058L,61059L,61060L,61061L,61062L,
-61063L,61064L,61065L,61066L,61067L,61068L,61069L,61070L,61071L,61072L,
-61073L,61074L,61075L,61076L,61077L,61078L,61079L,61080L,61081L,61082L,
-61083L,61084L,61085L,61086L,61087L,61088L,61089L,61090L,61091L,61092L,
-61093L,61094L,61095L,61096L,61097L,61098L,61099L,61100L,61101L,61102L,
-61103L,61104L,61105L,61106L,61107L,61108L,61109L,61110L,61111L,61112L,
-61113L,61114L,61115L,61116L,61117L,61118L,61119L,61120L,61121L,61122L,
-61123L,61124L,61125L,61126L,61127L,61128L,61129L,61130L,61131L,61132L,
-61133L,61134L,61135L,61136L,61137L,61138L,61139L,61140L,61141L,61142L,
-61143L,61144L,61145L,61146L,61147L,61148L,61149L,61150L,61151L,61152L,
-61153L,61154L,61155L,61156L,61157L,61158L,61159L,61160L,61161L,61162L,
-61163L,61164L,61165L,61166L,61167L,61168L,61169L,61170L,61171L,61172L,
-61173L,61174L,61175L,61176L,61177L,61178L,61179L,61180L,61181L,61182L,
-61183L,61184L,61185L,61186L,61187L,61188L,61189L,61190L,61191L,61192L,
-61193L,61194L,61195L,61196L,61197L,61198L,61199L,61200L,61201L,61202L,
-61203L,61204L,61205L,61206L,61207L,61208L,61209L,61210L,61211L,61212L,
-61213L,61214L,61215L,61216L,61217L,61218L,61219L,61220L,61221L,61222L,
-61223L,61224L,61225L,61226L,61227L,61228L,61229L,61230L,61231L,61232L,
-61233L,61234L,61235L,61236L,61237L,61238L,61239L,61240L,61241L,61242L,
-61243L,61244L,61245L,61246L,61247L,61248L,61249L,61250L,61251L,61252L,
-61253L,61254L,61255L,61256L,61257L,61258L,61259L,61260L,61261L,61262L,
-61263L,61264L,61265L,61266L,61267L,61268L,61269L,61270L,61271L,61272L,
-61273L,61274L,61275L,61276L,61277L,61278L,61279L,61280L,61281L,61282L,
-61283L,61284L,61285L,61286L,61287L,61288L,61289L,61290L,61291L,61292L,
-61293L,61294L,61295L,61296L,61297L,61298L,61299L,61300L,61301L,61302L,
-61303L,61304L,61305L,61306L,61307L,61308L,61309L,61310L,61311L,61312L,
-61313L,61314L,61315L,61316L,61317L,61318L,61319L,61320L,61321L,61322L,
-61323L,61324L,61325L,61326L,61327L,61328L,61329L,61330L,61331L,61332L,
-61333L,61334L,61335L,61336L,61337L,61338L,61339L,61340L,61341L,61342L,
-61343L,61344L,61345L,61346L,61347L,61348L,61349L,61350L,61351L,61352L,
-61353L,61354L,61355L,61356L,61357L,61358L,61359L,61360L,61361L,61362L,
-61363L,61364L,61365L,61366L,61367L,61368L,61369L,61370L,61371L,61372L,
-61373L,61374L,61375L,61376L,61377L,61378L,61379L,61380L,61381L,61382L,
-61383L,61384L,61385L,61386L,61387L,61388L,61389L,61390L,61391L,61392L,
-61393L,61394L,61395L,61396L,61397L,61398L,61399L,61400L,61401L,61402L,
-61403L,61404L,61405L,61406L,61407L,61408L,61409L,61410L,61411L,61412L,
-61413L,61414L,61415L,61416L,61417L,61418L,61419L,61420L,61421L,61422L,
-61423L,61424L,61425L,61426L,61427L,61428L,61429L,61430L,61431L,61432L,
-61433L,61434L,61435L,61436L,61437L,61438L,61439L,61440L,61441L,61442L,
-61443L,61444L,61445L,61446L,61447L,61448L,61449L,61450L,61451L,61452L,
-61453L,61454L,61455L,61456L,61457L,61458L,61459L,61460L,61461L,61462L,
-61463L,61464L,61465L,61466L,61467L,61468L,61469L,61470L,61471L,61472L,
-61473L,61474L,61475L,61476L,61477L,61478L,61479L,61480L,61481L,61482L,
-61483L,61484L,61485L,61486L,61487L,61488L,61489L,61490L,61491L,61492L,
-61493L,61494L,61495L,61496L,61497L,61498L,61499L,61500L,61501L,61502L,
-61503L,61504L,61505L,61506L,61507L,61508L,61509L,61510L,61511L,61512L,
-61513L,61514L,61515L,61516L,61517L,61518L,61519L,61520L,61521L,61522L,
-61523L,61524L,61525L,61526L,61527L,61528L,61529L,61530L,61531L,61532L,
-61533L,61534L,61535L,61536L,61537L,61538L,61539L,61540L,61541L,61542L,
-61543L,61544L,61545L,61546L,61547L,61548L,61549L,61550L,61551L,61552L,
-61553L,61554L,61555L,61556L,61557L,61558L,61559L,61560L,61561L,61562L,
-61563L,61564L,61565L,61566L,61567L,61568L,61569L,61570L,61571L,61572L,
-61573L,61574L,61575L,61576L,61577L,61578L,61579L,61580L,61581L,61582L,
-61583L,61584L,61585L,61586L,61587L,61588L,61589L,61590L,61591L,61592L,
-61593L,61594L,61595L,61596L,61597L,61598L,61599L,61600L,61601L,61602L,
-61603L,61604L,61605L,61606L,61607L,61608L,61609L,61610L,61611L,61612L,
-61613L,61614L,61615L,61616L,61617L,61618L,61619L,61620L,61621L,61622L,
-61623L,61624L,61625L,61626L,61627L,61628L,61629L,61630L,61631L,61632L,
-61633L,61634L,61635L,61636L,61637L,61638L,61639L,61640L,61641L,61642L,
-61643L,61644L,61645L,61646L,61647L,61648L,61649L,61650L,61651L,61652L,
-61653L,61654L,61655L,61656L,61657L,61658L,61659L,61660L,61661L,61662L,
-61663L,61664L,61665L,61666L,61667L,61668L,61669L,61670L,61671L,61672L,
-61673L,61674L,61675L,61676L,61677L,61678L,61679L,61680L,61681L,61682L,
-61683L,61684L,61685L,61686L,61687L,61688L,61689L,61690L,61691L,61692L,
-61693L,61694L,61695L,61696L,61697L,61698L,61699L,61700L,61701L,61702L,
-61703L,61704L,61705L,61706L,61707L,61708L,61709L,61710L,61711L,61712L,
-61713L,61714L,61715L,61716L,61717L,61718L,61719L,61720L,61721L,61722L,
-61723L,61724L,61725L,61726L,61727L,61728L,61729L,61730L,61731L,61732L,
-61733L,61734L,61735L,61736L,61737L,61738L,61739L,61740L,61741L,61742L,
-61743L,61744L,61745L,61746L,61747L,61748L,61749L,61750L,61751L,61752L,
-61753L,61754L,61755L,61756L,61757L,61758L,61759L,61760L,61761L,61762L,
-61763L,61764L,61765L,61766L,61767L,61768L,61769L,61770L,61771L,61772L,
-61773L,61774L,61775L,61776L,61777L,61778L,61779L,61780L,61781L,61782L,
-61783L,61784L,61785L,61786L,61787L,61788L,61789L,61790L,61791L,61792L,
-61793L,61794L,61795L,61796L,61797L,61798L,61799L,61800L,61801L,61802L,
-61803L,61804L,61805L,61806L,61807L,61808L,61809L,61810L,61811L,61812L,
-61813L,61814L,61815L,61816L,61817L,61818L,61819L,61820L,61821L,61822L,
-61823L,61824L,61825L,61826L,61827L,61828L,61829L,61830L,61831L,61832L,
-61833L,61834L,61835L,61836L,61837L,61838L,61839L,61840L,61841L,61842L,
-61843L,61844L,61845L,61846L,61847L,61848L,61849L,61850L,61851L,61852L,
-61853L,61854L,61855L,61856L,61857L,61858L,61859L,61860L,61861L,61862L,
-61863L,61864L,61865L,61866L,61867L,61868L,61869L,61870L,61871L,61872L,
-61873L,61874L,61875L,61876L,61877L,61878L,61879L,61880L,61881L,61882L,
-61883L,61884L,61885L,61886L,61887L,61888L,61889L,61890L,61891L,61892L,
-61893L,61894L,61895L,61896L,61897L,61898L,61899L,61900L,61901L,61902L,
-61903L,61904L,61905L,61906L,61907L,61908L,61909L,61910L,61911L,61912L,
-61913L,61914L,61915L,61916L,61917L,61918L,61919L,61920L,61921L,61922L,
-61923L,61924L,61925L,61926L,61927L,61928L,61929L,61930L,61931L,61932L,
-61933L,61934L,61935L,61936L,61937L,61938L,61939L,61940L,61941L,61942L,
-61943L,61944L,61945L,61946L,61947L,61948L,61949L,61950L,61951L,61952L,
-61953L,61954L,61955L,61956L,61957L,61958L,61959L,61960L,61961L,61962L,
-61963L,61964L,61965L,61966L,61967L,61968L,61969L,61970L,61971L,61972L,
-61973L,61974L,61975L,61976L,61977L,61978L,61979L,61980L,61981L,61982L,
-61983L,61984L,61985L,61986L,61987L,61988L,61989L,61990L,61991L,61992L,
-61993L,61994L,61995L,61996L,61997L,61998L,61999L,62000L,62001L,62002L,
-62003L,62004L,62005L,62006L,62007L,62008L,62009L,62010L,62011L,62012L,
-62013L,62014L,62015L,62016L,62017L,62018L,62019L,62020L,62021L,62022L,
-62023L,62024L,62025L,62026L,62027L,62028L,62029L,62030L,62031L,62032L,
-62033L,62034L,62035L,62036L,62037L,62038L,62039L,62040L,62041L,62042L,
-62043L,62044L,62045L,62046L,62047L,62048L,62049L,62050L,62051L,62052L,
-62053L,62054L,62055L,62056L,62057L,62058L,62059L,62060L,62061L,62062L,
-62063L,62064L,62065L,62066L,62067L,62068L,62069L,62070L,62071L,62072L,
-62073L,62074L,62075L,62076L,62077L,62078L,62079L,62080L,62081L,62082L,
-62083L,62084L,62085L,62086L,62087L,62088L,62089L,62090L,62091L,62092L,
-62093L,62094L,62095L,62096L,62097L,62098L,62099L,62100L,62101L,62102L,
-62103L,62104L,62105L,62106L,62107L,62108L,62109L,62110L,62111L,62112L,
-62113L,62114L,62115L,62116L,62117L,62118L,62119L,62120L,62121L,62122L,
-62123L,62124L,62125L,62126L,62127L,62128L,62129L,62130L,62131L,62132L,
-62133L,62134L,62135L,62136L,62137L,62138L,62139L,62140L,62141L,62142L,
-62143L,62144L,62145L,62146L,62147L,62148L,62149L,62150L,62151L,62152L,
-62153L,62154L,62155L,62156L,62157L,62158L,62159L,62160L,62161L,62162L,
-62163L,62164L,62165L,62166L,62167L,62168L,62169L,62170L,62171L,62172L,
-62173L,62174L,62175L,62176L,62177L,62178L,62179L,62180L,62181L,62182L,
-62183L,62184L,62185L,62186L,62187L,62188L,62189L,62190L,62191L,62192L,
-62193L,62194L,62195L,62196L,62197L,62198L,62199L,62200L,62201L,62202L,
-62203L,62204L,62205L,62206L,62207L,62208L,62209L,62210L,62211L,62212L,
-62213L,62214L,62215L,62216L,62217L,62218L,62219L,62220L,62221L,62222L,
-62223L,62224L,62225L,62226L,62227L,62228L,62229L,62230L,62231L,62232L,
-62233L,62234L,62235L,62236L,62237L,62238L,62239L,62240L,62241L,62242L,
-62243L,62244L,62245L,62246L,62247L,62248L,62249L,62250L,62251L,62252L,
-62253L,62254L,62255L,62256L,62257L,62258L,62259L,62260L,62261L,62262L,
-62263L,62264L,62265L,62266L,62267L,62268L,62269L,62270L,62271L,62272L,
-62273L,62274L,62275L,62276L,62277L,62278L,62279L,62280L,62281L,62282L,
-62283L,62284L,62285L,62286L,62287L,62288L,62289L,62290L,62291L,62292L,
-62293L,62294L,62295L,62296L,62297L,62298L,62299L,62300L,62301L,62302L,
-62303L,62304L,62305L,62306L,62307L,62308L,62309L,62310L,62311L,62312L,
-62313L,62314L,62315L,62316L,62317L,62318L,62319L,62320L,62321L,62322L,
-62323L,62324L,62325L,62326L,62327L,62328L,62329L,62330L,62331L,62332L,
-62333L,62334L,62335L,62336L,62337L,62338L,62339L,62340L,62341L,62342L,
-62343L,62344L,62345L,62346L,62347L,62348L,62349L,62350L,62351L,62352L,
-62353L,62354L,62355L,62356L,62357L,62358L,62359L,62360L,62361L,62362L,
-62363L,62364L,62365L,62366L,62367L,62368L,62369L,62370L,62371L,62372L,
-62373L,62374L,62375L,62376L,62377L,62378L,62379L,62380L,62381L,62382L,
-62383L,62384L,62385L,62386L,62387L,62388L,62389L,62390L,62391L,62392L,
-62393L,62394L,62395L,62396L,62397L,62398L,62399L,62400L,62401L,62402L,
-62403L,62404L,62405L,62406L,62407L,62408L,62409L,62410L,62411L,62412L,
-62413L,62414L,62415L,62416L,62417L,62418L,62419L,62420L,62421L,62422L,
-62423L,62424L,62425L,62426L,62427L,62428L,62429L,62430L,62431L,62432L,
-62433L,62434L,62435L,62436L,62437L,62438L,62439L,62440L,62441L,62442L,
-62443L,62444L,62445L,62446L,62447L,62448L,62449L,62450L,62451L,62452L,
-62453L,62454L,62455L,62456L,62457L,62458L,62459L,62460L,62461L,62462L,
-62463L,62464L,62465L,62466L,62467L,62468L,62469L,62470L,62471L,62472L,
-62473L,62474L,62475L,62476L,62477L,62478L,62479L,62480L,62481L,62482L,
-62483L,62484L,62485L,62486L,62487L,62488L,62489L,62490L,62491L,62492L,
-62493L,62494L,62495L,62496L,62497L,62498L,62499L,62500L,62501L,62502L,
-62503L,62504L,62505L,62506L,62507L,62508L,62509L,62510L,62511L,62512L,
-62513L,62514L,62515L,62516L,62517L,62518L,62519L,62520L,62521L,62522L,
-62523L,62524L,62525L,62526L,62527L,62528L,62529L,62530L,62531L,62532L,
-62533L,62534L,62535L,62536L,62537L,62538L,62539L,62540L,62541L,62542L,
-62543L,62544L,62545L,62546L,62547L,62548L,62549L,62550L,62551L,62552L,
-62553L,62554L,62555L,62556L,62557L,62558L,62559L,62560L,62561L,62562L,
-62563L,62564L,62565L,62566L,62567L,62568L,62569L,62570L,62571L,62572L,
-62573L,62574L,62575L,62576L,62577L,62578L,62579L,62580L,62581L,62582L,
-62583L,62584L,62585L,62586L,62587L,62588L,62589L,62590L,62591L,62592L,
-62593L,62594L,62595L,62596L,62597L,62598L,62599L,62600L,62601L,62602L,
-62603L,62604L,62605L,62606L,62607L,62608L,62609L,62610L,62611L,62612L,
-62613L,62614L,62615L,62616L,62617L,62618L,62619L,62620L,62621L,62622L,
-62623L,62624L,62625L,62626L,62627L,62628L,62629L,62630L,62631L,62632L,
-62633L,62634L,62635L,62636L,62637L,62638L,62639L,62640L,62641L,62642L,
-62643L,62644L,62645L,62646L,62647L,62648L,62649L,62650L,62651L,62652L,
-62653L,62654L,62655L,62656L,62657L,62658L,62659L,62660L,62661L,62662L,
-62663L,62664L,62665L,62666L,62667L,62668L,62669L,62670L,62671L,62672L,
-62673L,62674L,62675L,62676L,62677L,62678L,62679L,62680L,62681L,62682L,
-62683L,62684L,62685L,62686L,62687L,62688L,62689L,62690L,62691L,62692L,
-62693L,62694L,62695L,62696L,62697L,62698L,62699L,62700L,62701L,62702L,
-62703L,62704L,62705L,62706L,62707L,62708L,62709L,62710L,62711L,62712L,
-62713L,62714L,62715L,62716L,62717L,62718L,62719L,62720L,62721L,62722L,
-62723L,62724L,62725L,62726L,62727L,62728L,62729L,62730L,62731L,62732L,
-62733L,62734L,62735L,62736L,62737L,62738L,62739L,62740L,62741L,62742L,
-62743L,62744L,62745L,62746L,62747L,62748L,62749L,62750L,62751L,62752L,
-62753L,62754L,62755L,62756L,62757L,62758L,62759L,62760L,62761L,62762L,
-62763L,62764L,62765L,62766L,62767L,62768L,62769L,62770L,62771L,62772L,
-62773L,62774L,62775L,62776L,62777L,62778L,62779L,62780L,62781L,62782L,
-62783L,62784L,62785L,62786L,62787L,62788L,62789L,62790L,62791L,62792L,
-62793L,62794L,62795L,62796L,62797L,62798L,62799L,62800L,62801L,62802L,
-62803L,62804L,62805L,62806L,62807L,62808L,62809L,62810L,62811L,62812L,
-62813L,62814L,62815L,62816L,62817L,62818L,62819L,62820L,62821L,62822L,
-62823L,62824L,62825L,62826L,62827L,62828L,62829L,62830L,62831L,62832L,
-62833L,62834L,62835L,62836L,62837L,62838L,62839L,62840L,62841L,62842L,
-62843L,62844L,62845L,62846L,62847L,62848L,62849L,62850L,62851L,62852L,
-62853L,62854L,62855L,62856L,62857L,62858L,62859L,62860L,62861L,62862L,
-62863L,62864L,62865L,62866L,62867L,62868L,62869L,62870L,62871L,62872L,
-62873L,62874L,62875L,62876L,62877L,62878L,62879L,62880L,62881L,62882L,
-62883L,62884L,62885L,62886L,62887L,62888L,62889L,62890L,62891L,62892L,
-62893L,62894L,62895L,62896L,62897L,62898L,62899L,62900L,62901L,62902L,
-62903L,62904L,62905L,62906L,62907L,62908L,62909L,62910L,62911L,62912L,
-62913L,62914L,62915L,62916L,62917L,62918L,62919L,62920L,62921L,62922L,
-62923L,62924L,62925L,62926L,62927L,62928L,62929L,62930L,62931L,62932L,
-62933L,62934L,62935L,62936L,62937L,62938L,62939L,62940L,62941L,62942L,
-62943L,62944L,62945L,62946L,62947L,62948L,62949L,62950L,62951L,62952L,
-62953L,62954L,62955L,62956L,62957L,62958L,62959L,62960L,62961L,62962L,
-62963L,62964L,62965L,62966L,62967L,62968L,62969L,62970L,62971L,62972L,
-62973L,62974L,62975L,62976L,62977L,62978L,62979L,62980L,62981L,62982L,
-62983L,62984L,62985L,62986L,62987L,62988L,62989L,62990L,62991L,62992L,
-62993L,62994L,62995L,62996L,62997L,62998L,62999L,63000L,63001L,63002L,
-63003L,63004L,63005L,63006L,63007L,63008L,63009L,63010L,63011L,63012L,
-63013L,63014L,63015L,63016L,63017L,63018L,63019L,63020L,63021L,63022L,
-63023L,63024L,63025L,63026L,63027L,63028L,63029L,63030L,63031L,63032L,
-63033L,63034L,63035L,63036L,63037L,63038L,63039L,63040L,63041L,63042L,
-63043L,63044L,63045L,63046L,63047L,63048L,63049L,63050L,63051L,63052L,
-63053L,63054L,63055L,63056L,63057L,63058L,63059L,63060L,63061L,63062L,
-63063L,63064L,63065L,63066L,63067L,63068L,63069L,63070L,63071L,63072L,
-63073L,63074L,63075L,63076L,63077L,63078L,63079L,63080L,63081L,63082L,
-63083L,63084L,63085L,63086L,63087L,63088L,63089L,63090L,63091L,63092L,
-63093L,63094L,63095L,63096L,63097L,63098L,63099L,63100L,63101L,63102L,
-63103L,63104L,63105L,63106L,63107L,63108L,63109L,63110L,63111L,63112L,
-63113L,63114L,63115L,63116L,63117L,63118L,63119L,63120L,63121L,63122L,
-63123L,63124L,63125L,63126L,63127L,63128L,63129L,63130L,63131L,63132L,
-63133L,63134L,63135L,63136L,63137L,63138L,63139L,63140L,63141L,63142L,
-63143L,63144L,63145L,63146L,63147L,63148L,63149L,63150L,63151L,63152L,
-63153L,63154L,63155L,63156L,63157L,63158L,63159L,63160L,63161L,63162L,
-63163L,63164L,63165L,63166L,63167L,63168L,63169L,63170L,63171L,63172L,
-63173L,63174L,63175L,63176L,63177L,63178L,63179L,63180L,63181L,63182L,
-63183L,63184L,63185L,63186L,63187L,63188L,63189L,63190L,63191L,63192L,
-63193L,63194L,63195L,63196L,63197L,63198L,63199L,63200L,63201L,63202L,
-63203L,63204L,63205L,63206L,63207L,63208L,63209L,63210L,63211L,63212L,
-63213L,63214L,63215L,63216L,63217L,63218L,63219L,63220L,63221L,63222L,
-63223L,63224L,63225L,63226L,63227L,63228L,63229L,63230L,63231L,63232L,
-63233L,63234L,63235L,63236L,63237L,63238L,63239L,63240L,63241L,63242L,
-63243L,63244L,63245L,63246L,63247L,63248L,63249L,63250L,63251L,63252L,
-63253L,63254L,63255L,63256L,63257L,63258L,63259L,63260L,63261L,63262L,
-63263L,63264L,63265L,63266L,63267L,63268L,63269L,63270L,63271L,63272L,
-63273L,63274L,63275L,63276L,63277L,63278L,63279L,63280L,63281L,63282L,
-63283L,63284L,63285L,63286L,63287L,63288L,63289L,63290L,63291L,63292L,
-63293L,63294L,63295L,63296L,63297L,63298L,63299L,63300L,63301L,63302L,
-63303L,63304L,63305L,63306L,63307L,63308L,63309L,63310L,63311L,63312L,
-63313L,63314L,63315L,63316L,63317L,63318L,63319L,63320L,63321L,63322L,
-63323L,63324L,63325L,63326L,63327L,63328L,63329L,63330L,63331L,63332L,
-63333L,63334L,63335L,63336L,63337L,63338L,63339L,63340L,63341L,63342L,
-63343L,63344L,63345L,63346L,63347L,63348L,63349L,63350L,63351L,63352L,
-63353L,63354L,63355L,63356L,63357L,63358L,63359L,63360L,63361L,63362L,
-63363L,63364L,63365L,63366L,63367L,63368L,63369L,63370L,63371L,63372L,
-63373L,63374L,63375L,63376L,63377L,63378L,63379L,63380L,63381L,63382L,
-63383L,63384L,63385L,63386L,63387L,63388L,63389L,63390L,63391L,63392L,
-63393L,63394L,63395L,63396L,63397L,63398L,63399L,63400L,63401L,63402L,
-63403L,63404L,63405L,63406L,63407L,63408L,63409L,63410L,63411L,63412L,
-63413L,63414L,63415L,63416L,63417L,63418L,63419L,63420L,63421L,63422L,
-63423L,63424L,63425L,63426L,63427L,63428L,63429L,63430L,63431L,63432L,
-63433L,63434L,63435L,63436L,63437L,63438L,63439L,63440L,63441L,63442L,
-63443L,63444L,63445L,63446L,63447L,63448L,63449L,63450L,63451L,63452L,
-63453L,63454L,63455L,63456L,63457L,63458L,63459L,63460L,63461L,63462L,
-63463L,63464L,63465L,63466L,63467L,63468L,63469L,63470L,63471L,63472L,
-63473L,63474L,63475L,63476L,63477L,63478L,63479L,63480L,63481L,63482L,
-63483L,63484L,63485L,63486L,63487L,63488L,63489L,63490L,63491L,63492L,
-63493L,63494L,63495L,63496L,63497L,63498L,63499L,63500L,63501L,63502L,
-63503L,63504L,63505L,63506L,63507L,63508L,63509L,63510L,63511L,63512L,
-63513L,63514L,63515L,63516L,63517L,63518L,63519L,63520L,63521L,63522L,
-63523L,63524L,63525L,63526L,63527L,63528L,63529L,63530L,63531L,63532L,
-63533L,63534L,63535L,63536L,63537L,63538L,63539L,63540L,63541L,63542L,
-63543L,63544L,63545L,63546L,63547L,63548L,63549L,63550L,63551L,63552L,
-63553L,63554L,63555L,63556L,63557L,63558L,63559L,63560L,63561L,63562L,
-63563L,63564L,63565L,63566L,63567L,63568L,63569L,63570L,63571L,63572L,
-63573L,63574L,63575L,63576L,63577L,63578L,63579L,63580L,63581L,63582L,
-63583L,63584L,63585L,63586L,63587L,63588L,63589L,63590L,63591L,63592L,
-63593L,63594L,63595L,63596L,63597L,63598L,63599L,63600L,63601L,63602L,
-63603L,63604L,63605L,63606L,63607L,63608L,63609L,63610L,63611L,63612L,
-63613L,63614L,63615L,63616L,63617L,63618L,63619L,63620L,63621L,63622L,
-63623L,63624L,63625L,63626L,63627L,63628L,63629L,63630L,63631L,63632L,
-63633L,63634L,63635L,63636L,63637L,63638L,63639L,63640L,63641L,63642L,
-63643L,63644L,63645L,63646L,63647L,63648L,63649L,63650L,63651L,63652L,
-63653L,63654L,63655L,63656L,63657L,63658L,63659L,63660L,63661L,63662L,
-63663L,63664L,63665L,63666L,63667L,63668L,63669L,63670L,63671L,63672L,
-63673L,63674L,63675L,63676L,63677L,63678L,63679L,63680L,63681L,63682L,
-63683L,63684L,63685L,63686L,63687L,63688L,63689L,63690L,63691L,63692L,
-63693L,63694L,63695L,63696L,63697L,63698L,63699L,63700L,63701L,63702L,
-63703L,63704L,63705L,63706L,63707L,63708L,63709L,63710L,63711L,63712L,
-63713L,63714L,63715L,63716L,63717L,63718L,63719L,63720L,63721L,63722L,
-63723L,63724L,63725L,63726L,63727L,63728L,63729L,63730L,63731L,63732L,
-63733L,63734L,63735L,63736L,63737L,63738L,63739L,63740L,63741L,63742L,
-63743L,63744L,63745L,63746L,63747L,63748L,63749L,63750L,63751L,63752L,
-63753L,63754L,63755L,63756L,63757L,63758L,63759L,63760L,63761L,63762L,
-63763L,63764L,63765L,63766L,63767L,63768L,63769L,63770L,63771L,63772L,
-63773L,63774L,63775L,63776L,63777L,63778L,63779L,63780L,63781L,63782L,
-63783L,63784L,63785L,63786L,63787L,63788L,63789L,63790L,63791L,63792L,
-63793L,63794L,63795L,63796L,63797L,63798L,63799L,63800L,63801L,63802L,
-63803L,63804L,63805L,63806L,63807L,63808L,63809L,63810L,63811L,63812L,
-63813L,63814L,63815L,63816L,63817L,63818L,63819L,63820L,63821L,63822L,
-63823L,63824L,63825L,63826L,63827L,63828L,63829L,63830L,63831L,63832L,
-63833L,63834L,63835L,63836L,63837L,63838L,63839L,63840L,63841L,63842L,
-63843L,63844L,63845L,63846L,63847L,63848L,63849L,63850L,63851L,63852L,
-63853L,63854L,63855L,63856L,63857L,63858L,63859L,63860L,63861L,63862L,
-63863L,63864L,63865L,63866L,63867L,63868L,63869L,63870L,63871L,63872L,
-63873L,63874L,63875L,63876L,63877L,63878L,63879L,63880L,63881L,63882L,
-63883L,63884L,63885L,63886L,63887L,63888L,63889L,63890L,63891L,63892L,
-63893L,63894L,63895L,63896L,63897L,63898L,63899L,63900L,63901L,63902L,
-63903L,63904L,63905L,63906L,63907L,63908L,63909L,63910L,63911L,63912L,
-63913L,63914L,63915L,63916L,63917L,63918L,63919L,63920L,63921L,63922L,
-63923L,63924L,63925L,63926L,63927L,63928L,63929L,63930L,63931L,63932L,
-63933L,63934L,63935L,63936L,63937L,63938L,63939L,63940L,63941L,63942L,
-63943L,63944L,63945L,63946L,63947L,63948L,63949L,63950L,63951L,63952L,
-63953L,63954L,63955L,63956L,63957L,63958L,63959L,63960L,63961L,63962L,
-63963L,63964L,63965L,63966L,63967L,63968L,63969L,63970L,63971L,63972L,
-63973L,63974L,63975L,63976L,63977L,63978L,63979L,63980L,63981L,63982L,
-63983L,63984L,63985L,63986L,63987L,63988L,63989L,63990L,63991L,63992L,
-63993L,63994L,63995L,63996L,63997L,63998L,63999L,64000L,64001L,64002L,
-64003L,64004L,64005L,64006L,64007L,64008L,64009L,64010L,64011L,64012L,
-64013L,64014L,64015L,64016L,64017L,64018L,64019L,64020L,64021L,64022L,
-64023L,64024L,64025L,64026L,64027L,64028L,64029L,64030L,64031L,64032L,
-64033L,64034L,64035L,64036L,64037L,64038L,64039L,64040L,64041L,64042L,
-64043L,64044L,64045L,64046L,64047L,64048L,64049L,64050L,64051L,64052L,
-64053L,64054L,64055L,64056L,64057L,64058L,64059L,64060L,64061L,64062L,
-64063L,64064L,64065L,64066L,64067L,64068L,64069L,64070L,64071L,64072L,
-64073L,64074L,64075L,64076L,64077L,64078L,64079L,64080L,64081L,64082L,
-64083L,64084L,64085L,64086L,64087L,64088L,64089L,64090L,64091L,64092L,
-64093L,64094L,64095L,64096L,64097L,64098L,64099L,64100L,64101L,64102L,
-64103L,64104L,64105L,64106L,64107L,64108L,64109L,64110L,64111L,64112L,
-64113L,64114L,64115L,64116L,64117L,64118L,64119L,64120L,64121L,64122L,
-64123L,64124L,64125L,64126L,64127L,64128L,64129L,64130L,64131L,64132L,
-64133L,64134L,64135L,64136L,64137L,64138L,64139L,64140L,64141L,64142L,
-64143L,64144L,64145L,64146L,64147L,64148L,64149L,64150L,64151L,64152L,
-64153L,64154L,64155L,64156L,64157L,64158L,64159L,64160L,64161L,64162L,
-64163L,64164L,64165L,64166L,64167L,64168L,64169L,64170L,64171L,64172L,
-64173L,64174L,64175L,64176L,64177L,64178L,64179L,64180L,64181L,64182L,
-64183L,64184L,64185L,64186L,64187L,64188L,64189L,64190L,64191L,64192L,
-64193L,64194L,64195L,64196L,64197L,64198L,64199L,64200L,64201L,64202L,
-64203L,64204L,64205L,64206L,64207L,64208L,64209L,64210L,64211L,64212L,
-64213L,64214L,64215L,64216L,64217L,64218L,64219L,64220L,64221L,64222L,
-64223L,64224L,64225L,64226L,64227L,64228L,64229L,64230L,64231L,64232L,
-64233L,64234L,64235L,64236L,64237L,64238L,64239L,64240L,64241L,64242L,
-64243L,64244L,64245L,64246L,64247L,64248L,64249L,64250L,64251L,64252L,
-64253L,64254L,64255L,64256L,64257L,64258L,64259L,64260L,64261L,64262L,
-64263L,64264L,64265L,64266L,64267L,64268L,64269L,64270L,64271L,64272L,
-64273L,64274L,64275L,64276L,64277L,64278L,64279L,64280L,64281L,64282L,
-64283L,64284L,64285L,64286L,64287L,64288L,64289L,64290L,64291L,64292L,
-64293L,64294L,64295L,64296L,64297L,64298L,64299L,64300L,64301L,64302L,
-64303L,64304L,64305L,64306L,64307L,64308L,64309L,64310L,64311L,64312L,
-64313L,64314L,64315L,64316L,64317L,64318L,64319L,64320L,64321L,64322L,
-64323L,64324L,64325L,64326L,64327L,64328L,64329L,64330L,64331L,64332L,
-64333L,64334L,64335L,64336L,64337L,64338L,64339L,64340L,64341L,64342L,
-64343L,64344L,64345L,64346L,64347L,64348L,64349L,64350L,64351L,64352L,
-64353L,64354L,64355L,64356L,64357L,64358L,64359L,64360L,64361L,64362L,
-64363L,64364L,64365L,64366L,64367L,64368L,64369L,64370L,64371L,64372L,
-64373L,64374L,64375L,64376L,64377L,64378L,64379L,64380L,64381L,64382L,
-64383L,64384L,64385L,64386L,64387L,64388L,64389L,64390L,64391L,64392L,
-64393L,64394L,64395L,64396L,64397L,64398L,64399L,64400L,64401L,64402L,
-64403L,64404L,64405L,64406L,64407L,64408L,64409L,64410L,64411L,64412L,
-64413L,64414L,64415L,64416L,64417L,64418L,64419L,64420L,64421L,64422L,
-64423L,64424L,64425L,64426L,64427L,64428L,64429L,64430L,64431L,64432L,
-64433L,64434L,64435L,64436L,64437L,64438L,64439L,64440L,64441L,64442L,
-64443L,64444L,64445L,64446L,64447L,64448L,64449L,64450L,64451L,64452L,
-64453L,64454L,64455L,64456L,64457L,64458L,64459L,64460L,64461L,64462L,
-64463L,64464L,64465L,64466L,64467L,64468L,64469L,64470L,64471L,64472L,
-64473L,64474L,64475L,64476L,64477L,64478L,64479L,64480L,64481L,64482L,
-64483L,64484L,64485L,64486L,64487L,64488L,64489L,64490L,64491L,64492L,
-64493L,64494L,64495L,64496L,64497L,64498L,64499L,64500L,64501L,64502L,
-64503L,64504L,64505L,64506L,64507L,64508L,64509L,64510L,64511L,64512L,
-64513L,64514L,64515L,64516L,64517L,64518L,64519L,64520L,64521L,64522L,
-64523L,64524L,64525L,64526L,64527L,64528L,64529L,64530L,64531L,64532L,
-64533L,64534L,64535L,64536L,64537L,64538L,64539L,64540L,64541L,64542L,
-64543L,64544L,64545L,64546L,64547L,64548L,64549L,64550L,64551L,64552L,
-64553L,64554L,64555L,64556L,64557L,64558L,64559L,64560L,64561L,64562L,
-64563L,64564L,64565L,64566L,64567L,64568L,64569L,64570L,64571L,64572L,
-64573L,64574L,64575L,64576L,64577L,64578L,64579L,64580L,64581L,64582L,
-64583L,64584L,64585L,64586L,64587L,64588L,64589L,64590L,64591L,64592L,
-64593L,64594L,64595L,64596L,64597L,64598L,64599L,64600L,64601L,64602L,
-64603L,64604L,64605L,64606L,64607L,64608L,64609L,64610L,64611L,64612L,
-64613L,64614L,64615L,64616L,64617L,64618L,64619L,64620L,64621L,64622L,
-64623L,64624L,64625L,64626L,64627L,64628L,64629L,64630L,64631L,64632L,
-64633L,64634L,64635L,64636L,64637L,64638L,64639L,64640L,64641L,64642L,
-64643L,64644L,64645L,64646L,64647L,64648L,64649L,64650L,64651L,64652L,
-64653L,64654L,64655L,64656L,64657L,64658L,64659L,64660L,64661L,64662L,
-64663L,64664L,64665L,64666L,64667L,64668L,64669L,64670L,64671L,64672L,
-64673L,64674L,64675L,64676L,64677L,64678L,64679L,64680L,64681L,64682L,
-64683L,64684L,64685L,64686L,64687L,64688L,64689L,64690L,64691L,64692L,
-64693L,64694L,64695L,64696L,64697L,64698L,64699L,64700L,64701L,64702L,
-64703L,64704L,64705L,64706L,64707L,64708L,64709L,64710L,64711L,64712L,
-64713L,64714L,64715L,64716L,64717L,64718L,64719L,64720L,64721L,64722L,
-64723L,64724L,64725L,64726L,64727L,64728L,64729L,64730L,64731L,64732L,
-64733L,64734L,64735L,64736L,64737L,64738L,64739L,64740L,64741L,64742L,
-64743L,64744L,64745L,64746L,64747L,64748L,64749L,64750L,64751L,64752L,
-64753L,64754L,64755L,64756L,64757L,64758L,64759L,64760L,64761L,64762L,
-64763L,64764L,64765L,64766L,64767L,64768L,64769L,64770L,64771L,64772L,
-64773L,64774L,64775L,64776L,64777L,64778L,64779L,64780L,64781L,64782L,
-64783L,64784L,64785L,64786L,64787L,64788L,64789L,64790L,64791L,64792L,
-64793L,64794L,64795L,64796L,64797L,64798L,64799L,64800L,64801L,64802L,
-64803L,64804L,64805L,64806L,64807L,64808L,64809L,64810L,64811L,64812L,
-64813L,64814L,64815L,64816L,64817L,64818L,64819L,64820L,64821L,64822L,
-64823L,64824L,64825L,64826L,64827L,64828L,64829L,64830L,64831L,64832L,
-64833L,64834L,64835L,64836L,64837L,64838L,64839L,64840L,64841L,64842L,
-64843L,64844L,64845L,64846L,64847L,64848L,64849L,64850L,64851L,64852L,
-64853L,64854L,64855L,64856L,64857L,64858L,64859L,64860L,64861L,64862L,
-64863L,64864L,64865L,64866L,64867L,64868L,64869L,64870L,64871L,64872L,
-64873L,64874L,64875L,64876L,64877L,64878L,64879L,64880L,64881L,64882L,
-64883L,64884L,64885L,64886L,64887L,64888L,64889L,64890L,64891L,64892L,
-64893L,64894L,64895L,64896L,64897L,64898L,64899L,64900L,64901L,64902L,
-64903L,64904L,64905L,64906L,64907L,64908L,64909L,64910L,64911L,64912L,
-64913L,64914L,64915L,64916L,64917L,64918L,64919L,64920L,64921L,64922L,
-64923L,64924L,64925L,64926L,64927L,64928L,64929L,64930L,64931L,64932L,
-64933L,64934L,64935L,64936L,64937L,64938L,64939L,64940L,64941L,64942L,
-64943L,64944L,64945L,64946L,64947L,64948L,64949L,64950L,64951L,64952L,
-64953L,64954L,64955L,64956L,64957L,64958L,64959L,64960L,64961L,64962L,
-64963L,64964L,64965L,64966L,64967L,64968L,64969L,64970L,64971L,64972L,
-64973L,64974L,64975L,64976L,64977L,64978L,64979L,64980L,64981L,64982L,
-64983L,64984L,64985L,64986L,64987L,64988L,64989L,64990L,64991L,64992L,
-64993L,64994L,64995L,64996L,64997L,64998L,64999L,65000L,65001L,65002L,
-65003L,65004L,65005L,65006L,65007L,65008L,65009L,65010L,65011L,65012L,
-65013L,65014L,65015L,65016L,65017L,65018L,65019L,65020L,65021L,65022L,
-65023L,65024L,65025L,65026L,65027L,65028L,65029L,65030L,65031L,65032L,
-65033L,65034L,65035L,65036L,65037L,65038L,65039L,65040L,65041L,65042L,
-65043L,65044L,65045L,65046L,65047L,65048L,65049L,65050L,65051L,65052L,
-65053L,65054L,65055L,65056L,65057L,65058L,65059L,65060L,65061L,65062L,
-65063L,65064L,65065L,65066L,65067L,65068L,65069L,65070L,65071L,65072L,
-65073L,65074L,65075L,65076L,65077L,65078L,65079L,65080L,65081L,65082L,
-65083L,65084L,65085L,65086L,65087L,65088L,65089L,65090L,65091L,65092L,
-65093L,65094L,65095L,65096L,65097L,65098L,65099L,65100L,65101L,65102L,
-65103L,65104L,65105L,65106L,65107L,65108L,65109L,65110L,65111L,65112L,
-65113L,65114L,65115L,65116L,65117L,65118L,65119L,65120L,65121L,65122L,
-65123L,65124L,65125L,65126L,65127L,65128L,65129L,65130L,65131L,65132L,
-65133L,65134L,65135L,65136L,65137L,65138L,65139L,65140L,65141L,65142L,
-65143L,65144L,65145L,65146L,65147L,65148L,65149L,65150L,65151L,65152L,
-65153L,65154L,65155L,65156L,65157L,65158L,65159L,65160L,65161L,65162L,
-65163L,65164L,65165L,65166L,65167L,65168L,65169L,65170L,65171L,65172L,
-65173L,65174L,65175L,65176L,65177L,65178L,65179L,65180L,65181L,65182L,
-65183L,65184L,65185L,65186L,65187L,65188L,65189L,65190L,65191L,65192L,
-65193L,65194L,65195L,65196L,65197L,65198L,65199L,65200L,65201L,65202L,
-65203L,65204L,65205L,65206L,65207L,65208L,65209L,65210L,65211L,65212L,
-65213L,65214L,65215L,65216L,65217L,65218L,65219L,65220L,65221L,65222L,
-65223L,65224L,65225L,65226L,65227L,65228L,65229L,65230L,65231L,65232L,
-65233L,65234L,65235L,65236L,65237L,65238L,65239L,65240L,65241L,65242L,
-65243L,65244L,65245L,65246L,65247L,65248L,65249L,65250L,65251L,65252L,
-65253L,65254L,65255L,65256L,65257L,65258L,65259L,65260L,65261L,65262L,
-65263L,65264L,65265L,65266L,65267L,65268L,65269L,65270L,65271L,65272L,
-65273L,65274L,65275L,65276L,65277L,65278L,65279L,65280L,65281L,65282L,
-65283L,65284L,65285L,65286L,65287L,65288L,65289L,65290L,65291L,65292L,
-65293L,65294L,65295L,65296L,65297L,65298L,65299L,65300L,65301L,65302L,
-65303L,65304L,65305L,65306L,65307L,65308L,65309L,65310L,65311L,65312L,
-65313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,65321L,65322L,
-65323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,65331L,65332L,
-65333L,65334L,65335L,65336L,65337L,65338L,65339L,65340L,65341L,65342L,
-65343L,65344L,65313L,65314L,65315L,65316L,65317L,65318L,65319L,65320L,
-65321L,65322L,65323L,65324L,65325L,65326L,65327L,65328L,65329L,65330L,
-65331L,65332L,65333L,65334L,65335L,65336L,65337L,65338L,65371L,65372L,
-65373L,65374L,65375L,65376L,65377L,65378L,65379L,65380L,65381L,65382L,
-65383L,65384L,65385L,65386L,65387L,65388L,65389L,65390L,65391L,65392L,
-65393L,65394L,65395L,65396L,65397L,65398L,65399L,65400L,65401L,65402L,
-65403L,65404L,65405L,65406L,65407L,65408L,65409L,65410L,65411L,65412L,
-65413L,65414L,65415L,65416L,65417L,65418L,65419L,65420L,65421L,65422L,
-65423L,65424L,65425L,65426L,65427L,65428L,65429L,65430L,65431L,65432L,
-65433L,65434L,65435L,65436L,65437L,65438L,65439L,65440L,65441L,65442L,
-65443L,65444L,65445L,65446L,65447L,65448L,65449L,65450L,65451L,65452L,
-65453L,65454L,65455L,65456L,65457L,65458L,65459L,65460L,65461L,65462L,
-65463L,65464L,65465L,65466L,65467L,65468L,65469L,65470L,65471L,65472L,
-65473L,65474L,65475L,65476L,65477L,65478L,65479L,65480L,65481L,65482L,
-65483L,65484L,65485L,65486L,65487L,65488L,65489L,65490L,65491L,65492L,
-65493L,65494L,65495L,65496L,65497L,65498L,65499L,65500L,65501L,65502L,
-65503L,65504L,65505L,65506L,65507L,65508L,65509L,65510L,65511L,65512L,
-65513L,65514L,65515L,65516L,65517L,65518L,65519L,65520L,65521L,65522L,
-65523L,65524L,65525L,65526L,65527L,65528L,65529L,65530L,65531L,65532L,
-65533L,65534L,65535L,
-};
-#endif
-#line 1 "duk_util_bitdecoder.c"
-/*
- * Bitstream decoder.
- */
-
-/* include removed: duk_internal.h */
-
-/* Decode 'bits' bits from the input stream (bits must be 1...24).
- * When reading past bitstream end, zeroes are shifted in. The result
- * is signed to match duk_bd_decode_flagged.
- */
-DUK_INTERNAL duk_int32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
- duk_small_int_t shift;
- duk_uint32_t mask;
- duk_uint32_t tmp;
-
- /* Note: cannot read more than 24 bits without possibly shifting top bits out.
- * Fixable, but adds complexity.
- */
- DUK_ASSERT(bits >= 1 && bits <= 24);
-
- while (ctx->currbits < bits) {
-#if 0
- DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)",
- (long) bits, (long) ctx->currbits));
-#endif
- ctx->currval <<= 8;
- if (ctx->offset < ctx->length) {
- /* If ctx->offset >= ctx->length, we "shift zeroes in"
- * instead of croaking.
- */
- ctx->currval |= ctx->data[ctx->offset++];
- }
- ctx->currbits += 8;
- }
-#if 0
- DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx",
- (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval));
-#endif
-
- /* Extract 'top' bits of currval; note that the extracted bits do not need
- * to be cleared, we just ignore them on next round.
- */
- shift = ctx->currbits - bits;
- mask = (1 << bits) - 1;
- tmp = (ctx->currval >> shift) & mask;
- ctx->currbits = shift; /* remaining */
-
-#if 0
- DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx",
- (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval));
-#endif
-
- return tmp;
-}
-
-DUK_INTERNAL duk_small_int_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
- return (duk_small_int_t) duk_bd_decode(ctx, 1);
-}
-
-/* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
- * default value. Return value is signed so that negative marker value can be
- * used by caller as a "not present" value.
- */
-DUK_INTERNAL duk_int32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_int32_t def_value) {
- if (duk_bd_decode_flag(ctx)) {
- return (duk_int32_t) duk_bd_decode(ctx, bits);
- } else {
- return def_value;
- }
-}
-#line 1 "duk_util_bitencoder.c"
-/*
- * Bitstream encoder.
- */
-
-/* include removed: duk_internal.h */
-
-DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) {
- duk_uint8_t tmp;
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(ctx->currbits < 8);
-
- /* This limitation would be fixable but adds unnecessary complexity. */
- DUK_ASSERT(bits >= 1 && bits <= 24);
-
- ctx->currval = (ctx->currval << bits) | data;
- ctx->currbits += bits;
-
- while (ctx->currbits >= 8) {
- if (ctx->offset < ctx->length) {
- tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff);
- ctx->data[ctx->offset++] = tmp;
- } else {
- /* If buffer has been exhausted, truncate bitstream */
- ctx->truncated = 1;
- }
-
- ctx->currbits -= 8;
- }
-}
-
-DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) {
- duk_small_int_t npad;
-
- DUK_ASSERT(ctx != NULL);
- DUK_ASSERT(ctx->currbits < 8);
-
- npad = (duk_small_int_t) (8 - ctx->currbits);
- if (npad > 0) {
- duk_be_encode(ctx, 0, npad);
- }
- DUK_ASSERT(ctx->currbits == 0);
-}
-#line 1 "duk_util_bufwriter.c"
-/*
- * Fast buffer writer with spare management.
- */
-
-/* include removed: duk_internal.h */
-
-/*
- * Macro support functions (use only macros in calling code)
- */
-
-DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t curr_offset, duk_size_t new_length) {
- duk_uint8_t *p;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw_ctx != NULL);
- DUK_UNREF(thr);
-
- p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf);
- DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0));
- bw_ctx->p = p + curr_offset;
- bw_ctx->p_base = p;
- bw_ctx->p_limit = p + new_length;
-}
-
-DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) {
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw_ctx != NULL);
- DUK_ASSERT(h_buf != NULL);
- DUK_UNREF(thr);
-
- bw_ctx->buf = h_buf;
- duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf));
-}
-
-DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) {
- duk_context *ctx;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw_ctx != NULL);
- ctx = (duk_context *) thr;
-
- (void) duk_push_dynamic_buffer(ctx, buf_size);
- bw_ctx->buf = (duk_hbuffer_dynamic *) duk_get_hbuffer(ctx, -1);
- duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
-}
-
-/* Resize target buffer for requested size. Called by the macro only when the
- * fast path test (= there is space) fails.
- */
-DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz) {
- duk_size_t curr_off;
- duk_size_t add_sz;
- duk_size_t new_sz;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw_ctx != NULL);
-
- /* We could do this operation without caller updating bw_ctx->ptr,
- * but by writing it back here we can share code better.
- */
-
- curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
- add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD;
- new_sz = curr_off + sz + add_sz;
- if (new_sz < curr_off) {
- /* overflow */
- DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
- return NULL; /* not reachable */
- }
-#if 0 /* for manual torture testing: tight allocation, useful with valgrind */
- new_sz = curr_off + sz;
-#endif
-
- /* This is important to ensure dynamic buffer data pointer is not
- * NULL (which is possible if buffer size is zero), which in turn
- * causes portability issues with e.g. memmove() and memcpy().
- */
- DUK_ASSERT(new_sz >= 1);
-
- DUK_DD(DUK_DDPRINT("resize bufferwriter from %ld to %ld (add_sz=%ld)", (long) curr_off, (long) new_sz, (long) add_sz));
-
- duk_hbuffer_resize(thr, bw_ctx->buf, new_sz);
- duk__bw_update_ptrs(thr, bw_ctx, curr_off, new_sz);
- return bw_ctx->p;
-}
-
-/* Make buffer compact, matching current written size. */
-DUK_INTERNAL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) {
- duk_size_t len;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw_ctx != NULL);
- DUK_UNREF(thr);
-
- len = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
- duk_hbuffer_resize(thr, bw_ctx->buf, len);
- duk__bw_update_ptrs(thr, bw_ctx, len, len);
-}
-
-DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
- duk_uint8_t *p_base;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
-
- p_base = bw->p_base;
- DUK_MEMCPY((void *) bw->p,
- (const void *) (p_base + src_off),
- (size_t) len);
- bw->p += len;
-}
-
-DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
-
- DUK_BW_ENSURE(thr, bw, len);
- duk_bw_write_raw_slice(thr, bw, src_off, len);
-}
-
-DUK_INTERNAL void duk_bw_insert_raw_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len) {
- duk_uint8_t *p_base;
- duk_size_t buf_sz, move_sz;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(buf != NULL);
- DUK_UNREF(thr);
-
- p_base = bw->p_base;
- buf_sz = bw->p - p_base;
- move_sz = buf_sz - dst_off;
-
- DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
- DUK_MEMMOVE((void *) (p_base + dst_off + len),
- (const void *) (p_base + dst_off),
- (size_t) move_sz);
- DUK_MEMCPY((void *) (p_base + dst_off),
- (const void *) buf,
- (size_t) len);
- bw->p += len;
-}
-
-DUK_INTERNAL void duk_bw_insert_ensure_bytes(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, const duk_uint8_t *buf, duk_size_t len) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(buf != NULL);
- DUK_UNREF(thr);
-
- DUK_BW_ENSURE(thr, bw, len);
- duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len);
-}
-
-DUK_INTERNAL void duk_bw_insert_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len) {
- duk_uint8_t *p_base;
- duk_size_t buf_sz, move_sz;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
-
- p_base = bw->p_base;
-
- /* Don't support "straddled" source now. */
- DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
-
- if (dst_off <= src_off) {
- /* Target is before source. Source offset is expressed as
- * a "before change" offset. Account for the memmove.
- */
- src_off += len;
- }
-
- buf_sz = bw->p - p_base;
- move_sz = buf_sz - dst_off;
-
- DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
- DUK_MEMMOVE((void *) (p_base + dst_off + len),
- (const void *) (p_base + dst_off),
- (size_t) move_sz);
- DUK_MEMCPY((void *) (p_base + dst_off),
- (const void *) (p_base + src_off),
- (size_t) len);
- bw->p += len;
-}
-
-DUK_INTERNAL void duk_bw_insert_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t dst_off, duk_size_t src_off, duk_size_t len) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
-
- /* Don't support "straddled" source now. */
- DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
-
- DUK_BW_ENSURE(thr, bw, len);
- duk_bw_insert_raw_slice(thr, bw, dst_off, src_off, len);
-}
-
-DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
- duk_uint8_t *p_base, *p_dst, *p_src;
- duk_size_t buf_sz, move_sz;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
-
- p_base = bw->p_base;
- buf_sz = bw->p - p_base;
- move_sz = buf_sz - off;
- p_dst = p_base + off + len;
- p_src = p_base + off;
- DUK_MEMMOVE((void *) p_dst, (const void *) p_src, (size_t) move_sz);
- return p_src; /* point to start of 'reserved area' */
-}
-
-DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
-
- DUK_BW_ENSURE(thr, bw, len);
- return duk_bw_insert_raw_area(thr, bw, off, len);
-}
-
-DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
- duk_size_t move_sz;
-
- duk_uint8_t *p_base;
- duk_uint8_t *p_src;
- duk_uint8_t *p_dst;
-
- DUK_ASSERT(thr != NULL);
- DUK_ASSERT(bw != NULL);
- DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_ASSERT(off + len <= DUK_BW_GET_SIZE(thr, bw));
- DUK_UNREF(thr);
-
- p_base = bw->p_base;
- p_dst = p_base + off;
- p_src = p_dst + len;
- move_sz = (duk_size_t) (bw->p - p_src);
- DUK_MEMMOVE((void *) p_dst,
- (const void *) p_src,
- (size_t) move_sz);
- bw->p -= len;
-}
-
-/*
- * Macro support functions for reading/writing raw data.
- *
- * These are done using mempcy to ensure they're valid even for unaligned
- * reads/writes on platforms where alignment counts. On x86 at least gcc
- * is able to compile these into a bswap+mov. "Always inline" is used to
- * ensure these macros compile to minimal code.
- *
- * Not really bufwriter related, but currently used together.
- */
-
-DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p) {
- union {
- duk_uint8_t b[2];
- duk_uint16_t x;
- } u;
-
- DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 2);
- u.x = DUK_NTOH16(u.x);
- *p += 2;
- return u.x;
-}
-
-DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p) {
- union {
- duk_uint8_t b[4];
- duk_uint32_t x;
- } u;
-
- DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
- u.x = DUK_NTOH32(u.x);
- *p += 4;
- return u.x;
-}
-
-DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p) {
- duk_double_union du;
- union {
- duk_uint8_t b[4];
- duk_uint32_t x;
- } u;
-
- DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
- u.x = DUK_NTOH32(u.x);
- du.ui[DUK_DBL_IDX_UI0] = u.x;
- DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), (size_t) 4);
- u.x = DUK_NTOH32(u.x);
- du.ui[DUK_DBL_IDX_UI1] = u.x;
- *p += 8;
-
- return du.d;
-}
-
-DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val) {
- union {
- duk_uint8_t b[2];
- duk_uint16_t x;
- } u;
-
- u.x = DUK_HTON16(val);
- DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 2);
- *p += 2;
-}
-
-DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val) {
- union {
- duk_uint8_t b[4];
- duk_uint32_t x;
- } u;
-
- u.x = DUK_HTON32(val);
- DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
- *p += 4;
-}
-
-DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val) {
- duk_double_union du;
- union {
- duk_uint8_t b[4];
- duk_uint32_t x;
- } u;
-
- du.d = val;
- u.x = du.ui[DUK_DBL_IDX_UI0];
- u.x = DUK_HTON32(u.x);
- DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
- u.x = du.ui[DUK_DBL_IDX_UI1];
- u.x = DUK_HTON32(u.x);
- DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4);
- *p += 8;
-}
-#line 1 "duk_util_hashbytes.c"
-/*
- * Hash function duk_util_hashbytes().
- *
- * Currently, 32-bit MurmurHash2.
- *
- * Don't rely on specific hash values; hash function may be endianness
- * dependent, for instance.
- */
-
-/* include removed: duk_internal.h */
-
-#if defined(DUK_USE_STRHASH_DENSE)
-/* 'magic' constants for Murmurhash2 */
-#define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL)
-#define DUK__MAGIC_R 24
-
-DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) {
- duk_uint32_t h = seed ^ ((duk_uint32_t) len);
-
- while (len >= 4) {
- /* Portability workaround is required for platforms without
- * unaligned access. The replacement code emulates little
- * endian access even on big endian architectures, which is
- * OK as long as it is consistent for a build.
- */
-#ifdef DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS
- duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
-#else
- duk_uint32_t k = ((duk_uint32_t) data[0]) |
- (((duk_uint32_t) data[1]) << 8) |
- (((duk_uint32_t) data[2]) << 16) |
- (((duk_uint32_t) data[3]) << 24);
-#endif
-
- k *= DUK__MAGIC_M;
- k ^= k >> DUK__MAGIC_R;
- k *= DUK__MAGIC_M;
- h *= DUK__MAGIC_M;
- h ^= k;
- data += 4;
- len -= 4;
- }
-
- switch (len) {
- case 3: h ^= data[2] << 16;
- case 2: h ^= data[1] << 8;
- case 1: h ^= data[0];
- h *= DUK__MAGIC_M;
- }
-
- h ^= h >> 13;
- h *= DUK__MAGIC_M;
- h ^= h >> 15;
-
- return h;
-}
-#endif /* DUK_USE_STRHASH_DENSE */
-#line 1 "duk_util_tinyrandom.c"
-/*
- * A tiny random number generator.
- *
- * Currently used for Math.random().
- *
- * http://www.woodmann.com/forum/archive/index.php/t-3100.html
- */
-
-/* include removed: duk_internal.h */
-
-#define DUK__UPDATE_RND(rnd) do { \
- (rnd) += ((rnd) * (rnd)) | 0x05; \
- (rnd) = ((rnd) & 0xffffffffU); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
- } while (0)
-
-#define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */
-
-DUK_INTERNAL duk_uint32_t duk_util_tinyrandom_get_bits(duk_hthread *thr, duk_small_int_t n) {
- duk_small_int_t i;
- duk_uint32_t res = 0;
- duk_uint32_t rnd;
-
- rnd = thr->heap->rnd_state;
-
- for (i = 0; i < n; i++) {
- DUK__UPDATE_RND(rnd);
- res <<= 1;
- res += DUK__RND_BIT(rnd);
- }
-
- thr->heap->rnd_state = rnd;
-
- return res;
-}
-
-DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
- duk_double_t t;
- duk_small_int_t n;
- duk_uint32_t rnd;
-
- /*
- * XXX: could make this a lot faster if we create the double memory
- * representation directly. Feasible easily (must be uniform random).
- */
-
- rnd = thr->heap->rnd_state;
-
- n = 53; /* enough to cover the whole mantissa */
- t = 0.0;
-
- do {
- DUK__UPDATE_RND(rnd);
- t += DUK__RND_BIT(rnd);
- t /= 2.0;
- } while (--n);
-
- thr->heap->rnd_state = rnd;
-
- DUK_ASSERT(t >= (duk_double_t) 0.0);
- DUK_ASSERT(t < (duk_double_t) 1.0);
-
- return t;
-}
-#endif
diff --git a/javascript/duktape/duktape.h b/javascript/duktape/duktape.h
deleted file mode 100644
index a727187eb..000000000
--- a/javascript/duktape/duktape.h
+++ /dev/null
@@ -1,1567 +0,0 @@
-/*
- * Duktape public API for Duktape 1.5.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 83d557704ee63f68ab40b6fcb00995c9b3d6777c (v1.5.0).
- * Git branch master.
- *
- * See Duktape AUTHORS.rst and LICENSE.txt for copyright and
- * licensing information.
- */
-
-/* LICENSE.txt */
-/*
- * ===============
- * Duktape license
- * ===============
- *
- * (http://opensource.org/licenses/MIT)
- *
- * 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
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* AUTHORS.rst */
-/*
- * ===============
- * Duktape authors
- * ===============
- *
- * Copyright
- * =========
- *
- * Duktape copyrights are held by its authors. Each author has a copyright
- * to their contribution, and agrees to irrevocably license the contribution
- * under the Duktape ``LICENSE.txt``.
- *
- * Authors
- * =======
- *
- * Please include an e-mail address, a link to your GitHub profile, or something
- * similar to allow your contribution to be identified accurately.
- *
- * The following people have contributed code, website contents, or Wiki contents,
- * and agreed to irrevocably license their contributions under the Duktape
- * ``LICENSE.txt`` (in order of appearance):
- *
- * * Sami Vaarala <sami.vaarala@iki.fi>
- * * Niki Dobrev
- * * Andreas \u00d6man <andreas@lonelycoder.com>
- * * L\u00e1szl\u00f3 Lang\u00f3 <llango.u-szeged@partner.samsung.com>
- * * Legimet <legimet.calc@gmail.com>
- * * Karl Skomski <karl@skomski.com>
- * * Bruce Pascoe <fatcerberus1@gmail.com>
- * * Ren\u00e9 Hollander <rene@rene8888.at>
- * * Julien Hamaide (https://github.com/crazyjul)
- * * Sebastian G\u00f6tte (https://github.com/jaseg)
- *
- * Other contributions
- * ===================
- *
- * The following people have contributed something other than code (e.g. reported
- * bugs, provided ideas, etc; roughly in order of appearance):
- *
- * * Greg Burns
- * * Anthony Rabine
- * * Carlos Costa
- * * Aur\u00e9lien Bouilland
- * * Preet Desai (Pris Matic)
- * * judofyr (http://www.reddit.com/user/judofyr)
- * * Jason Woofenden
- * * Micha\u0142 Przyby\u015b
- * * Anthony Howe
- * * Conrad Pankoff
- * * Jim Schimpf
- * * Rajaran Gaunker (https://github.com/zimbabao)
- * * Andreas \u00d6man
- * * Doug Sanden
- * * Josh Engebretson (https://github.com/JoshEngebretson)
- * * Remo Eichenberger (https://github.com/remoe)
- * * Mamod Mehyar (https://github.com/mamod)
- * * David Demelier (https://github.com/markand)
- * * Tim Caswell (https://github.com/creationix)
- * * Mitchell Blank Jr (https://github.com/mitchblank)
- * * https://github.com/yushli
- * * Seo Sanghyeon (https://github.com/sanxiyn)
- * * Han ChoongWoo (https://github.com/tunz)
- * * Joshua Peek (https://github.com/josh)
- * * Bruce E. Pascoe (https://github.com/fatcerberus)
- * * https://github.com/Kelledin
- * * https://github.com/sstruchtrup
- * * Michael Drake (https://github.com/tlsa)
- * * https://github.com/chris-y
- * * Laurent Zubiaur (https://github.com/lzubiaur)
- * * Ole Andr\u00e9 Vadla Ravn\u00e5s (https://github.com/oleavr)
- *
- * If you are accidentally missing from this list, send me an e-mail
- * (``sami.vaarala@iki.fi``) and I'll fix the omission.
- */
-
-#ifndef DUKTAPE_H_INCLUDED
-#define DUKTAPE_H_INCLUDED
-
-#define DUK_SINGLE_FILE
-
-/* External duk_config.h provides platform/compiler/OS dependent
- * typedefs and macros, and DUK_USE_xxx config options so that
- * the rest of Duktape doesn't need to do any feature detection.
- */
-#include "duk_config.h"
-
-/*
- * BEGIN PUBLIC API
- */
-
-#ifndef DUK_API_PUBLIC_H_INCLUDED
-#define DUK_API_PUBLIC_H_INCLUDED
-
-/*
- * Avoid C++ name mangling
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Some defines forwarded from feature detection
- */
-
-#undef DUK_API_VARIADIC_MACROS
-#ifdef DUK_USE_VARIADIC_MACROS
-#define DUK_API_VARIADIC_MACROS
-#endif
-
-#define DUK_API_NORETURN(decl) DUK_NORETURN(decl)
-
-/*
- * Public API specific typedefs
- *
- * Many types are wrapped by Duktape for portability to rare platforms
- * where e.g. 'int' is a 16-bit type. See practical typing discussion
- * in Duktape web documentation.
- */
-
-struct duk_memory_functions;
-struct duk_function_list_entry;
-struct duk_number_list_entry;
-
-/* duk_context is now defined in duk_config.h because it may also be
- * referenced there by prototypes.
- */
-typedef struct duk_memory_functions duk_memory_functions;
-typedef struct duk_function_list_entry duk_function_list_entry;
-typedef struct duk_number_list_entry duk_number_list_entry;
-
-typedef duk_ret_t (*duk_c_function)(duk_context *ctx);
-typedef void *(*duk_alloc_function) (void *udata, duk_size_t size);
-typedef void *(*duk_realloc_function) (void *udata, void *ptr, duk_size_t size);
-typedef void (*duk_free_function) (void *udata, void *ptr);
-typedef void (*duk_fatal_function) (duk_context *ctx, duk_errcode_t code, const char *msg);
-typedef void (*duk_decode_char_function) (void *udata, duk_codepoint_t codepoint);
-typedef duk_codepoint_t (*duk_map_char_function) (void *udata, duk_codepoint_t codepoint);
-typedef duk_ret_t (*duk_safe_call_function) (duk_context *ctx);
-typedef duk_size_t (*duk_debug_read_function) (void *udata, char *buffer, duk_size_t length);
-typedef duk_size_t (*duk_debug_write_function) (void *udata, const char *buffer, duk_size_t length);
-typedef duk_size_t (*duk_debug_peek_function) (void *udata);
-typedef void (*duk_debug_read_flush_function) (void *udata);
-typedef void (*duk_debug_write_flush_function) (void *udata);
-typedef duk_idx_t (*duk_debug_request_function) (duk_context *ctx, void *udata, duk_idx_t nvalues);
-typedef void (*duk_debug_detached_function) (void *udata);
-
-struct duk_memory_functions {
- duk_alloc_function alloc_func;
- duk_realloc_function realloc_func;
- duk_free_function free_func;
- void *udata;
-};
-
-struct duk_function_list_entry {
- const char *key;
- duk_c_function value;
- duk_idx_t nargs;
-};
-
-struct duk_number_list_entry {
- const char *key;
- duk_double_t value;
-};
-
-/*
- * Constants
- */
-
-/* Duktape version, (major * 10000) + (minor * 100) + patch. Allows C code
- * to #ifdef against Duktape API version. The same value is also available
- * to Ecmascript code in Duktape.version. Unofficial development snapshots
- * 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 10500L
-
-/* 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 "83d557704ee63f68ab40b6fcb00995c9b3d6777c"
-#define DUK_GIT_DESCRIBE "v1.5.0"
-#define DUK_GIT_BRANCH "master"
-
-/* Duktape debug protocol version used by this build. */
-#define DUK_DEBUG_PROTOCOL_VERSION 1
-
-/* Used to represent invalid index; if caller uses this without checking,
- * this index will map to a non-existent stack entry. Also used in some
- * API calls as a marker to denote "no value".
- */
-#define DUK_INVALID_INDEX DUK_IDX_MIN
-
-/* Indicates that a native function does not have a fixed number of args,
- * and the argument stack should not be capped/extended at all.
- */
-#define DUK_VARARGS ((duk_int_t) (-1))
-
-/* Number of value stack entries (in addition to actual call arguments)
- * guaranteed to be allocated on entry to a Duktape/C function.
- */
-#define DUK_API_ENTRY_STACK 64
-
-/* Value types, used by e.g. duk_get_type() */
-#define DUK_TYPE_MIN 0
-#define DUK_TYPE_NONE 0 /* no value, e.g. invalid index */
-#define DUK_TYPE_UNDEFINED 1 /* Ecmascript undefined */
-#define DUK_TYPE_NULL 2 /* Ecmascript null */
-#define DUK_TYPE_BOOLEAN 3 /* Ecmascript boolean: 0 or 1 */
-#define DUK_TYPE_NUMBER 4 /* Ecmascript number: double */
-#define DUK_TYPE_STRING 5 /* Ecmascript string: CESU-8 / extended UTF-8 encoded */
-#define DUK_TYPE_OBJECT 6 /* Ecmascript object: includes objects, arrays, functions, threads */
-#define DUK_TYPE_BUFFER 7 /* fixed or dynamic, garbage collected byte buffer */
-#define DUK_TYPE_POINTER 8 /* raw void pointer */
-#define DUK_TYPE_LIGHTFUNC 9 /* lightweight function pointer */
-#define DUK_TYPE_MAX 9
-
-/* Value mask types, used by e.g. duk_get_type_mask() */
-#define DUK_TYPE_MASK_NONE (1 << DUK_TYPE_NONE)
-#define DUK_TYPE_MASK_UNDEFINED (1 << DUK_TYPE_UNDEFINED)
-#define DUK_TYPE_MASK_NULL (1 << DUK_TYPE_NULL)
-#define DUK_TYPE_MASK_BOOLEAN (1 << DUK_TYPE_BOOLEAN)
-#define DUK_TYPE_MASK_NUMBER (1 << DUK_TYPE_NUMBER)
-#define DUK_TYPE_MASK_STRING (1 << DUK_TYPE_STRING)
-#define DUK_TYPE_MASK_OBJECT (1 << DUK_TYPE_OBJECT)
-#define DUK_TYPE_MASK_BUFFER (1 << DUK_TYPE_BUFFER)
-#define DUK_TYPE_MASK_POINTER (1 << DUK_TYPE_POINTER)
-#define DUK_TYPE_MASK_LIGHTFUNC (1 << DUK_TYPE_LIGHTFUNC)
-#define DUK_TYPE_MASK_THROW (1 << 10) /* internal flag value: throw if mask doesn't match */
-
-/* Coercion hints */
-#define DUK_HINT_NONE 0 /* prefer number, unless input is a Date, in which
- * case prefer string (E5 Section 8.12.8)
- */
-#define DUK_HINT_STRING 1 /* prefer string */
-#define DUK_HINT_NUMBER 2 /* prefer number */
-
-/* Enumeration flags for duk_enum() */
-#define DUK_ENUM_INCLUDE_NONENUMERABLE (1 << 0) /* enumerate non-numerable properties in addition to enumerable */
-#define DUK_ENUM_INCLUDE_INTERNAL (1 << 1) /* enumerate internal properties (regardless of enumerability) */
-#define DUK_ENUM_OWN_PROPERTIES_ONLY (1 << 2) /* don't walk prototype chain, only check own properties */
-#define DUK_ENUM_ARRAY_INDICES_ONLY (1 << 3) /* only enumerate array indices */
-#define DUK_ENUM_SORT_ARRAY_INDICES (1 << 4) /* sort array indices, use with DUK_ENUM_ARRAY_INDICES_ONLY */
-#define DUK_ENUM_NO_PROXY_BEHAVIOR (1 << 5) /* enumerate a proxy object itself without invoking proxy behavior */
-
-/* Compilation flags for duk_compile() and duk_eval() */
-/* DUK_COMPILE_xxx bits 0-2 are reserved for an internal 'nargs' argument
- * (the nargs value passed is direct stack arguments + 1 to account for an
- * internal extra argument).
- */
-#define DUK_COMPILE_EVAL (1 << 3) /* compile eval code (instead of global code) */
-#define DUK_COMPILE_FUNCTION (1 << 4) /* compile function code (instead of global code) */
-#define DUK_COMPILE_STRICT (1 << 5) /* use strict (outer) context for global, eval, or function code */
-#define DUK_COMPILE_SAFE (1 << 6) /* (internal) catch compilation errors */
-#define DUK_COMPILE_NORESULT (1 << 7) /* (internal) omit eval result */
-#define DUK_COMPILE_NOSOURCE (1 << 8) /* (internal) no source string on stack */
-#define DUK_COMPILE_STRLEN (1 << 9) /* (internal) take strlen() of src_buffer (avoids double evaluation in macro) */
-#define DUK_COMPILE_NOFILENAME (1 << 10) /* (internal) no filename on stack */
-
-/* Flags for duk_def_prop() and its variants */
-#define DUK_DEFPROP_WRITABLE (1 << 0) /* set writable (effective if DUK_DEFPROP_HAVE_WRITABLE set) */
-#define DUK_DEFPROP_ENUMERABLE (1 << 1) /* set enumerable (effective if DUK_DEFPROP_HAVE_ENUMERABLE set) */
-#define DUK_DEFPROP_CONFIGURABLE (1 << 2) /* set configurable (effective if DUK_DEFPROP_HAVE_CONFIGURABLE set) */
-#define DUK_DEFPROP_HAVE_WRITABLE (1 << 3) /* set/clear writable */
-#define DUK_DEFPROP_HAVE_ENUMERABLE (1 << 4) /* set/clear enumerable */
-#define DUK_DEFPROP_HAVE_CONFIGURABLE (1 << 5) /* set/clear configurable */
-#define DUK_DEFPROP_HAVE_VALUE (1 << 6) /* set value (given on value stack) */
-#define DUK_DEFPROP_HAVE_GETTER (1 << 7) /* set getter (given on value stack) */
-#define DUK_DEFPROP_HAVE_SETTER (1 << 8) /* set setter (given on value stack) */
-#define DUK_DEFPROP_FORCE (1 << 9) /* force change if possible, may still fail for e.g. virtual properties */
-#define DUK_DEFPROP_SET_WRITABLE (DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE)
-#define DUK_DEFPROP_CLEAR_WRITABLE DUK_DEFPROP_HAVE_WRITABLE
-#define DUK_DEFPROP_SET_ENUMERABLE (DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE)
-#define DUK_DEFPROP_CLEAR_ENUMERABLE DUK_DEFPROP_HAVE_ENUMERABLE
-#define DUK_DEFPROP_SET_CONFIGURABLE (DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE)
-#define DUK_DEFPROP_CLEAR_CONFIGURABLE DUK_DEFPROP_HAVE_CONFIGURABLE
-
-/* Flags for duk_push_thread_raw() */
-#define DUK_THREAD_NEW_GLOBAL_ENV (1 << 0) /* create a new global environment */
-
-/* Flags for duk_push_string_file_raw() */
-#define DUK_STRING_PUSH_SAFE (1 << 0) /* no error if file does not exist */
-
-/* Duktape specific error codes (must be 8 bits at most, see duk_error.h) */
-#define DUK_ERR_NONE 0 /* no error (e.g. from duk_get_error_code()) */
-#define DUK_ERR_UNIMPLEMENTED_ERROR 50 /* UnimplementedError */ /* XXX: replace with TypeError? */
-#define DUK_ERR_UNSUPPORTED_ERROR 51 /* UnsupportedError */ /* XXX: replace with TypeError? */
-#define DUK_ERR_INTERNAL_ERROR 52 /* InternalError */ /* XXX: replace with plain Error? */
-#define DUK_ERR_ALLOC_ERROR 53 /* AllocError */ /* XXX: replace with RangeError? */
-#define DUK_ERR_ASSERTION_ERROR 54 /* AssertionError */ /* XXX: to be removed? */
-#define DUK_ERR_API_ERROR 55 /* APIError */ /* XXX: replace with TypeError? */
-#define DUK_ERR_UNCAUGHT_ERROR 56 /* UncaughtError */ /* XXX: to be removed? */
-
-/* Ecmascript E5 specification error codes */
-#define DUK_ERR_ERROR 100 /* Error */
-#define DUK_ERR_EVAL_ERROR 101 /* EvalError */
-#define DUK_ERR_RANGE_ERROR 102 /* RangeError */
-#define DUK_ERR_REFERENCE_ERROR 103 /* ReferenceError */
-#define DUK_ERR_SYNTAX_ERROR 104 /* SyntaxError */
-#define DUK_ERR_TYPE_ERROR 105 /* TypeError */
-#define DUK_ERR_URI_ERROR 106 /* URIError */
-
-/* Return codes for C functions (shortcut for throwing an error) */
-#define DUK_RET_UNIMPLEMENTED_ERROR (-DUK_ERR_UNIMPLEMENTED_ERROR)
-#define DUK_RET_UNSUPPORTED_ERROR (-DUK_ERR_UNSUPPORTED_ERROR)
-#define DUK_RET_INTERNAL_ERROR (-DUK_ERR_INTERNAL_ERROR)
-#define DUK_RET_ALLOC_ERROR (-DUK_ERR_ALLOC_ERROR)
-#define DUK_RET_ASSERTION_ERROR (-DUK_ERR_ASSERTION_ERROR)
-#define DUK_RET_API_ERROR (-DUK_ERR_API_ERROR)
-#define DUK_RET_UNCAUGHT_ERROR (-DUK_ERR_UNCAUGHT_ERROR)
-#define DUK_RET_ERROR (-DUK_ERR_ERROR)
-#define DUK_RET_EVAL_ERROR (-DUK_ERR_EVAL_ERROR)
-#define DUK_RET_RANGE_ERROR (-DUK_ERR_RANGE_ERROR)
-#define DUK_RET_REFERENCE_ERROR (-DUK_ERR_REFERENCE_ERROR)
-#define DUK_RET_SYNTAX_ERROR (-DUK_ERR_SYNTAX_ERROR)
-#define DUK_RET_TYPE_ERROR (-DUK_ERR_TYPE_ERROR)
-#define DUK_RET_URI_ERROR (-DUK_ERR_URI_ERROR)
-
-/* Return codes for protected calls (duk_safe_call(), duk_pcall()) */
-#define DUK_EXEC_SUCCESS 0
-#define DUK_EXEC_ERROR 1
-
-/* Log levels */
-#define DUK_LOG_TRACE 0
-#define DUK_LOG_DEBUG 1
-#define DUK_LOG_INFO 2
-#define DUK_LOG_WARN 3
-#define DUK_LOG_ERROR 4
-#define DUK_LOG_FATAL 5
-
-/*
- * If no variadic macros, __FILE__ and __LINE__ are passed through globals
- * which is ugly and not thread safe.
- */
-
-#ifndef DUK_API_VARIADIC_MACROS
-DUK_EXTERNAL_DECL const char *duk_api_global_filename;
-DUK_EXTERNAL_DECL duk_int_t duk_api_global_line;
-#endif
-
-/*
- * Context management
- */
-
-DUK_EXTERNAL_DECL
-duk_context *duk_create_heap(duk_alloc_function alloc_func,
- duk_realloc_function realloc_func,
- duk_free_function free_func,
- void *heap_udata,
- duk_fatal_function fatal_handler);
-DUK_EXTERNAL_DECL void duk_destroy_heap(duk_context *ctx);
-
-#define duk_create_heap_default() \
- duk_create_heap(NULL, NULL, NULL, NULL, NULL)
-
-/*
- * Memory management
- *
- * Raw functions have no side effects (cannot trigger GC).
- */
-
-DUK_EXTERNAL_DECL void *duk_alloc_raw(duk_context *ctx, duk_size_t size);
-DUK_EXTERNAL_DECL void duk_free_raw(duk_context *ctx, void *ptr);
-DUK_EXTERNAL_DECL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size);
-DUK_EXTERNAL_DECL void *duk_alloc(duk_context *ctx, duk_size_t size);
-DUK_EXTERNAL_DECL void duk_free(duk_context *ctx, void *ptr);
-DUK_EXTERNAL_DECL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size);
-DUK_EXTERNAL_DECL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs);
-DUK_EXTERNAL_DECL void duk_gc(duk_context *ctx, duk_uint_t flags);
-
-/*
- * Error handling
- */
-
-DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_throw(duk_context *ctx));
-DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_fatal(duk_context *ctx, duk_errcode_t err_code, const char *err_msg));
-
-DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...));
-
-#ifdef DUK_API_VARIADIC_MACROS
-#define duk_error(ctx,err_code,...) \
- duk_error_raw((ctx), (duk_errcode_t) (err_code), (const char *) (__FILE__), (duk_int_t) (__LINE__), __VA_ARGS__)
-#else
-DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...));
-/* One problem with this macro is that expressions like the following fail
- * to compile: "(void) duk_error(...)". But because duk_error() is noreturn,
- * they make little sense anyway.
- */
-#define duk_error \
- (duk_api_global_filename = (const char *) (__FILE__), \
- duk_api_global_line = (duk_int_t) (__LINE__), \
- duk_error_stash) /* last value is func pointer, arguments follow in parens */
-#endif
-
-DUK_API_NORETURN(DUK_EXTERNAL_DECL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap));
-#define duk_error_va(ctx,err_code,fmt,ap) \
- duk_error_va_raw((ctx), (duk_errcode_t) (err_code), (const char *) (__FILE__), (duk_int_t) (__LINE__), (fmt), (ap))
-
-/*
- * Other state related functions
- */
-
-DUK_EXTERNAL_DECL duk_bool_t duk_is_strict_call(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_constructor_call(duk_context *ctx);
-
-/*
- * Stack management
- */
-
-DUK_EXTERNAL_DECL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_require_valid_index(duk_context *ctx, duk_idx_t index);
-
-DUK_EXTERNAL_DECL duk_idx_t duk_get_top(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_set_top(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_idx_t duk_get_top_index(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_idx_t duk_require_top_index(duk_context *ctx);
-
-/* Although extra/top could be an unsigned type here, using a signed type
- * makes the API more robust to calling code calculation errors or corner
- * cases (where caller might occasionally come up with negative values).
- * Negative values are treated as zero, which is better than casting them
- * to a large unsigned number. (This principle is used elsewhere in the
- * API too.)
- */
-DUK_EXTERNAL_DECL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra);
-DUK_EXTERNAL_DECL void duk_require_stack(duk_context *ctx, duk_idx_t extra);
-DUK_EXTERNAL_DECL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top);
-DUK_EXTERNAL_DECL void duk_require_stack_top(duk_context *ctx, duk_idx_t top);
-
-/*
- * Stack manipulation (other than push/pop)
- */
-
-DUK_EXTERNAL_DECL void duk_swap(duk_context *ctx, duk_idx_t index1, duk_idx_t index2);
-DUK_EXTERNAL_DECL void duk_swap_top(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_dup(duk_context *ctx, duk_idx_t from_index);
-DUK_EXTERNAL_DECL void duk_dup_top(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_insert(duk_context *ctx, duk_idx_t to_index);
-DUK_EXTERNAL_DECL void duk_replace(duk_context *ctx, duk_idx_t to_index);
-DUK_EXTERNAL_DECL void duk_copy(duk_context *ctx, duk_idx_t from_index, duk_idx_t to_index);
-DUK_EXTERNAL_DECL void duk_remove(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy);
-
-#define duk_xmove_top(to_ctx,from_ctx,count) \
- duk_xcopymove_raw((to_ctx), (from_ctx), (count), 0 /*is_copy*/)
-#define duk_xcopy_top(to_ctx,from_ctx,count) \
- duk_xcopymove_raw((to_ctx), (from_ctx), (count), 1 /*is_copy*/)
-
-/*
- * Push operations
- *
- * Push functions return the absolute (relative to bottom of frame)
- * position of the pushed value for convenience.
- *
- * Note: duk_dup() is technically a push.
- */
-
-DUK_EXTERNAL_DECL void duk_push_undefined(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_null(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_boolean(duk_context *ctx, duk_bool_t val);
-DUK_EXTERNAL_DECL void duk_push_true(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_false(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_number(duk_context *ctx, duk_double_t val);
-DUK_EXTERNAL_DECL void duk_push_nan(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_int(duk_context *ctx, duk_int_t val);
-DUK_EXTERNAL_DECL void duk_push_uint(duk_context *ctx, duk_uint_t val);
-DUK_EXTERNAL_DECL const char *duk_push_string(duk_context *ctx, const char *str);
-DUK_EXTERNAL_DECL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len);
-DUK_EXTERNAL_DECL void duk_push_pointer(duk_context *ctx, void *p);
-DUK_EXTERNAL_DECL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...);
-DUK_EXTERNAL_DECL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap);
-
-DUK_EXTERNAL_DECL const char *duk_push_string_file_raw(duk_context *ctx, const char *path, duk_uint_t flags);
-#define duk_push_string_file(ctx,path) \
- duk_push_string_file_raw((ctx), (path), 0)
-
-DUK_EXTERNAL_DECL void duk_push_this(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_current_function(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_current_thread(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_global_object(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_heap_stash(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_global_stash(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx);
-
-DUK_EXTERNAL_DECL duk_idx_t duk_push_object(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_idx_t duk_push_array(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_idx_t nargs);
-DUK_EXTERNAL_DECL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic);
-DUK_EXTERNAL_DECL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags);
-
-#define duk_push_thread(ctx) \
- duk_push_thread_raw((ctx), 0 /*flags*/)
-
-#define duk_push_thread_new_globalenv(ctx) \
- duk_push_thread_raw((ctx), DUK_THREAD_NEW_GLOBAL_ENV /*flags*/)
-
-DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...);
-
-#ifdef DUK_API_VARIADIC_MACROS
-#define duk_push_error_object(ctx,err_code,...) \
- duk_push_error_object_raw((ctx), (err_code), (const char *) (__FILE__), (duk_int_t) (__LINE__), __VA_ARGS__)
-#else
-DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...);
-/* Note: parentheses are required so that the comma expression works in assignments. */
-#define duk_push_error_object \
- (duk_api_global_filename = (const char *) (__FILE__), \
- duk_api_global_line = (duk_int_t) (__LINE__), \
- duk_push_error_object_stash) /* last value is func pointer, arguments follow in parens */
-#endif
-
-DUK_EXTERNAL_DECL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap);
-#define duk_push_error_object_va(ctx,err_code,fmt,ap) \
- duk_push_error_object_va_raw((ctx), (err_code), (const char *) (__FILE__), (duk_int_t) (__LINE__), (fmt), (ap))
-
-#define DUK_BUF_FLAG_DYNAMIC (1 << 0) /* internal flag: dynamic buffer */
-#define DUK_BUF_FLAG_EXTERNAL (1 << 1) /* internal flag: external buffer */
-#define DUK_BUF_FLAG_NOZERO (1 << 2) /* internal flag: don't zero allocated buffer */
-
-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)
-#define duk_push_fixed_buffer(ctx,size) \
- duk_push_buffer_raw((ctx), (size), 0 /*flags*/)
-#define duk_push_dynamic_buffer(ctx,size) \
- duk_push_buffer_raw((ctx), (size), DUK_BUF_FLAG_DYNAMIC /*flags*/)
-#define duk_push_external_buffer(ctx) \
- ((void) duk_push_buffer_raw((ctx), 0, DUK_BUF_FLAG_DYNAMIC | DUK_BUF_FLAG_EXTERNAL))
-
-#define DUK_BUFOBJ_CREATE_ARRBUF (1 << 4) /* internal flag: create backing ArrayBuffer; keep in one byte */
-#define DUK_BUFOBJ_DUKTAPE_BUFFER 0
-#define DUK_BUFOBJ_NODEJS_BUFFER 1
-#define DUK_BUFOBJ_ARRAYBUFFER 2
-#define DUK_BUFOBJ_DATAVIEW (3 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_INT8ARRAY (4 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_UINT8ARRAY (5 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_UINT8CLAMPEDARRAY (6 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_INT16ARRAY (7 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_UINT16ARRAY (8 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_INT32ARRAY (9 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_UINT32ARRAY (10 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_FLOAT32ARRAY (11 | DUK_BUFOBJ_CREATE_ARRBUF)
-#define DUK_BUFOBJ_FLOAT64ARRAY (12 | DUK_BUFOBJ_CREATE_ARRBUF)
-
-DUK_EXTERNAL_DECL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags);
-
-DUK_EXTERNAL_DECL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr);
-
-/*
- * Pop operations
- */
-
-DUK_EXTERNAL_DECL void duk_pop(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_pop_n(duk_context *ctx, duk_idx_t count);
-DUK_EXTERNAL_DECL void duk_pop_2(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_pop_3(duk_context *ctx);
-
-/*
- * Type checks
- *
- * duk_is_none(), which would indicate whether index it outside of stack,
- * is not needed; duk_is_valid_index() gives the same information.
- */
-
-DUK_EXTERNAL_DECL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t index, duk_int_t type);
-DUK_EXTERNAL_DECL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t index, duk_uint_t mask);
-
-DUK_EXTERNAL_DECL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_null_or_undefined(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t index);
-
-DUK_EXTERNAL_DECL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t index);
-
-#define duk_is_callable(ctx,index) \
- duk_is_function((ctx), (index))
-DUK_EXTERNAL_DECL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t index);
-
-#define duk_is_primitive(ctx,index) \
- duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_UNDEFINED | \
- DUK_TYPE_MASK_NULL | \
- DUK_TYPE_MASK_BOOLEAN | \
- DUK_TYPE_MASK_NUMBER | \
- DUK_TYPE_MASK_STRING | \
- DUK_TYPE_MASK_BUFFER | \
- DUK_TYPE_MASK_POINTER | \
- DUK_TYPE_MASK_LIGHTFUNC)
-
-#define duk_is_object_coercible(ctx,index) \
- duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_BOOLEAN | \
- DUK_TYPE_MASK_NUMBER | \
- DUK_TYPE_MASK_STRING | \
- DUK_TYPE_MASK_OBJECT | \
- DUK_TYPE_MASK_BUFFER | \
- DUK_TYPE_MASK_POINTER | \
- DUK_TYPE_MASK_LIGHTFUNC)
-
-DUK_EXTERNAL_DECL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t index);
-#define duk_is_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) != 0)
-#define duk_is_eval_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_EVAL_ERROR)
-#define duk_is_range_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_RANGE_ERROR)
-#define duk_is_reference_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_REFERENCE_ERROR)
-#define duk_is_syntax_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_SYNTAX_ERROR)
-#define duk_is_type_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_TYPE_ERROR)
-#define duk_is_uri_error(ctx,index) \
- (duk_get_error_code((ctx), (index)) == DUK_ERR_URI_ERROR)
-
-/*
- * Get operations: no coercion, returns default value for invalid
- * indices and invalid value types.
- *
- * duk_get_undefined() and duk_get_null() would be pointless and
- * are not included.
- */
-
-DUK_EXTERNAL_DECL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_get_string(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_get_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len);
-DUK_EXTERNAL_DECL void *duk_get_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void *duk_get_pointer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_context *duk_get_context(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void *duk_get_heapptr(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index);
-
-/*
- * Require operations: no coercion, throw error if index or type
- * is incorrect. No defaulting.
- */
-
-#define duk_require_type_mask(ctx,index,mask) \
- ((void) duk_check_type_mask((ctx), (index), (mask) | DUK_TYPE_MASK_THROW))
-
-DUK_EXTERNAL_DECL void duk_require_undefined(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_require_null(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_require_string(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_require_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len);
-DUK_EXTERNAL_DECL void *duk_require_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void *duk_require_pointer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_context *duk_require_context(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_require_function(duk_context *ctx, duk_idx_t index);
-#define duk_require_callable(ctx,index) \
- duk_require_function((ctx), (index))
-DUK_EXTERNAL_DECL void *duk_require_heapptr(duk_context *ctx, duk_idx_t index);
-
-#define duk_require_object_coercible(ctx,index) \
- ((void) duk_check_type_mask((ctx), (index), DUK_TYPE_MASK_BOOLEAN | \
- DUK_TYPE_MASK_NUMBER | \
- DUK_TYPE_MASK_STRING | \
- DUK_TYPE_MASK_OBJECT | \
- DUK_TYPE_MASK_BUFFER | \
- DUK_TYPE_MASK_POINTER | \
- DUK_TYPE_MASK_LIGHTFUNC | \
- DUK_TYPE_MASK_THROW))
-
-/*
- * Coercion operations: in-place coercion, return coerced value where
- * applicable. If index is invalid, throw error. Some coercions may
- * throw an expected error (e.g. from a toString() or valueOf() call)
- * or an internal error (e.g. from out of memory).
- */
-
-DUK_EXTERNAL_DECL void duk_to_undefined(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_to_null(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_to_string(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len);
-DUK_EXTERNAL_DECL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t index, duk_size_t *out_size, duk_uint_t flags);
-DUK_EXTERNAL_DECL void *duk_to_pointer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_to_object(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint);
-DUK_EXTERNAL_DECL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint);
-
-#define DUK_BUF_MODE_FIXED 0 /* internal: request fixed buffer result */
-#define DUK_BUF_MODE_DYNAMIC 1 /* internal: request dynamic buffer result */
-#define DUK_BUF_MODE_DONTCARE 2 /* internal: don't care about fixed/dynamic nature */
-
-#define duk_to_buffer(ctx,index,out_size) \
- duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_DONTCARE)
-#define duk_to_fixed_buffer(ctx,index,out_size) \
- duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_FIXED)
-#define duk_to_dynamic_buffer(ctx,index,out_size) \
- duk_to_buffer_raw((ctx), (index), (out_size), DUK_BUF_MODE_DYNAMIC)
-
-/* safe variants of a few coercion operations */
-DUK_EXTERNAL_DECL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t index, duk_size_t *out_len);
-#define duk_safe_to_string(ctx,index) \
- duk_safe_to_lstring((ctx), (index), NULL)
-
-/*
- * Misc conversion
- */
-
-DUK_EXTERNAL_DECL const char *duk_base64_encode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_base64_decode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_hex_encode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_hex_decode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL const char *duk_json_encode(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_json_decode(duk_context *ctx, duk_idx_t index);
-
-/*
- * Buffer
- */
-
-DUK_EXTERNAL_DECL void *duk_resize_buffer(duk_context *ctx, duk_idx_t index, duk_size_t new_size);
-DUK_EXTERNAL_DECL void *duk_steal_buffer(duk_context *ctx, duk_idx_t index, duk_size_t *out_size);
-DUK_EXTERNAL_DECL void duk_config_buffer(duk_context *ctx, duk_idx_t index, void *ptr, duk_size_t len);
-
-/*
- * Property access
- *
- * The basic function assumes key is on stack. The _string variant takes
- * a C string as a property name, while the _index variant takes an array
- * index as a property name (e.g. 123 is equivalent to the key "123").
- */
-
-DUK_EXTERNAL_DECL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index);
-DUK_EXTERNAL_DECL void duk_def_prop(duk_context *ctx, duk_idx_t obj_index, duk_uint_t flags);
-
-DUK_EXTERNAL_DECL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key);
-DUK_EXTERNAL_DECL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key);
-
-/*
- * Object prototype
- */
-
-DUK_EXTERNAL_DECL void duk_get_prototype(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_set_prototype(duk_context *ctx, duk_idx_t index);
-
-/*
- * Object finalizer
- */
-
-DUK_EXTERNAL_DECL void duk_get_finalizer(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_set_finalizer(duk_context *ctx, duk_idx_t index);
-
-/*
- * Global object
- */
-
-DUK_EXTERNAL_DECL void duk_set_global_object(duk_context *ctx);
-
-/*
- * Duktape/C function magic value
- */
-
-DUK_EXTERNAL_DECL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL void duk_set_magic(duk_context *ctx, duk_idx_t index, duk_int_t magic);
-DUK_EXTERNAL_DECL duk_int_t duk_get_current_magic(duk_context *ctx);
-
-/*
- * Module helpers: put multiple function or constant properties
- */
-
-DUK_EXTERNAL_DECL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs);
-DUK_EXTERNAL_DECL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers);
-
-/*
- * Variable access
- */
-
-/* XXX: These calls are incomplete and not usable now. They are not (yet)
- * part of the public API.
- */
-DUK_EXTERNAL_DECL void duk_get_var(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_put_var(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_bool_t duk_del_var(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_bool_t duk_has_var(duk_context *ctx);
-
-/*
- * Object operations
- */
-
-DUK_EXTERNAL_DECL void duk_compact(duk_context *ctx, duk_idx_t obj_index);
-DUK_EXTERNAL_DECL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags);
-DUK_EXTERNAL_DECL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value);
-
-/*
- * String manipulation
- */
-
-DUK_EXTERNAL_DECL void duk_concat(duk_context *ctx, duk_idx_t count);
-DUK_EXTERNAL_DECL void duk_join(duk_context *ctx, duk_idx_t count);
-DUK_EXTERNAL_DECL void duk_decode_string(duk_context *ctx, duk_idx_t index, duk_decode_char_function callback, void *udata);
-DUK_EXTERNAL_DECL void duk_map_string(duk_context *ctx, duk_idx_t index, duk_map_char_function callback, void *udata);
-DUK_EXTERNAL_DECL void duk_substring(duk_context *ctx, duk_idx_t index, duk_size_t start_char_offset, duk_size_t end_char_offset);
-DUK_EXTERNAL_DECL void duk_trim(duk_context *ctx, duk_idx_t index);
-DUK_EXTERNAL_DECL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t index, duk_size_t char_offset);
-
-/*
- * Ecmascript operators
- */
-
-DUK_EXTERNAL_DECL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2);
-DUK_EXTERNAL_DECL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t index1, duk_idx_t index2);
-DUK_EXTERNAL_DECL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t index1, duk_idx_t index2);
-
-/*
- * Function (method) calls
- */
-
-DUK_EXTERNAL_DECL void duk_call(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL void duk_call_method(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL void duk_call_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs);
-DUK_EXTERNAL_DECL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_index, duk_idx_t nargs);
-DUK_EXTERNAL_DECL void duk_new(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs);
-DUK_EXTERNAL_DECL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets);
-
-/*
- * Thread management
- */
-
-/* There are currently no native functions to yield/resume, due to the internal
- * limitations on coroutine handling. These will be added later.
- */
-
-/*
- * Compilation and evaluation
- */
-
-DUK_EXTERNAL_DECL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags);
-DUK_EXTERNAL_DECL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags);
-
-/* plain */
-#define duk_eval(ctx) \
- ((void) duk_eval_raw((ctx), NULL, 0, 2 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOFILENAME))
-
-#define duk_eval_noresult(ctx) \
- ((void) duk_eval_raw((ctx), NULL, 0, 2 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
-
-#define duk_peval(ctx) \
- (duk_eval_raw((ctx), NULL, 0, 2 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME))
-
-#define duk_peval_noresult(ctx) \
- (duk_eval_raw((ctx), NULL, 0, 2 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
-
-#define duk_compile(ctx,flags) \
- ((void) duk_compile_raw((ctx), NULL, 0, 3 /*args*/ | (flags)))
-
-#define duk_pcompile(ctx,flags) \
- (duk_compile_raw((ctx), NULL, 0, 3 /*args*/ | (flags) | DUK_COMPILE_SAFE))
-
-/* string */
-#define duk_eval_string(ctx,src) \
- ((void) duk_eval_raw((ctx), (src), 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
-
-#define duk_eval_string_noresult(ctx,src) \
- ((void) duk_eval_raw((ctx), (src), 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
-
-#define duk_peval_string(ctx,src) \
- (duk_eval_raw((ctx), (src), 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
-
-#define duk_peval_string_noresult(ctx,src) \
- (duk_eval_raw((ctx), (src), 0, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
-
-#define duk_compile_string(ctx,flags,src) \
- ((void) duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
-
-#define duk_compile_string_filename(ctx,flags,src) \
- ((void) duk_compile_raw((ctx), (src), 0, 2 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN))
-
-#define duk_pcompile_string(ctx,flags,src) \
- (duk_compile_raw((ctx), (src), 0, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN | DUK_COMPILE_NOFILENAME))
-
-#define duk_pcompile_string_filename(ctx,flags,src) \
- (duk_compile_raw((ctx), (src), 0, 2 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_STRLEN))
-
-/* lstring */
-#define duk_eval_lstring(ctx,buf,len) \
- ((void) duk_eval_raw((ctx), buf, len, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
-
-#define duk_eval_lstring_noresult(ctx,buf,len) \
- ((void) duk_eval_raw((ctx), buf, len, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
-
-#define duk_peval_lstring(ctx,buf,len) \
- (duk_eval_raw((ctx), buf, len, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NOSOURCE | DUK_COMPILE_SAFE | DUK_COMPILE_NOFILENAME))
-
-#define duk_peval_lstring_noresult(ctx,buf,len) \
- (duk_eval_raw((ctx), buf, len, 1 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NORESULT | DUK_COMPILE_NOFILENAME))
-
-#define duk_compile_lstring(ctx,flags,buf,len) \
- ((void) duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
-
-#define duk_compile_lstring_filename(ctx,flags,buf,len) \
- ((void) duk_compile_raw((ctx), buf, len, 2 /*args*/ | (flags) | DUK_COMPILE_NOSOURCE))
-
-#define duk_pcompile_lstring(ctx,flags,buf,len) \
- (duk_compile_raw((ctx), buf, len, 1 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE | DUK_COMPILE_NOFILENAME))
-
-#define duk_pcompile_lstring_filename(ctx,flags,buf,len) \
- (duk_compile_raw((ctx), buf, len, 2 /*args*/ | (flags) | DUK_COMPILE_SAFE | DUK_COMPILE_NOSOURCE))
-
-/* file */
-#define duk_eval_file(ctx,path) \
- ((void) duk_push_string_file_raw((ctx), (path), 0), \
- (void) duk_push_string((ctx), (path)), \
- (void) duk_eval_raw((ctx), NULL, 0, 3 /*args*/ | DUK_COMPILE_EVAL))
-
-#define duk_eval_file_noresult(ctx,path) \
- ((void) duk_push_string_file_raw((ctx), (path), 0), \
- (void) duk_push_string((ctx), (path)), \
- (void) duk_eval_raw((ctx), NULL, 0, 3 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_NORESULT))
-
-#define duk_peval_file(ctx,path) \
- ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \
- (void) duk_push_string((ctx), (path)), \
- duk_eval_raw((ctx), NULL, 0, 3 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE))
-
-#define duk_peval_file_noresult(ctx,path) \
- ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \
- (void) duk_push_string((ctx), (path)), \
- duk_eval_raw((ctx), NULL, 0, 3 /*args*/ | DUK_COMPILE_EVAL | DUK_COMPILE_SAFE | DUK_COMPILE_NORESULT))
-
-#define duk_compile_file(ctx,flags,path) \
- ((void) duk_push_string_file_raw((ctx), (path), 0), \
- (void) duk_push_string((ctx), (path)), \
- (void) duk_compile_raw((ctx), NULL, 0, 3 /*args*/ | (flags)))
-
-#define duk_pcompile_file(ctx,flags,path) \
- ((void) duk_push_string_file_raw((ctx), (path), DUK_STRING_PUSH_SAFE), \
- (void) duk_push_string((ctx), (path)), \
- duk_compile_raw((ctx), NULL, 0, 3 /*args*/ | (flags) | DUK_COMPILE_SAFE))
-
-/*
- * Bytecode load/dump
- */
-
-DUK_EXTERNAL_DECL void duk_dump_function(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_load_function(duk_context *ctx);
-
-/*
- * Logging
- */
-
-DUK_EXTERNAL_DECL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...);
-DUK_EXTERNAL_DECL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap);
-
-/*
- * Debugging
- */
-
-DUK_EXTERNAL_DECL void duk_push_context_dump(duk_context *ctx);
-
-#if defined(DUK_USE_FILE_IO)
-/* internal use */
-#define duk_dump_context_filehandle(ctx,fh) \
- (duk_push_context_dump((ctx)), \
- DUK_FPRINTF((fh), "%s\n", duk_safe_to_string(ctx, -1)), \
- duk_pop(ctx))
-
-/* external use */
-#define duk_dump_context_stdout(ctx) \
- duk_dump_context_filehandle((ctx), DUK_STDOUT)
-#define duk_dump_context_stderr(ctx) \
- duk_dump_context_filehandle((ctx), DUK_STDERR)
-#else /* DUK_USE_FILE_IO */
-#define duk_dump_context_stdout(ctx) ((void) 0)
-#define duk_dump_context_stderr(ctx) ((void) 0)
-#endif /* DUK_USE_FILE_IO */
-
-/*
- * Debugger (debug protocol)
- */
-
-#define duk_debugger_attach(ctx,read_cb,write_cb,peek_cb,read_flush_cb,write_flush_cb,detached_cb,udata) \
- duk_debugger_attach_custom((ctx), (read_cb), (write_cb), (peek_cb), (read_flush_cb), (write_flush_cb), \
- NULL, (detached_cb), (udata))
-
-DUK_EXTERNAL_DECL void duk_debugger_attach_custom(duk_context *ctx,
- duk_debug_read_function read_cb,
- duk_debug_write_function write_cb,
- duk_debug_peek_function peek_cb,
- duk_debug_read_flush_function read_flush_cb,
- duk_debug_write_flush_function write_flush_cb,
- duk_debug_request_function request_cb,
- duk_debug_detached_function detached_cb,
- void *udata);
-DUK_EXTERNAL_DECL void duk_debugger_detach(duk_context *ctx);
-DUK_EXTERNAL_DECL void duk_debugger_cooperate(duk_context *ctx);
-DUK_EXTERNAL_DECL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues);
-DUK_EXTERNAL_DECL void duk_debugger_pause(duk_context *ctx);
-
-/*
- * Date provider related constants
- *
- * NOTE: These are "semi public" - you should only use these if you write
- * your own platform specific Date provider, see doc/datetime.rst.
- */
-
-/* Millisecond count constants. */
-#define DUK_DATE_MSEC_SECOND 1000L
-#define DUK_DATE_MSEC_MINUTE (60L * 1000L)
-#define DUK_DATE_MSEC_HOUR (60L * 60L * 1000L)
-#define DUK_DATE_MSEC_DAY (24L * 60L * 60L * 1000L)
-
-/* Ecmascript date range is 100 million days from Epoch:
- * > 100e6 * 24 * 60 * 60 * 1000 // 100M days in millisecs
- * 8640000000000000
- * (= 8.64e15)
- */
-#define DUK_DATE_MSEC_100M_DAYS (8.64e15)
-#define DUK_DATE_MSEC_100M_DAYS_LEEWAY (8.64e15 + 24 * 3600e3)
-
-/* Ecmascript year range:
- * > new Date(100e6 * 24 * 3600e3).toISOString()
- * '+275760-09-13T00:00:00.000Z'
- * > new Date(-100e6 * 24 * 3600e3).toISOString()
- * '-271821-04-20T00:00:00.000Z'
- */
-#define DUK_DATE_MIN_ECMA_YEAR (-271821L)
-#define DUK_DATE_MAX_ECMA_YEAR 275760L
-
-/* Part indices for internal breakdowns. Part order from DUK_DATE_IDX_YEAR
- * to DUK_DATE_IDX_MILLISECOND matches argument ordering of Ecmascript API
- * calls (like Date constructor call). Some functions in duk_bi_date.c
- * depend on the specific ordering, so change with care. 16 bits are not
- * enough for all parts (year, specifically).
- *
- * (Must be in-sync with genbuiltins.py.)
- */
-#define DUK_DATE_IDX_YEAR 0 /* year */
-#define DUK_DATE_IDX_MONTH 1 /* month: 0 to 11 */
-#define DUK_DATE_IDX_DAY 2 /* day within month: 0 to 30 */
-#define DUK_DATE_IDX_HOUR 3
-#define DUK_DATE_IDX_MINUTE 4
-#define DUK_DATE_IDX_SECOND 5
-#define DUK_DATE_IDX_MILLISECOND 6
-#define DUK_DATE_IDX_WEEKDAY 7 /* weekday: 0 to 6, 0=sunday, 1=monday, etc */
-#define DUK_DATE_IDX_NUM_PARTS 8
-
-/* Internal API call flags, used for various functions in this file.
- * Certain flags are used by only certain functions, but since the flags
- * don't overlap, a single flags value can be passed around to multiple
- * functions.
- *
- * The unused top bits of the flags field are also used to pass values
- * to helpers (duk__get_part_helper() and duk__set_part_helper()).
- *
- * (Must be in-sync with genbuiltins.py.)
- */
-
-/* NOTE: when writing a Date provider you only need a few specific
- * flags from here, the rest are internal. Avoid using anything you
- * don't need.
- */
-
-#define DUK_DATE_FLAG_NAN_TO_ZERO (1 << 0) /* timeval breakdown: internal time value NaN -> zero */
-#define DUK_DATE_FLAG_NAN_TO_RANGE_ERROR (1 << 1) /* timeval breakdown: internal time value NaN -> RangeError (toISOString) */
-#define DUK_DATE_FLAG_ONEBASED (1 << 2) /* timeval breakdown: convert month and day-of-month parts to one-based (default is zero-based) */
-#define DUK_DATE_FLAG_EQUIVYEAR (1 << 3) /* timeval breakdown: replace year with equivalent year in the [1971,2037] range for DST calculations */
-#define DUK_DATE_FLAG_LOCALTIME (1 << 4) /* convert time value to local time */
-#define DUK_DATE_FLAG_SUB1900 (1 << 5) /* getter: subtract 1900 from year when getting year part */
-#define DUK_DATE_FLAG_TOSTRING_DATE (1 << 6) /* include date part in string conversion result */
-#define DUK_DATE_FLAG_TOSTRING_TIME (1 << 7) /* include time part in string conversion result */
-#define DUK_DATE_FLAG_TOSTRING_LOCALE (1 << 8) /* use locale specific formatting if available */
-#define DUK_DATE_FLAG_TIMESETTER (1 << 9) /* setter: call is a time setter (affects hour, min, sec, ms); otherwise date setter (affects year, month, day-in-month) */
-#define DUK_DATE_FLAG_YEAR_FIXUP (1 << 10) /* setter: perform 2-digit year fixup (00...99 -> 1900...1999) */
-#define DUK_DATE_FLAG_SEP_T (1 << 11) /* string conversion: use 'T' instead of ' ' as a separator */
-#define DUK_DATE_FLAG_VALUE_SHIFT 12 /* additional values begin at bit 12 */
-
-/*
- * ROM pointer compression
- */
-
-/* Support array for ROM pointer compression. Only declared when ROM
- * pointer compression is active.
- */
-#if defined(DUK_USE_ROM_OBJECTS) && defined(DUK_USE_HEAPPTR16)
-DUK_EXTERNAL_DECL const void * const duk_rom_compressed_pointers[];
-#endif
-
-/*
- * C++ name mangling
- */
-
-#ifdef __cplusplus
-/* end 'extern "C"' wrapper */
-}
-#endif
-
-#endif /* DUK_API_PUBLIC_H_INCLUDED */
-
-/*
- * END PUBLIC API
- */
-
-/*
- * Union to access IEEE double memory representation, indexes for double
- * memory representation, and some macros for double manipulation.
- *
- * Also used by packed duk_tval. Use a union for bit manipulation to
- * minimize aliasing issues in practice. The C99 standard does not
- * guarantee that this should work, but it's a very widely supported
- * practice for low level manipulation.
- *
- * IEEE double format summary:
- *
- * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
- * A B C D E F G H
- *
- * s sign bit
- * eee... exponent field
- * fff... fraction
- *
- * See http://en.wikipedia.org/wiki/Double_precision_floating-point_format.
- *
- * NaNs are represented as exponent 0x7ff and mantissa != 0. The NaN is a
- * signaling NaN when the highest bit of the mantissa is zero, and a quiet
- * NaN when the highest bit is set.
- *
- * At least three memory layouts are relevant here:
- *
- * A B C D E F G H Big endian (e.g. 68k) DUK_USE_DOUBLE_BE
- * H G F E D C B A Little endian (e.g. x86) DUK_USE_DOUBLE_LE
- * D C B A H G F E Mixed/cross endian (e.g. ARM) DUK_USE_DOUBLE_ME
- *
- * ARM is a special case: ARM double values are in mixed/cross endian
- * format while ARM duk_uint64_t values are in standard little endian
- * format (H G F E D C B A). When a double is read as a duk_uint64_t
- * from memory, the register will contain the (logical) value
- * E F G H A B C D. This requires some special handling below.
- *
- * Indexes of various types (8-bit, 16-bit, 32-bit) in memory relative to
- * the logical (big endian) order:
- *
- * byte order duk_uint8_t duk_uint16_t duk_uint32_t
- * BE 01234567 0123 01
- * LE 76543210 3210 10
- * ME (ARM) 32107654 1032 01
- *
- * Some processors may alter NaN values in a floating point load+store.
- * For instance, on X86 a FLD + FSTP may convert a signaling NaN to a
- * quiet one. This is catastrophic when NaN space is used in packed
- * duk_tval values. See: misc/clang_aliasing.c.
- */
-
-#ifndef DUK_DBLUNION_H_INCLUDED
-#define DUK_DBLUNION_H_INCLUDED
-
-/*
- * Union for accessing double parts, also serves as packed duk_tval
- */
-
-union duk_double_union {
- double d;
- float f[2];
-#if defined(DUK_USE_64BIT_OPS)
- duk_uint64_t ull[1];
-#endif
- duk_uint32_t ui[2];
- duk_uint16_t us[4];
- duk_uint8_t uc[8];
-#if defined(DUK_USE_PACKED_TVAL)
- void *vp[2]; /* used by packed duk_tval, assumes sizeof(void *) == 4 */
-#endif
-};
-
-typedef union duk_double_union duk_double_union;
-
-/*
- * Indexes of various types with respect to big endian (logical) layout
- */
-
-#if defined(DUK_USE_DOUBLE_LE)
-#ifdef DUK_USE_64BIT_OPS
-#define DUK_DBL_IDX_ULL0 0
-#endif
-#define DUK_DBL_IDX_UI0 1
-#define DUK_DBL_IDX_UI1 0
-#define DUK_DBL_IDX_US0 3
-#define DUK_DBL_IDX_US1 2
-#define DUK_DBL_IDX_US2 1
-#define DUK_DBL_IDX_US3 0
-#define DUK_DBL_IDX_UC0 7
-#define DUK_DBL_IDX_UC1 6
-#define DUK_DBL_IDX_UC2 5
-#define DUK_DBL_IDX_UC3 4
-#define DUK_DBL_IDX_UC4 3
-#define DUK_DBL_IDX_UC5 2
-#define DUK_DBL_IDX_UC6 1
-#define DUK_DBL_IDX_UC7 0
-#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
-#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
-#elif defined(DUK_USE_DOUBLE_BE)
-#ifdef DUK_USE_64BIT_OPS
-#define DUK_DBL_IDX_ULL0 0
-#endif
-#define DUK_DBL_IDX_UI0 0
-#define DUK_DBL_IDX_UI1 1
-#define DUK_DBL_IDX_US0 0
-#define DUK_DBL_IDX_US1 1
-#define DUK_DBL_IDX_US2 2
-#define DUK_DBL_IDX_US3 3
-#define DUK_DBL_IDX_UC0 0
-#define DUK_DBL_IDX_UC1 1
-#define DUK_DBL_IDX_UC2 2
-#define DUK_DBL_IDX_UC3 3
-#define DUK_DBL_IDX_UC4 4
-#define DUK_DBL_IDX_UC5 5
-#define DUK_DBL_IDX_UC6 6
-#define DUK_DBL_IDX_UC7 7
-#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
-#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
-#elif defined(DUK_USE_DOUBLE_ME)
-#ifdef DUK_USE_64BIT_OPS
-#define DUK_DBL_IDX_ULL0 0 /* not directly applicable, byte order differs from a double */
-#endif
-#define DUK_DBL_IDX_UI0 0
-#define DUK_DBL_IDX_UI1 1
-#define DUK_DBL_IDX_US0 1
-#define DUK_DBL_IDX_US1 0
-#define DUK_DBL_IDX_US2 3
-#define DUK_DBL_IDX_US3 2
-#define DUK_DBL_IDX_UC0 3
-#define DUK_DBL_IDX_UC1 2
-#define DUK_DBL_IDX_UC2 1
-#define DUK_DBL_IDX_UC3 0
-#define DUK_DBL_IDX_UC4 7
-#define DUK_DBL_IDX_UC5 6
-#define DUK_DBL_IDX_UC6 5
-#define DUK_DBL_IDX_UC7 4
-#define DUK_DBL_IDX_VP0 DUK_DBL_IDX_UI0 /* packed tval */
-#define DUK_DBL_IDX_VP1 DUK_DBL_IDX_UI1 /* packed tval */
-#else
-#error internal error
-#endif
-
-/*
- * Helper macros for reading/writing memory representation parts, used
- * by duk_numconv.c and duk_tval.h.
- */
-
-#define DUK_DBLUNION_SET_DOUBLE(u,v) do { \
- (u)->d = (v); \
- } while (0)
-
-#define DUK_DBLUNION_SET_HIGH32(u,v) do { \
- (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
- } while (0)
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
- } while (0)
-#else
-#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = ((duk_uint64_t) (v)) << 32; \
- } while (0)
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK_DBLUNION_SET_HIGH32_ZERO_LOW32(u,v) do { \
- (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) (v); \
- (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0; \
- } while (0)
-#endif /* DUK_USE_64BIT_OPS */
-
-#define DUK_DBLUNION_SET_LOW32(u,v) do { \
- (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
- } while (0)
-
-#define DUK_DBLUNION_GET_DOUBLE(u) ((u)->d)
-#define DUK_DBLUNION_GET_HIGH32(u) ((u)->ui[DUK_DBL_IDX_UI0])
-#define DUK_DBLUNION_GET_LOW32(u) ((u)->ui[DUK_DBL_IDX_UI1])
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK_DBLUNION_SET_UINT64(u,v) do { \
- (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) ((v) >> 32); \
- (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (v); \
- } while (0)
-#define DUK_DBLUNION_GET_UINT64(u) \
- ((((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI0]) << 32) | \
- ((duk_uint64_t) (u)->ui[DUK_DBL_IDX_UI1]))
-#else
-#define DUK_DBLUNION_SET_UINT64(u,v) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = (duk_uint64_t) (v); \
- } while (0)
-#define DUK_DBLUNION_GET_UINT64(u) ((u)->ull[DUK_DBL_IDX_ULL0])
-#endif
-#define DUK_DBLUNION_SET_INT64(u,v) DUK_DBLUNION_SET_UINT64((u), (duk_uint64_t) (v))
-#define DUK_DBLUNION_GET_INT64(u) ((duk_int64_t) DUK_DBLUNION_GET_UINT64((u)))
-#endif /* DUK_USE_64BIT_OPS */
-
-/*
- * Double NaN manipulation macros related to NaN normalization needed when
- * using the packed duk_tval representation. NaN normalization is necessary
- * to keep double values compatible with the duk_tval format.
- *
- * When packed duk_tval is used, the NaN space is used to store pointers
- * and other tagged values in addition to NaNs. Actual NaNs are normalized
- * to a specific quiet NaN. The macros below are used by the implementation
- * to check and normalize NaN values when they might be created. The macros
- * are essentially NOPs when the non-packed duk_tval representation is used.
- *
- * A FULL check is exact and checks all bits. A NOTFULL check is used by
- * the packed duk_tval and works correctly for all NaNs except those that
- * begin with 0x7ff0. Since the 'normalized NaN' values used with packed
- * duk_tval begin with 0x7ff8, the partial check is reliable when packed
- * duk_tval is used. The 0x7ff8 prefix means the normalized NaN will be a
- * quiet NaN regardless of its remaining lower bits.
- *
- * The ME variant below is specifically for ARM byte order, which has the
- * feature that while doubles have a mixed byte order (32107654), unsigned
- * long long values has a little endian byte order (76543210). When writing
- * a logical double value through a ULL pointer, the 32-bit words need to be
- * swapped; hence the #ifdefs below for ULL writes with DUK_USE_DOUBLE_ME.
- * This is not full ARM support but suffices for some environments.
- */
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = 0x000000007ff80000ULL; \
- } while (0)
-#else
-#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
- (u)->ull[DUK_DBL_IDX_ULL0] = 0x7ff8000000000000ULL; \
- } while (0)
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK__DBLUNION_SET_NAN_FULL(u) do { \
- (u)->ui[DUK_DBL_IDX_UI0] = (duk_uint32_t) 0x7ff80000UL; \
- (u)->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) 0x00000000UL; \
- } while (0)
-#endif /* DUK_USE_64BIT_OPS */
-
-#define DUK__DBLUNION_SET_NAN_NOTFULL(u) do { \
- (u)->us[DUK_DBL_IDX_US0] = 0x7ff8UL; \
- } while (0)
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK__DBLUNION_IS_NAN_FULL(u) \
- /* E == 0x7ff, F != 0 => NaN */ \
- ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
- ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0xffffffff000fffffULL) != 0))
-#else
-#define DUK__DBLUNION_IS_NAN_FULL(u) \
- /* E == 0x7ff, F != 0 => NaN */ \
- ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
- ((((u)->ull[DUK_DBL_IDX_ULL0]) & 0x000fffffffffffffULL) != 0))
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK__DBLUNION_IS_NAN_FULL(u) \
- /* E == 0x7ff, F != 0 => NaN */ \
- ((((u)->ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL) && \
- (((u)->ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) != 0 || \
- (u)->ui[DUK_DBL_IDX_UI1] != 0))
-#endif /* DUK_USE_64BIT_OPS */
-
-#define DUK__DBLUNION_IS_NAN_NOTFULL(u) \
- /* E == 0x7ff, topmost four bits of F != 0 => assume NaN */ \
- ((((u)->us[DUK_DBL_IDX_US0] & 0x7ff0UL) == 0x7ff0UL) && \
- (((u)->us[DUK_DBL_IDX_US0] & 0x000fUL) != 0x0000UL))
-
-#ifdef DUK_USE_64BIT_OPS
-#ifdef DUK_USE_DOUBLE_ME
-#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x000000007ff80000ULL)
-#else
-#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
- ((u)->ull[DUK_DBL_IDX_ULL0] == 0x7ff8000000000000ULL)
-#endif
-#else /* DUK_USE_64BIT_OPS */
-#define DUK__DBLUNION_IS_NORMALIZED_NAN_FULL(u) \
- (((u)->ui[DUK_DBL_IDX_UI0] == 0x7ff80000UL) && \
- ((u)->ui[DUK_DBL_IDX_UI1] == 0x00000000UL))
-#endif /* DUK_USE_64BIT_OPS */
-
-#define DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL(u) \
- /* E == 0x7ff, F == 8 => normalized NaN */ \
- ((u)->us[DUK_DBL_IDX_US0] == 0x7ff8UL)
-
-#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL(u) do { \
- if (DUK__DBLUNION_IS_NAN_FULL((u))) { \
- DUK__DBLUNION_SET_NAN_FULL((u)); \
- } \
- } while (0)
-
-#define DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL(u) do { \
- if (DUK__DBLUNION_IS_NAN_NOTFULL((u))) { \
- DUK__DBLUNION_SET_NAN_NOTFULL((u)); \
- } \
- } while (0)
-
-/* Concrete macros for NaN handling used by the implementation internals.
- * Chosen so that they match the duk_tval representation: with a packed
- * duk_tval, ensure NaNs are properly normalized; with a non-packed duk_tval
- * these are essentially NOPs.
- */
-
-#if defined(DUK_USE_PACKED_TVAL)
-#if defined(DUK_USE_FULL_TVAL)
-#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_FULL((u))
-#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_FULL((u))
-#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_FULL((u))
-#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_FULL((d))
-#else
-#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) DUK__DBLUNION_NORMALIZE_NAN_CHECK_NOTFULL((u))
-#define DUK_DBLUNION_IS_NAN(u) DUK__DBLUNION_IS_NAN_NOTFULL((u))
-#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) DUK__DBLUNION_IS_NORMALIZED_NAN_NOTFULL((u))
-#define DUK_DBLUNION_SET_NAN(d) DUK__DBLUNION_SET_NAN_NOTFULL((d))
-#endif
-#define DUK_DBLUNION_IS_NORMALIZED(u) \
- (!DUK_DBLUNION_IS_NAN((u)) || /* either not a NaN */ \
- DUK_DBLUNION_IS_NORMALIZED_NAN((u))) /* or is a normalized NaN */
-#else /* DUK_USE_PACKED_TVAL */
-#define DUK_DBLUNION_NORMALIZE_NAN_CHECK(u) /* nop: no need to normalize */
-#define DUK_DBLUNION_IS_NAN(u) (DUK_ISNAN((u)->d))
-#define DUK_DBLUNION_IS_NORMALIZED_NAN(u) (DUK_ISNAN((u)->d))
-#define DUK_DBLUNION_IS_NORMALIZED(u) 1 /* all doubles are considered normalized */
-#define DUK_DBLUNION_SET_NAN(u) do { \
- /* in non-packed representation we don't care about which NaN is used */ \
- (u)->d = DUK_DOUBLE_NAN; \
- } while (0)
-#endif /* DUK_USE_PACKED_TVAL */
-
-/* XXX: native 64-bit byteswaps when available */
-
-/* 64-bit byteswap, same operation independent of target endianness. */
-#define DUK_DBLUNION_BSWAP64(u) do { \
- duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
- duk__bswaptmp1 = (u)->ui[0]; \
- duk__bswaptmp2 = (u)->ui[1]; \
- duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
- duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
- (u)->ui[0] = duk__bswaptmp2; \
- (u)->ui[1] = duk__bswaptmp1; \
- } while (0)
-
-/* Byteswap an IEEE double in the duk_double_union from host to network
- * order. For a big endian target this is a no-op.
- */
-#if defined(DUK_USE_DOUBLE_LE)
-#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
- duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
- duk__bswaptmp1 = (u)->ui[0]; \
- duk__bswaptmp2 = (u)->ui[1]; \
- duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
- duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
- (u)->ui[0] = duk__bswaptmp2; \
- (u)->ui[1] = duk__bswaptmp1; \
- } while (0)
-#elif defined(DUK_USE_DOUBLE_ME)
-#define DUK_DBLUNION_DOUBLE_HTON(u) do { \
- duk_uint32_t duk__bswaptmp1, duk__bswaptmp2; \
- duk__bswaptmp1 = (u)->ui[0]; \
- duk__bswaptmp2 = (u)->ui[1]; \
- duk__bswaptmp1 = DUK_BSWAP32(duk__bswaptmp1); \
- duk__bswaptmp2 = DUK_BSWAP32(duk__bswaptmp2); \
- (u)->ui[0] = duk__bswaptmp1; \
- (u)->ui[1] = duk__bswaptmp2; \
- } while (0)
-#elif defined(DUK_USE_DOUBLE_BE)
-#define DUK_DBLUNION_DOUBLE_HTON(u) do { } while (0)
-#else
-#error internal error, double endianness insane
-#endif
-
-/* Reverse operation is the same. */
-#define DUK_DBLUNION_DOUBLE_NTOH(u) DUK_DBLUNION_DOUBLE_HTON((u))
-
-#endif /* DUK_DBLUNION_H_INCLUDED */
-
-#endif /* DUKTAPE_H_INCLUDED */
diff --git a/javascript/duktape/netsurf.bnd b/javascript/duktape/netsurf.bnd
deleted file mode 100644
index 4aca4752f..000000000
--- a/javascript/duktape/netsurf.bnd
+++ /dev/null
@@ -1,200 +0,0 @@
-/* Binding for browser using duktape and libdom
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-binding duk_libdom {
- webidl "dom.idl";
- webidl "dom-parsing.idl";
- webidl "html.idl";
- webidl "cssom.idl";
- webidl "uievents.idl";
- webidl "urlutils.idl";
- webidl "console.idl";
-
- preface %{
-/* DukTape JavaScript bindings for NetSurf browser
- *
- * Copyright 2015 Vincent Sanders <vince@netsurf-browser.org>
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- * Released under the terms of the MIT License,
- * http://www.opensource.org/licenses/mit-license
- */
-
-#include <dom/dom.h>
-
-#include "utils/log.h"
-#include "utils/nsurl.h"
-
-#include "javascript/duktape/duktape.h"
-
-struct browser_window;
-struct html_content;
-struct dom_node;
-struct dom_element;
-struct dom_document;
-struct dom_html_element;
-struct dom_node_character_data;
-struct dom_node_text;
-struct dom_node_list;
-struct dom_node_comment;
-struct dom_html_collection;
-struct dom_html_br_element;
-
-%};
-
- prologue %{
-#include "javascript/duktape/dukky.h"
-%};
-
-};
-
-#include "Console.bnd"
-#include "Window.bnd"
-#include "Document.bnd"
-#include "Node.bnd"
-#include "NodeList.bnd"
-#include "Element.bnd"
-#include "HTMLCollection.bnd"
-#include "Location.bnd"
-#include "Navigator.bnd"
-
-/* events */
-
-#include "Event.bnd"
-
-init MutationEvent(struct dom_mutation_event *evt::evt);
-init UIEvent(struct dom_ui_event *evt::evt);
-init TextEvent(struct dom_text_event *evt::evt);
-init MutationNameEvent(struct dom_mutation_name_event *evt::evt);
-init MouseWheelEvent(struct dom_mouse_wheel_event *evt::evt);
-init MouseMultiWheelEvent(struct dom_mouse_multi_wheel_event *evt::evt);
-init MouseEvent(struct dom_mouse_event *evt::evt);
-init KeyboardEvent(struct dom_keyboard_event *evt::evt);
-init DocumentEvent(struct dom_document_event *evt::evt);
-init CustomEvent(struct dom_custom_event *evt::evt);
-init CompositionEvent(struct dom_ui_event *evt::evt);
-init WheelEvent(struct dom_mouse_event *evt::evt);
-init FocusEvent(struct dom_ui_event *evt::evt);
-init StorageEvent(struct dom_event *evt::evt);
-init CloseEvent(struct dom_event *evt::evt);
-init MessageEvent(struct dom_event *evt::evt);
-init ErrorEvent(struct dom_event *evt::evt);
-init BeforeUnloadEvent(struct dom_event *evt::evt);
-init PageTransitionEvent(struct dom_event *evt::evt);
-init HashChangeEvent(struct dom_event *evt::evt);
-init PopStateEvent(struct dom_event *evt::evt);
-init DragEvent(struct dom_mouse_event *evt::evt);
-init RelatedEvent(struct dom_event *evt::evt);
-init AutocompleteErrorEvent(struct dom_event *evt::evt);
-init TrackEvent(struct dom_event *evt::evt);
-
-
-/* html elements */
-#include "HTMLElement.bnd"
-
-/* specialisations of html_element */
-#include "HTMLAnchorElement.bnd"
-#include "HTMLAppletElement.bnd"
-#include "HTMLAreaElement.bnd"
-#include "HTMLBaseElement.bnd"
-#include "HTMLBodyElement.bnd"
-#include "HTMLButtonElement.bnd"
-#include "HTMLBRElement.bnd"
-#include "HTMLDivElement.bnd"
-#include "HTMLFontElement.bnd"
-#include "HTMLFormElement.bnd"
-#include "HTMLFrameElement.bnd"
-#include "HTMLFrameSetElement.bnd"
-#include "HTMLHeadingElement.bnd"
-#include "HTMLHRElement.bnd"
-#include "HTMLHTMLElement.bnd"
-#include "HTMLIFrameElement.bnd"
-#include "HTMLImageElement.bnd"
-#include "HTMLInputElement.bnd"
-#include "HTMLLabelElement.bnd"
-#include "HTMLLegendElement.bnd"
-#include "HTMLLIElement.bnd"
-#include "HTMLLinkElement.bnd"
-#include "HTMLMapElement.bnd"
-#include "HTMLMarqueeElement.bnd"
-#include "HTMLMenuElement.bnd"
-#include "HTMLMetaElement.bnd"
-#include "HTMLObjectElement.bnd"
-#include "HTMLOptionElement.bnd"
-#include "HTMLOListElement.bnd"
-#include "HTMLParagraphElement.bnd"
-#include "HTMLParamElement.bnd"
-#include "HTMLPreElement.bnd"
-#include "HTMLQuoteElement.bnd"
-#include "HTMLScriptElement.bnd"
-#include "HTMLSelectElement.bnd"
-#include "HTMLStyleElement.bnd"
-#include "HTMLTableCaptionElement.bnd"
-#include "HTMLTableCellElement.bnd"
-#include "HTMLTableColElement.bnd"
-#include "HTMLTableElement.bnd"
-#include "HTMLTableRowElement.bnd"
-#include "HTMLTableSectionElement.bnd"
-#include "HTMLTextAreaElement.bnd"
-#include "HTMLTitleElement.bnd"
-
-init HTMLUnknownElement(struct dom_html_element *html_unknown_element::html_element);
-init HTMLDirectoryElement(struct dom_html_element *html_directory_element::html_element);
-init HTMLCanvasElement(struct dom_html_element *html_canvas_element::html_element);
-init HTMLTemplateElement(struct dom_html_element *html_template_element::html_element);
-init HTMLDialogElement(struct dom_html_element *html_dialog_element::html_element);
-init HTMLMenuItemElement(struct dom_html_element *html_menu_item_element::html_element);
-init HTMLDetailsElement(struct dom_html_element *html_details_element::html_element);
-init HTMLFieldSetElement(struct dom_html_element *html_field_set_element::html_element);
-init HTMLMeterElement(struct dom_html_element *html_meter_element::html_element);
-init HTMLProgressElement(struct dom_html_element *html_progress_element::html_element);
-init HTMLOutputElement(struct dom_html_element *html_output_element::html_element);
-init HTMLKeygenElement(struct dom_html_element *html_keygen_element::html_element);
-init HTMLOptGroupElement(struct dom_html_element *html_opt_group_element::html_element);
-init HTMLDataListElement(struct dom_html_element *html_data_list_element::html_element);
-init HTMLMediaElement(struct dom_html_element *html_media_element::html_element);
-init HTMLTrackElement(struct dom_html_element *html_track_element::html_element);
-init HTMLEmbedElement(struct dom_html_element *html_embed_element::html_element);
-init HTMLSourceElement(struct dom_html_element *html_source_element::html_element);
-init HTMLPictureElement(struct dom_html_element *html_picture_element::html_element);
-init HTMLModElement(struct dom_html_element *html_mod_element::html_element);
-init HTMLSpanElement(struct dom_html_element *html_span_element::html_element);
-init HTMLTimeElement(struct dom_html_element *html_time_element::html_element);
-init HTMLDataElement(struct dom_html_element *html_data_element::html_element);
-init HTMLDListElement(struct dom_html_element *html_d_list_element::html_element);
-init HTMLUListElement(struct dom_html_element *html_u_list_element::html_element);
-init HTMLHeadElement(struct dom_html_element *html_head_element::html_element);
-
-/* specialisations of HTMLTableCellElement */
-init HTMLTableHeaderCellElement(struct dom_html_element *html_table_header_cell_element::html_table_cell_element);
-init HTMLTableDataCellElement(struct dom_html_element *html_table_data_cell_element::html_table_cell_element);
-
-/* specialisations of html_media_element */
-init HTMLAudioElement(struct dom_html_element *html_audio_element::html_media_element);
-init HTMLVideoElement(struct dom_html_element *html_video_element::html_media_element);
-
-init Text(struct dom_node_text *text::character_data);
-init Comment(struct dom_node_comment *comment::character_data);
-init ProcessingInstruction(struct dom_node_text *text::character_data);
-
-init XMLDocument(struct dom_document *document);
-
-init CharacterData(struct dom_node_character_data *character_data::node);
-init DocumentFragment(struct dom_document *document::node);
-init DocumentType(struct dom_document *document::node);
-
-init PropertyNodeList(struct dom_nodelist *nodes);
-init RadioNodeList(struct dom_nodelist *nodes);
-
-init HTMLAllCollection(struct dom_html_collection *coll);
-init HTMLFormControlsCollection(struct dom_html_collection *coll);
-init HTMLOptionsCollection(struct dom_html_collection *coll);
-init HTMLPropertiesCollection(struct dom_html_collection *coll);
-
-
diff --git a/javascript/fetcher.c b/javascript/fetcher.c
deleted file mode 100644
index 839df265a..000000000
--- a/javascript/fetcher.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2012 Vincent Sanders <vince@kyllikki.org>
- *
- * 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/>.
- */
-
-/** \file
- * implementation for javascript scheme fetcher
- *
- * This fetcher implements http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#javascript-protocol
- */
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <libwapcaplet/libwapcaplet.h>
-
-#include "utils/nsurl.h"
-#include "utils/corestrings.h"
-#include "utils/ring.h"
-#include "content/fetch.h"
-#include "content/fetchers.h"
-
-#include "javascript/fetcher.h"
-
-/** Context for an resource fetch */
-struct fetch_javascript_context {
- struct fetch_javascript_context *r_next, *r_prev;
-
- struct fetch *fetchh; /**< Handle for this fetch */
-
- bool aborted; /**< Flag indicating fetch has been aborted */
- bool locked; /**< Flag indicating entry is already entered */
-
- nsurl *url; /**< The URL being fetched */
-};
-
-static struct fetch_javascript_context *ring = NULL;
-
-
-/** issue fetch callbacks with locking */
-static inline bool fetch_javascript_send_callback(const fetch_msg *msg,
- struct fetch_javascript_context *ctx)
-{
- ctx->locked = true;
- fetch_send_callback(msg, ctx->fetchh);
- ctx->locked = false;
-
- return ctx->aborted;
-}
-
-
-/**
- * called from poll to progress fetch.
- *
- * \todo This is currently completely unimplemented and just returns 204
- */
-static bool fetch_javascript_handler(struct fetch_javascript_context *ctx)
-{
- fetch_msg msg;
- int code = 204;
-
- /* content is going to return error code */
- fetch_set_http_code(ctx->fetchh, code);
-
- msg.type = FETCH_FINISHED;
- fetch_javascript_send_callback(&msg, ctx);
-
- return true;
-}
-
-
-
-/** callback to initialise the resource fetcher. */
-static bool fetch_javascript_initialise(lwc_string *scheme)
-{
- return true;
-}
-
-/** callback to finalise the resource fetcher. */
-static void fetch_javascript_finalise(lwc_string *scheme)
-{
-}
-
-static bool fetch_javascript_can_fetch(const nsurl *url)
-{
- return true;
-}
-
-/** callback to set up a resource fetch context. */
-static void *
-fetch_javascript_setup(struct fetch *fetchh,
- nsurl *url,
- bool only_2xx,
- bool downgrade_tls,
- const char *post_urlenc,
- const struct fetch_multipart_data *post_multipart,
- const char **headers)
-{
- struct fetch_javascript_context *ctx;
-
- ctx = calloc(1, sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- ctx->url = nsurl_ref(url);
-
- ctx->fetchh = fetchh;
-
- RING_INSERT(ring, ctx);
-
- return ctx;
-}
-
-/** callback to free a resource fetch */
-static void fetch_javascript_free(void *ctx)
-{
- struct fetch_javascript_context *c = ctx;
- if (c->url != NULL) {
- nsurl_unref(c->url);
- }
- RING_REMOVE(ring, c);
- free(ctx);
-}
-
-/** callback to start a resource fetch */
-static bool fetch_javascript_start(void *ctx)
-{
- return true;
-}
-
-/** callback to abort a resource fetch */
-static void fetch_javascript_abort(void *ctx)
-{
- struct fetch_javascript_context *c = ctx;
-
- /* To avoid the poll loop having to deal with the fetch context
- * disappearing from under it, we simply flag the abort here.
- * The poll loop itself will perform the appropriate cleanup.
- */
- c->aborted = true;
-}
-
-
-/** callback to poll for additional resource fetch contents */
-static void fetch_javascript_poll(lwc_string *scheme)
-{
- struct fetch_javascript_context *c, *next;
-
- if (ring == NULL) return;
-
- /* Iterate over ring, processing each pending fetch */
- c = ring;
- do {
- /* Ignore fetches that have been flagged as locked.
- * This allows safe re-entrant calls to this function.
- * Re-entrancy can occur if, as a result of a callback,
- * the interested party causes fetch_poll() to be called
- * again.
- */
- if (c->locked == true) {
- next = c->r_next;
- continue;
- }
-
- /* Only process non-aborted fetches */
- if (c->aborted == false) {
- /* resource fetches can be processed in one go */
- fetch_javascript_handler(c);
- }
-
- /* Compute next fetch item at the last possible moment
- * as processing this item may have added to the ring
- */
- next = c->r_next;
-
- fetch_remove_from_queues(c->fetchh);
- fetch_free(c->fetchh);
-
- /* Advance to next ring entry, exiting if we've reached
- * the start of the ring or the ring has become empty
- */
- } while ( (c = next) != ring && ring != NULL);
-}
-
-/**
- * Register javascript scheme fetcher with fetcher factory.
- *
- * \return NSERROR_OK on success or appropriate error code on faliure.
-*/
-nserror fetch_javascript_register(void)
-{
- lwc_string *scheme = lwc_string_ref(corestring_lwc_javascript);
- const struct fetcher_operation_table fetcher_ops = {
- .initialise = fetch_javascript_initialise,
- .acceptable = fetch_javascript_can_fetch,
- .setup = fetch_javascript_setup,
- .start = fetch_javascript_start,
- .abort = fetch_javascript_abort,
- .free = fetch_javascript_free,
- .poll = fetch_javascript_poll,
- .finalise = fetch_javascript_finalise
- };
-
- return fetcher_add(scheme, &fetcher_ops);
-}
diff --git a/javascript/fetcher.h b/javascript/fetcher.h
deleted file mode 100644
index f39714089..000000000
--- a/javascript/fetcher.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf.
- *
- * 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/>.
- */
-
-/** \file
- * javascript scheme handler
- */
-
-#ifndef NETSURF_JAVASCRIPT_FETCHER_H
-#define NETSURF_JAVASCRIPT_FETCHER_H
-
-nserror fetch_javascript_register(void);
-
-#endif
diff --git a/javascript/js.h b/javascript/js.h
deleted file mode 100644
index 2929d0b5e..000000000
--- a/javascript/js.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
- *
- * 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/>.
- */
-
-/** \file
- * Interface to javascript engine functions.
- */
-
-#ifndef _NETSURF_JAVASCRIPT_JS_H_
-#define _NETSURF_JAVASCRIPT_JS_H_
-
-#include "utils/errors.h"
-
-
-typedef struct jscontext jscontext;
-typedef struct jsobject jsobject;
-
-typedef bool(jscallback)(void *ctx);
-
-struct dom_event;
-struct dom_document;
-struct dom_node;
-struct dom_element;
-struct dom_string;
-
-/** Initialise javascript interpreter */
-void js_initialise(void);
-
-/** finalise javascript interpreter */
-void js_finalise(void);
-
-/** Create a new javascript context.
- *
- * There is usually one context per browser context
- *
- * \param timeout elapsed wallclock time (in seconds) before \a callback is called
- * \param cb the callback when the runtime exceeds the timeout
- * \param cbctx The context to pass to the callback
- * \param jsctx Updated to the created JS context
- * \return NSERROR_OK on success, appropriate error otherwise.
- */
-nserror js_newcontext(int timeout, jscallback *cb, void *cbctx,
- jscontext **jsctx);
-
-/** Destroy a previously created context */
-void js_destroycontext(jscontext *ctx);
-
-/** Create a new javascript compartment
- *
- * This is called once for a page with javascript script tags on
- * it. It constructs a fresh global window object.
- */
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv);
-
-/* execute some javascript in a context */
-bool js_exec(jscontext *ctx, const char *txt, size_t txtlen);
-
-
-/* fire an event at a dom node */
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, struct dom_node *target);
-
-bool
-js_dom_event_add_listener(jscontext *ctx,
- struct dom_document *document,
- struct dom_node *node,
- struct dom_string *event_type_dom,
- void *js_funcval);
-
-/*** New Events ***/
-
-/** Handle a new element being created.
- *
- * This is called once an element is inserted into the DOM document handled
- * by the context provided. The JS implementation must then scan the element
- * for on* attributes and register appropriate listeners for those handlers.
- */
-void js_handle_new_element(jscontext *ctx, struct dom_element *node);
-
-/** Handle an event propagation finished callback.
- *
- * This is called once an event finishes propagating, no matter how it
- * finishes. The intent here is that the JS context can perform any cleanups
- * it may need to perform before the DOM finishes and the event may end up
- * freed.
- */
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt);
-
-#endif /* _NETSURF_JAVASCRIPT_JS_H_ */
diff --git a/javascript/none/Makefile b/javascript/none/Makefile
deleted file mode 100644
index ec7826da4..000000000
--- a/javascript/none/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# NetSurf javascript source file inclusion
-#
-# Included by javascript/Makefile
-#
-
-# no javascript interpreter
-
-S_JAVASCRIPT += none/none.c \ No newline at end of file
diff --git a/javascript/none/none.c b/javascript/none/none.c
deleted file mode 100644
index 9a8b0a49d..000000000
--- a/javascript/none/none.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
- *
- * 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/>.
- */
-
-/** \file
- * Dummy implementation of javascript engine functions.
- */
-
-#include "content/content.h"
-#include "utils/nsoption.h"
-
-#include "javascript/js.h"
-#include "utils/log.h"
-
-void js_initialise(void)
-{
- nsoption_set_bool(enable_javascript, false);
-}
-
-void js_finalise(void)
-{
-}
-
-nserror js_newcontext(int timeout, jscallback *cb, void *cbctx,
- jscontext **jsctx)
-{
- *jsctx = NULL;
- return NSERROR_OK;
-}
-
-void js_destroycontext(jscontext *ctx)
-{
-}
-
-jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
-{
- return NULL;
-}
-
-bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
-{
- return true;
-}
-
-bool js_fire_event(jscontext *ctx, const char *type, struct dom_document *doc, struct dom_node *target)
-{
- return true;
-}
-
-void js_handle_new_element(jscontext *ctx, struct dom_element *node)
-{
-}
-
-void js_event_cleanup(jscontext *ctx, struct dom_event *evt)
-{
-}