▣ 명령 프롬프트에서 빌드하기
1. js.mak 내 269 라인에서 “_FIX_JSSHELL” /D 를 추가한다.
/D "WIN32" /D "XP_WIN" /D "JSFILE" /D "_FIX_JSSHELL" /D "EXPORT_JS_API" /Fp"$(INTDIR)/js.pch" /I"$(INTDIR)" /YX\
2. jsinterp.c 내 _FIX_JSSHELL 조건으로 jsiter.c 를 추가 include 한다.
#include "jsiter.h"
#if _FIX_JSSHELL
#include "jsiter.c"
#endif
3. VS 에서 제공하는 명령 프롬프트를 실행한다.
4. nmake –f js.mak 를 통해 빌드한다.
▣ VC 6.0에서 빌드하기
1. jsautokw.h를 /src/ 아래 위치시킨다.
2. js.mdp 파일을 덮어 씌우고 VC6.0을 통해 open한다.
3. js 프로젝트 내 _FIX_JSSHELL 을 pre define 시킨다.
4. jsutil.h 내 JS_STATIC_ASSERT 정의를 무효화한다.
#define JS_STATIC_ASSERT(condition) \
// JS_STATIC_ASSERT_IMPL(condition, __LINE__)
5. jsexn.c 내 JS_STATIC_ASSERT 사용을 막는다.
// JS_STATIC_ASSERT(sizeof(JSErrorReport) % sizeof(const char *) == 0);
// JS_STATIC_ASSERT(sizeof(const char *) % sizeof(jschar) == 0);
6. 빌드한다.
spicemonkey_v1.7_vc60_build.zip
▣ JS 1.7이 지원하는 java script 버전은?
1. JS 1.7.0 is based on the same branch (1.8.1.8) as Firefox 2.0.0.8 and includes the same stability and security fixes
-> Firefox 2.0.0.8 버전과 같다고 합니다.
2. JavaScript 1.7에 대한 내용을 살펴 보면
|
Version |
Release date |
Equivalent to |
Netscape |
Mozilla |
Internet |
Opera |
Safari |
|
1.7 |
October 2006 |
1.6 + Pythonic generators + Iterators + let |
|
2.0 |
|
|
|
-> Firefox 2.0에서 javascript 1.7을 지원한다고 합니다.
3. JavaScript 1.7 기능들에 대해서 JS1.7 버전에서 정상 동작하는 것을 확인하였습니다.
<https://developer.mozilla.org/en/New_in_JavaScript_1.7>
따라서, 명시적이지는 않지만 지원한다고 말할 수 있겠습니다.
▣ Shell에서부터의 개략적인 흐름
Javascript 문장이 입력으로 주어졌을 때 Spider monkey 내에서는 Compile 단계를 거쳐 byte code를 만듭니다.
해당 bytecode는 Interpret 단계를 거쳐 실행을 하게 됩니다.
Example of byte code
– “1”을 입력한 경우 길이 3인 byte code가 compile됩니다. 3F 02 C3
3F(opcode) “one”
02(opcode) “push”
C3(opcode) “stop”
opcode에 대한 정의는 jsopcode.tbl 파일을 나열되어 있습니다.
/* legend: op val name image len use def prec format */
/* Longstanding JavaScript bytecodes. */
OPDEF(JSOP_NOP, 0, "nop", NULL, 1, 0, 0, 0, JOF_BYTE)
OPDEF(JSOP_PUSH, 1, "push", NULL, 1, 0, 1, 0, JOF_BYTE)
……
▣ TIP
shell에서 dis(FUNC) 명령을 사용하면 함수의 byte code를 disassemble할 수 있다.
tracing(true) 명령을 사용하면 interpret 시의 동작을 확인할 수 있다.
▣ Interpreter part
금일 Interpreter 관련 코드를 살펴 보았습니다.
Interpret 기능은 jsinterp.c 파일 내 js_Interpret 함수가 핵심 역할을 수행하고 있습니다.
함수의 양은 엄청 크며 while 문 안에서 switch 문이 opcode(명령어)를 하나씩 실행하는 구조로 되어 있습니다.
while{
switch() {
case:
break;
}
}
js_Interpret 함수의 parameter
1. JSContext* cx [IN] bytecode가 실행되어야 할 context를 가리킵니다.
2. jsbytecode* pc (uint8) [IN] bytecode
3. jsval* result [OUT] 결과 값
js_Interpret 함수 내 몇몇 주요 변수
JSRuntime* rt context가 가진 런타임
JSStackFrame* fp context가 가진 스택 프레임
JSScript* script 스택 프레임이 가진 script
jsval* sp 스택 포인터, fp->spbase와 동일시 됩니다.
……
Function 처리에 대한 고찰
Function은 (예상) compile 단계에서 다른 곳에 기억해 두고 있습니다.
byte code에서 function call을 하게 되면 JSInlineFrame를 사용하여 해당 위치로 옮겨 가서 동작을 수행하게 됩니다.
▣ Developer로서 spice monkey의 활용 매커니즘.
java script를 실행해야 하는 시점에 js engine에게 기본 환경을 제공해 주고 실제 script를 실행하도록 요청한다.
DOM에 대한 제어 처리는 콜백 함수를 등록하여 처리한다.
이벤트 함수는 해당 시점에 js engine을 통해 실행시킨다.
페이지가 완전히 사라질 때까지 context는 그대로 유지시킨다.
ex. 브라우저와의 연동
▣ Compiler
script 구문을 입력으로 해서 token을 얻어 AST를 만들고 이를 byte code로 변환하는 과정을 말합니다.
JS_CompileScript 내에서는 js_InflateString을 UNICODE로 바꾸고 실제 작업은 JS_CompileUCScript(->JS_CompileUCScriptForPrincipals)을 통해 한다.
JS_CompileUCScriptForPrincipals에서는 입력 스트링을 토큰들로 바꾸고(js_NewTokenStream) 이에 대해 CompileTokenStream를 실행한다.
CompileTokenStream(jsapi.c) 내 중요한 함수는 js_CompileTokenStream(jsparse.c) 내 Statements인 듯 함.
다음으로 js_NewScriptFromCG(jsscript.c)에서 script를 만듬.
Statements 후반에 js_EmitTree(jsemit.c)를 호출한다.
JSParseNode* 를 따라 cg->current->base(궁극적으로 srcript->code)를 만들어 나간다.
JSParseNode::pn_type - 구분자(토큰)
JSParseNode::pn_arity - operand의 개수
cg 내 byte code 값은 JSScript::code가 bytecode로 넘어 감.(jsopcode.tbl 참고함)
NewOrRecycledNode 함수는 JSParseNode를 생성해 준다.
- JSTreeContext::nodelist : 생성할 node(JSParseNode)를 리스트로 가진다.
- nodelist가 비어 있으면 JSContext::tempPool(JSArenaPool)로부터 얻는다.
Statements 함수는 하나의 구간({..})을 가리킨다.
js_PushStatement
js_PopStatement
JSParseNode::pn_type : 토큰 값
JSParseNode::pn_op : op code 값
JSParseNode::pn_arity : set의 성격을 나타낸다.
JSParseNode::pn_u : 실제 내용
* Label Variant Members
* ----- ------- -------
* <Definitions>
* TOK_FUNCTION func pn_funAtom: atom holding function object containing
* arg and var properties. We create the function
* object at parse (not emit) time to specialize arg
* and var bytecodes early.인자와 변수를 가진 함수를 가지는 기본 요소.
* 인자와 변수를 가진 함수를 가지는 기본 요소.
* pn_body: TOK_LC node for function body statements -
* pn_flags: TCF_FUN_* flags (see jsemit.h) collected -
* while parsing the function's body
* pn_tryCount: of try statements in function - 해당 함수 내 try 구문 개수
*
* <Statements>
* TOK_LC list pn_head: list of pn_count statements - pn_count개 statement들의 리스트
* TOK_EXPORT list pn_head: list of pn_count TOK_NAMEs or one TOK_STAR - pn_count 개 TOK_NAME들 또는 *의 리스트
* (which is not a multiply node)
* TOK_IMPORT list pn_head: list of pn_count sub-trees of the form - pn_count개 subtree의 리스트
* a.b.*, a[b].*, a.*, a.b, or a[b] -- but never a.
* Each member is expressed with TOK_DOT or TOK_LB.
* Each sub-tree's root node has a pn_op in the set
* JSOP_IMPORT{ALL,PROP,ELEM}
* TOK_IF ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else or null - 조건, true일 경우, false일 경우로 나뉜다.
* TOK_SWITCH binary pn_left: discriminant - 판별식
* pn_right: list of TOK_CASE nodes, with at most one - CASE node 리스트
* TOK_DEFAULT node, or if there are let bindings
* in the top level of the switch body's cases, a
* TOK_LEXICALSCOPE node that contains the list of
* TOK_CASE nodes.
* TOK_CASE, binary pn_left: case expr or null if TOK_DEFAULT
* TOK_DEFAULT pn_right: TOK_LC node for this case's statements
* pn_val: constant value if lookup or table switch
* TOK_WHILE binary pn_left: cond, pn_right: body - 조건, body
* TOK_DO binary pn_left: body, pn_right: cond - body, 조건
* TOK_FOR binary pn_left: either - binary??
* for/in loop: a binary TOK_IN node with
* pn_left: TOK_VAR or TOK_NAME to left of 'in'
* if TOK_VAR, its pn_extra may have PNX_POPVAR
* and PNX_FORINVAR bits set
* pn_right: object expr to right of 'in'
* for(;;) loop: a ternary TOK_RESERVED node with
* pn_kid1: init expr before first ';'
* pn_kid2: cond expr before second ';'
* pn_kid3: update expr after second ';'
* any kid may be null
* pn_right: body
* TOK_THROW unary pn_op: JSOP_THROW, pn_kid: exception
* TOK_TRY ternary pn_kid1: try block
* pn_kid2: null or TOK_RESERVED list of
* TOK_LEXICALSCOPE nodes, each with pn_expr pointing
* to a TOK_CATCH node
* pn_kid3: null or finally block
* TOK_CATCH ternary pn_kid1: TOK_NAME, TOK_RB, or TOK_RC catch var node
* (TOK_RB or TOK_RC if destructuring)
* pn_kid2: null or the catch guard expression
* pn_kid3: catch block statements
* TOK_BREAK name pn_atom: label or null
* TOK_CONTINUE name pn_atom: label or null
* TOK_WITH binary pn_left: head expr, pn_right: body
* TOK_VAR list pn_head: list of pn_count TOK_NAME nodes
* each name node has
* pn_atom: variable name
* pn_expr: initializer or null
* TOK_RETURN unary pn_kid: return expr or null
* TOK_SEMI unary pn_kid: expr or null statement
* TOK_COLON name pn_atom: label, pn_expr: labeled statement
*
* <Expressions>
* All left-associated binary trees of the same type are optimized into lists
* to avoid recursion when processing expression chains.
* TOK_COMMA list pn_head: list of pn_count comma-separated exprs
* TOK_ASSIGN binary pn_left: lvalue, pn_right: rvalue
* pn_op: JSOP_ADD for +=, etc.
* TOK_HOOK ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else
* TOK_OR binary pn_left: first in || chain, pn_right: rest of chain
* TOK_AND binary pn_left: first in && chain, pn_right: rest of chain
* TOK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr
* TOK_BITXOR binary pn_left: left-assoc ^ expr, pn_right: & expr
* TOK_BITAND binary pn_left: left-assoc & expr, pn_right: EQ expr
* TOK_EQOP binary pn_left: left-assoc EQ expr, pn_right: REL expr
* pn_op: JSOP_EQ, JSOP_NE, JSOP_NEW_EQ, JSOP_NEW_NE
* TOK_RELOP binary pn_left: left-assoc REL expr, pn_right: SH expr
* pn_op: JSOP_LT, JSOP_LE, JSOP_GT, JSOP_GE
* TOK_SHOP binary pn_left: left-assoc SH expr, pn_right: ADD expr
* pn_op: JSOP_LSH, JSOP_RSH, JSOP_URSH
* TOK_PLUS, binary pn_left: left-assoc ADD expr, pn_right: MUL expr
* pn_extra: if a left-associated binary TOK_PLUS
* tree has been flattened into a list (see above
* under <Expressions>), pn_extra will contain
* PNX_STRCAT if at least one list element is a
* string literal (TOK_STRING); if such a list has
* any non-string, non-number term, pn_extra will
* contain PNX_CANTFOLD.
* pn_
* TOK_MINUS pn_op: JSOP_ADD, JSOP_SUB
* TOK_STAR, binary pn_left: left-assoc MUL expr, pn_right: UNARY expr
* TOK_DIVOP pn_op: JSOP_MUL, JSOP_DIV, JSOP_MOD
* TOK_UNARYOP unary pn_kid: UNARY expr, pn_op: JSOP_NEG, JSOP_POS,
* JSOP_NOT, JSOP_BITNOT, JSOP_TYPEOF, JSOP_VOID
* TOK_INC, unary pn_kid: MEMBER expr
* TOK_DEC
* TOK_NEW list pn_head: list of ctor, arg1, arg2, ... argN
* pn_count: 1 + N (where N is number of args)
* ctor is a MEMBER expr
* TOK_DELETE unary pn_kid: MEMBER expr
* TOK_DOT, name pn_expr: MEMBER expr to left of .
* TOK_DBLDOT pn_atom: name to right of .
* TOK_LB binary pn_left: MEMBER expr to left of [
* pn_right: expr between [ and ]
* TOK_LP list pn_head: list of call, arg1, arg2, ... argN
* pn_count: 1 + N (where N is number of args)
* call is a MEMBER expr naming a callable object
* TOK_RB list pn_head: list of pn_count array element exprs
* [,,] holes are represented by TOK_COMMA nodes
* #n=[...] produces TOK_DEFSHARP at head of list
* pn_extra: PN_ENDCOMMA if extra comma at end
* TOK_RC list pn_head: list of pn_count TOK_COLON nodes where
* each has pn_left: property id, pn_right: value
* #n={...} produces TOK_DEFSHARP at head of list
* TOK_DEFSHARP unary pn_num: jsint value of n in #n=
* pn_kid: null for #n=[...] and #n={...}, primary
* if #n=primary for function, paren, name, object
* literal expressions
* TOK_USESHARP nullary pn_num: jsint value of n in #n#
* TOK_RP unary pn_kid: parenthesized expression
* TOK_NAME, name pn_atom: name, string, or object atom
* TOK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or
* JSOP_REGEXP
* TOK_OBJECT If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR
* with pn_slot >= 0 and pn_attrs telling const-ness
* TOK_NUMBER dval pn_dval: double value of numeric literal
* TOK_PRIMARY nullary pn_op: JSOp bytecode
*
* <E4X node descriptions>
* TOK_ANYNAME nullary pn_op: JSOP_ANYNAME
* pn_atom: cx->runtime->atomState.starAtom
* TOK_AT unary pn_op: JSOP_TOATTRNAME; pn_kid attribute id/expr
* TOK_DBLCOLON binary pn_op: JSOP_QNAME
* pn_left: TOK_ANYNAME or TOK_NAME node
* pn_right: TOK_STRING "*" node, or expr within []
* name pn_op: JSOP_QNAMECONST
* pn_expr: TOK_ANYNAME or TOK_NAME left operand
* pn_atom: name on right of ::
* TOK_XMLELEM list XML element node
* pn_head: start tag, content1, ... contentN, end tag
* pn_count: 2 + N where N is number of content nodes
* N may be > x.length() if {expr} embedded
* TOK_XMLLIST list XML list node
* pn_head: content1, ... contentN
* TOK_XMLSTAGO, list XML start, end, and point tag contents
* TOK_XMLETAGC, pn_head: tag name or {expr}, ... XML attrs ...
* TOK_XMLPTAGO
* TOK_XMLNAME nullary pn_atom: XML name, with no {expr} embedded
* TOK_XMLNAME list pn_head: tag name or {expr}, ... name or {expr}
* TOK_XMLATTR, nullary pn_atom: attribute value string; pn_op: JSOP_STRING
* TOK_XMLCDATA,
* TOK_XMLCOMMENT
* TOK_XMLPI nullary pn_atom: XML processing instruction target
* pn_atom2: XML PI content, or null if no content
* TOK_XMLTEXT nullary pn_atom: marked-up text, or null if empty string
* TOK_LC unary {expr} in XML tag or content; pn_kid is expr
*
* So an XML tag with no {expr} and three attributes is a list with the form:
*
* (tagname attrname1 attrvalue1 attrname2 attrvalue2 attrname2 attrvalue3)
*
* An XML tag with embedded expressions like so:
*
* <name1{expr1} name2{expr2}name3={expr3}>
*
* would have the form:
*
* ((name1 {expr1}) (name2 {expr2} name3) {expr3})
*
* where () bracket a list with elements separated by spaces, and {expr} is a
* TOK_LC unary node with expr as its kid.
*
* Thus, the attribute name/value pairs occupy successive odd and even list
* locations, where pn_head is the TOK_XMLNAME node at list location 0. The
* parser builds the same sort of structures for elements:
*
* <a x={x}>Hi there!<b y={y}>How are you?</b><answer>{x + y}</answer></a>
*
* translates to:
*
* ((a x {x}) 'Hi there!' ((b y {y}) 'How are you?') ((answer) {x + y}))
*
* <Non-E4X node descriptions, continued>
*
* Label Variant Members
* ----- ------- -------
* TOK_LEXICALSCOPE name pn_op: JSOP_LEAVEBLOCK or JSOP_LEAVEBLOCKEXPR
* pn_atom: block object
* pn_expr: block body
* TOK_ARRAYCOMP list pn_head: list of pn_count (1 or 2) elements
* if pn_count is 2, first element is #n=[...]
* last element is block enclosing for loop(s)
* and optionally if-guarded TOK_ARRAYPUSH
* pn_extra: stack slot, used during code gen
* TOK_ARRAYPUSH unary pn_op: JSOP_ARRAYCOMP
* pn_kid: array comprehension expression