看到HorkeyChen写的文章《[WebKit] JavaScriptCore解析--基础篇(三)从脚本代码到JIT编译的代码实现》,写的很好,深受启发。想补充一些Horkey没有写到的细节比如字节码是如何生成的等等,为此成文。
JSC对JavaScript的处理,其实与Webkit对CSS的处理许多地方是类似的,它这么几个部分:
(1)词法分析->出来词语(Token);
(2)语法分析->出来抽象语法树(AST:Abstract Syntax Tree);
(3)遍历抽象语法树->生成字节码(Bytecode);
(4)用解释器(LLInt:Low Level Interpreter)执行字节码;
(5)如果性能不够好就用Baseline JIT编译字节码生成机器码、然后执行此机器码;
(6)如果性能还不够好,就用DFG JIT重新编译字节码生成更好的机器码、然后执行此机器码;
(7)最后,如果还不好,就祭出重器--虚拟器(LLVM:Low Level Virtual Machine)来编译DFG的中间表示代码、生成更高优化的机器码并执行。接下来,我将会用一下系列文章描述此过程。
其中,步骤1、2是类似的,3、4、5步的思想,CSS JIT也是采用类似方法,请参考[1]。想写写JSC的文章,用菜鸟和愚公移山的方式,敲开JSC的冰山一角。
本篇主要描述词法和语法解析的细节。
一、 JavaScriptCore的词法分析器工作流程分析
W3C是这么解释词法和语法工作流程的:
词法器Tokenizer的工作过程如下,就是不断从字符串中寻找一个个的词(Token),比如找到连续的“true”字符串,就创建一个TokenTrue。词法器工作过程如下:
JavaScriptCore/interpreter/interpreter.cpp:
template <typename CharType>
[cpp] view plaincopyprint?01.template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token)
02.{
03. while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
04. ++m_ptr;
05.
06. if (m_ptr >= m_end) {
07. token.type = TokEnd;
08. token.start = token.end = m_ptr;
09. return TokEnd;
10. }
11. token.type = TokError;
12. token.start = m_ptr;
13. switch (*m_ptr) {
14. case '[':
15. token.type = TokLBracket;
16. token.end = ++m_ptr;
17. return TokLBracket;
18. case ']':
19. token.type = TokRBracket;
20. token.end = ++m_ptr;
21. return TokRBracket;
22. case '(':
23. token.type = TokLParen;
24. token.end = ++m_ptr;
25. return TokLParen;
26. case ')':
27. token.type = TokRParen;
28. token.end = ++m_ptr;
29. return TokRParen;
30. case ',':
31. token.type = TokComma;
32. token.end = ++m_ptr;
33. return TokComma;
34. case ':':
35. token.type = TokColon;
36. token.end = ++m_ptr;
37. return TokColon;
38. case '"':
39. return lexString<mode, '"'>(token);
40. case 't':
41. if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') {
42. m_ptr += 4;
43. token.type = TokTrue;
44. token.end = m_ptr;
45. return TokTrue;
46. }
47. break;
48. case '-':
49. case '0':
template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token)
{
while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
++m_ptr;
if (m_ptr >= m_end) {
token.type = TokEnd;
token.start = token.end = m_ptr;
return TokEnd;
}
token.type = TokError;
token.start = m_ptr;
switch (*m_ptr) {
case '[':
token.type = TokLBracket;
token.end = ++m_ptr;
return TokLBracket;
case ']':
token.type = TokRBracket;
token.end = ++m_ptr;
return TokRBracket;
case '(':
token.type = TokLParen;
token.end = ++m_ptr;
return TokLParen;
case ')':
token.type = TokRParen;
token.end = ++m_ptr;
return TokRParen;
case ',':
token.type = TokComma;
token.end = ++m_ptr;
return TokComma;
case ':':
token.type = TokColon;
token.end = ++m_ptr;
return TokColon;
case '"':
return lexString<mode, '"'>(token);
case 't':
if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') {
m_ptr += 4;
token.type = TokTrue;
token.end = m_ptr;
return TokTrue;
}
break;
case '-':
case '0':[cpp] view plaincopyprint?01. ...
02. case '9':
03. return lexNumber(token);
04. }
05. if (m_ptr < m_end) {
06. if (*m_ptr == '.') {
07. token.type = TokDot;
08. token.end = ++m_ptr;
09. return TokDot;
10. }
11. if (*m_ptr == '=') {
12. token.type = TokAssign;
13. token.end = ++m_ptr;
14. return TokAssign;
15. }
16. if (*m_ptr == ';') {
17. token.type = TokSemi;
18. token.end = ++m_ptr;
19. return TokAssign;
20. }
21. if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')
22. return lexIdentifier(token);
23. if (*m_ptr == '\'') {
24. return lexString<mode, '\''>(token);
25. }
26. }
27. m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
28. return TokError;
29.}
...
case '9':
return lexNumber(token);
}
if (m_ptr < m_end) {
if (*m_ptr == '.') {
token.type = TokDot;
token.end = ++m_ptr;
return TokDot;
}
if (*m_ptr == '=') {
token.type = TokAssign;
token.end = ++m_ptr;
return TokAssign;
}
if (*m_ptr == ';') {
token.type = TokSemi;
token.end = ++m_ptr;
return TokAssign;
}
if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')
return lexIdentifier(token);
if (*m_ptr == '\'') {
return lexString<mode, '\''>(token);
}
}
m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
return TokError;
} 经过此过程,一个完整的JSC世界的Token就生成了。然后,再进行语法分析,生成抽象语法树.
JavaScriptCore/parser/parser.cpp:
[cpp] view plaincopyprint?01.<span style="font-family: Arial, Helvetica, sans-serif;">PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, JSObject** exception)</span>
<span style="font-family: Arial, Helvetica, sans-serif;">PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, JSObject** exception)</span>[cpp] view plaincopyprint?01.{
02. ASSERT(lexicalGlobalObject);
03. ASSERT(exception && !*exception);
04. int errLine;
05. UString errMsg;
06.
07. if (ParsedNode::scopeIsFunction)
08. m_lexer->setIsReparsing();
09.
10. m_sourceElements = 0;
11.
12. errLine = -1;
13. errMsg = UString();
14.
15. UString parseError = parseInner();
16. 。。。
17.}
{
ASSERT(lexicalGlobalObject);
ASSERT(exception && !*exception);
int errLine;
UString errMsg;
if (ParsedNode::scopeIsFunction)
m_lexer->setIsReparsing();
m_sourceElements = 0;
errLine = -1;
errMsg = UString();
UString parseError = parseInner();
。。。
}
UString Parser<LexerType>::parseInner()
[cpp] view plaincopyprint?01.{
02. UString parseError = UString();
03.
04. unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
{
UString parseError = UString();
unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;[cpp] view plaincopyprint?01.//抽象语法树Builder:
02.ASTBuilder context(const_cast<JSGlobalData*>(m_globalData), const_cast<SourceCode*>(m_source));
03.if (m_lexer->isReparsing())
04. m_statementDepth--;
05.ScopeRef scope = currentScope();
//抽象语法树Builder:
ASTBuilder context(const_cast<JSGlobalData*>(m_globalData), const_cast<SourceCode*>(m_source));
if (m_lexer->isReparsing())
m_statementDepth--;
ScopeRef scope = currentScope();[cpp] view plaincopyprint?01.//开始解析生成语法树的一个节点:
02.SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
03.if (!sourceElements || !consume(EOFTOK))
//开始解析生成语法树的一个节点:
SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
if (!sourceElements || !consume(EOFTOK))
}
举例说来,根据Token的类型,JSC认为输入的Token是一个常量声明,就会使用如下的模板函数生成语法节点(Node),然后放入ASTBuilder里面:
[cpp] view plaincopyprint?01.JavaScriptCore/bytecompiler/NodeCodeGen.cpp:
02.template <typename LexerType>
03.template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
04.{
05. failIfTrue(strictMode());
06. TreeConstDeclList constDecls = 0;
07. TreeConstDeclList tail = 0;
08. do {
09. next();
10. matchOrFail(IDENT);
11. const Identifier* name = m_token.m_data.ident;
12. next();
13. bool hasInitializer = match(EQUAL);
14. declareVariable(name);
15. context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
16. TreeExpression initializer = 0;
17. if (hasInitializer) {
18. next(TreeBuilder::DontBuildStrings); // consume '='
19. initializer = parseAssignmentExpression(context);
20. }
21. tail = context.appendConstDecl(m_lexer->lastLineNumber(), tail, name, initializer);
22. if (!constDecls)
23. constDecls = tail;
24. } while (match(COMMA));
25. return constDecls;
26.}
JavaScriptCore/bytecompiler/NodeCodeGen.cpp:
template <typename LexerType>
template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
{
failIfTrue(strictMode());
TreeConstDeclList constDecls = 0;
TreeConstDeclList tail = 0;
do {
next();
matchOrFail(IDENT);
const Identifier* name = m_token.m_data.ident;
next();
bool hasInitializer = match(EQUAL);
declareVariable(name);
context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
TreeExpression initializer = 0;
if (hasInitializer) {
next(TreeBuilder::DontBuildStrings); // consume '='
initializer = parseAssignmentExpression(context);
}
tail = context.appendConstDecl(m_lexer->lastLineNumber(), tail, name, initializer);
if (!constDecls)
constDecls = tail;
} while (match(COMMA));
return constDecls;
}
接下来,就会调用BytecodeGenerator::generate生成字节码,具体分下节分析。我们先看看下面来自JavaScript的一个个语法树节点生成字节码的过程:
JavaScriptCore/bytecompiler/NodeCodeGen.cpp:
RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
[cpp] view plaincopyprint?01.{
02. if (dst == generator.ignoredResult())
03. return 0;
04. return generator.emitLoad(dst, m_value);
05.}
{
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, m_value);
}
以下是我准备写的文章题目:
一、 JavaScriptCore的词法分析器工作流程分析;
二、 JavaScriptCore的语法分析器工作流程分析;
三、 JavaScriptCore的字节码生成流程分析;
四、 LLInt解释器工作流程分析;
五、 Baseline JIT编译器的工作流程分析;
六、 DFG JIT编译器的工作流程分析;
七、LLVM虚拟机的工作流程分析;
八、JavaScriptCore的未来展望;
文笔粗糙,不善表达,希望能越写越好。
引用:
1 https://www.webkit.org/blog/3271/webkit-css-selector-jit-compiler/
2 http://blog.csdn.net/horkychen/article/details/8928578
第一时间获得博客更新提醒,以及更多技术信息分享,欢迎关注个人微信公众平台:程序员互动联盟(coder_online),扫一扫下方二维码或搜索微信号coder_online即可关注,我们可以在线交流。
JSC对JavaScript的处理,其实与Webkit对CSS的处理许多地方是类似的,它这么几个部分:
(1)词法分析->出来词语(Token);
(2)语法分析->出来抽象语法树(AST:Abstract Syntax Tree);
(3)遍历抽象语法树->生成字节码(Bytecode);
(4)用解释器(LLInt:Low Level Interpreter)执行字节码;
(5)如果性能不够好就用Baseline JIT编译字节码生成机器码、然后执行此机器码;
(6)如果性能还不够好,就用DFG JIT重新编译字节码生成更好的机器码、然后执行此机器码;
(7)最后,如果还不好,就祭出重器--虚拟器(LLVM:Low Level Virtual Machine)来编译DFG的中间表示代码、生成更高优化的机器码并执行。接下来,我将会用一下系列文章描述此过程。
其中,步骤1、2是类似的,3、4、5步的思想,CSS JIT也是采用类似方法,请参考[1]。想写写JSC的文章,用菜鸟和愚公移山的方式,敲开JSC的冰山一角。
本篇主要描述词法和语法解析的细节。
一、 JavaScriptCore的词法分析器工作流程分析
W3C是这么解释词法和语法工作流程的:
词法器Tokenizer的工作过程如下,就是不断从字符串中寻找一个个的词(Token),比如找到连续的“true”字符串,就创建一个TokenTrue。词法器工作过程如下:
JavaScriptCore/interpreter/interpreter.cpp:
template <typename CharType>
[cpp] view plaincopyprint?01.template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token)
02.{
03. while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
04. ++m_ptr;
05.
06. if (m_ptr >= m_end) {
07. token.type = TokEnd;
08. token.start = token.end = m_ptr;
09. return TokEnd;
10. }
11. token.type = TokError;
12. token.start = m_ptr;
13. switch (*m_ptr) {
14. case '[':
15. token.type = TokLBracket;
16. token.end = ++m_ptr;
17. return TokLBracket;
18. case ']':
19. token.type = TokRBracket;
20. token.end = ++m_ptr;
21. return TokRBracket;
22. case '(':
23. token.type = TokLParen;
24. token.end = ++m_ptr;
25. return TokLParen;
26. case ')':
27. token.type = TokRParen;
28. token.end = ++m_ptr;
29. return TokRParen;
30. case ',':
31. token.type = TokComma;
32. token.end = ++m_ptr;
33. return TokComma;
34. case ':':
35. token.type = TokColon;
36. token.end = ++m_ptr;
37. return TokColon;
38. case '"':
39. return lexString<mode, '"'>(token);
40. case 't':
41. if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') {
42. m_ptr += 4;
43. token.type = TokTrue;
44. token.end = m_ptr;
45. return TokTrue;
46. }
47. break;
48. case '-':
49. case '0':
template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token)
{
while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
++m_ptr;
if (m_ptr >= m_end) {
token.type = TokEnd;
token.start = token.end = m_ptr;
return TokEnd;
}
token.type = TokError;
token.start = m_ptr;
switch (*m_ptr) {
case '[':
token.type = TokLBracket;
token.end = ++m_ptr;
return TokLBracket;
case ']':
token.type = TokRBracket;
token.end = ++m_ptr;
return TokRBracket;
case '(':
token.type = TokLParen;
token.end = ++m_ptr;
return TokLParen;
case ')':
token.type = TokRParen;
token.end = ++m_ptr;
return TokRParen;
case ',':
token.type = TokComma;
token.end = ++m_ptr;
return TokComma;
case ':':
token.type = TokColon;
token.end = ++m_ptr;
return TokColon;
case '"':
return lexString<mode, '"'>(token);
case 't':
if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') {
m_ptr += 4;
token.type = TokTrue;
token.end = m_ptr;
return TokTrue;
}
break;
case '-':
case '0':[cpp] view plaincopyprint?01. ...
02. case '9':
03. return lexNumber(token);
04. }
05. if (m_ptr < m_end) {
06. if (*m_ptr == '.') {
07. token.type = TokDot;
08. token.end = ++m_ptr;
09. return TokDot;
10. }
11. if (*m_ptr == '=') {
12. token.type = TokAssign;
13. token.end = ++m_ptr;
14. return TokAssign;
15. }
16. if (*m_ptr == ';') {
17. token.type = TokSemi;
18. token.end = ++m_ptr;
19. return TokAssign;
20. }
21. if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')
22. return lexIdentifier(token);
23. if (*m_ptr == '\'') {
24. return lexString<mode, '\''>(token);
25. }
26. }
27. m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
28. return TokError;
29.}
...
case '9':
return lexNumber(token);
}
if (m_ptr < m_end) {
if (*m_ptr == '.') {
token.type = TokDot;
token.end = ++m_ptr;
return TokDot;
}
if (*m_ptr == '=') {
token.type = TokAssign;
token.end = ++m_ptr;
return TokAssign;
}
if (*m_ptr == ';') {
token.type = TokSemi;
token.end = ++m_ptr;
return TokAssign;
}
if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')
return lexIdentifier(token);
if (*m_ptr == '\'') {
return lexString<mode, '\''>(token);
}
}
m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
return TokError;
} 经过此过程,一个完整的JSC世界的Token就生成了。然后,再进行语法分析,生成抽象语法树.
JavaScriptCore/parser/parser.cpp:
[cpp] view plaincopyprint?01.<span style="font-family: Arial, Helvetica, sans-serif;">PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, JSObject** exception)</span>
<span style="font-family: Arial, Helvetica, sans-serif;">PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, JSObject** exception)</span>[cpp] view plaincopyprint?01.{
02. ASSERT(lexicalGlobalObject);
03. ASSERT(exception && !*exception);
04. int errLine;
05. UString errMsg;
06.
07. if (ParsedNode::scopeIsFunction)
08. m_lexer->setIsReparsing();
09.
10. m_sourceElements = 0;
11.
12. errLine = -1;
13. errMsg = UString();
14.
15. UString parseError = parseInner();
16. 。。。
17.}
{
ASSERT(lexicalGlobalObject);
ASSERT(exception && !*exception);
int errLine;
UString errMsg;
if (ParsedNode::scopeIsFunction)
m_lexer->setIsReparsing();
m_sourceElements = 0;
errLine = -1;
errMsg = UString();
UString parseError = parseInner();
。。。
}
UString Parser<LexerType>::parseInner()
[cpp] view plaincopyprint?01.{
02. UString parseError = UString();
03.
04. unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
{
UString parseError = UString();
unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;[cpp] view plaincopyprint?01.//抽象语法树Builder:
02.ASTBuilder context(const_cast<JSGlobalData*>(m_globalData), const_cast<SourceCode*>(m_source));
03.if (m_lexer->isReparsing())
04. m_statementDepth--;
05.ScopeRef scope = currentScope();
//抽象语法树Builder:
ASTBuilder context(const_cast<JSGlobalData*>(m_globalData), const_cast<SourceCode*>(m_source));
if (m_lexer->isReparsing())
m_statementDepth--;
ScopeRef scope = currentScope();[cpp] view plaincopyprint?01.//开始解析生成语法树的一个节点:
02.SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
03.if (!sourceElements || !consume(EOFTOK))
//开始解析生成语法树的一个节点:
SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
if (!sourceElements || !consume(EOFTOK))
}
举例说来,根据Token的类型,JSC认为输入的Token是一个常量声明,就会使用如下的模板函数生成语法节点(Node),然后放入ASTBuilder里面:
[cpp] view plaincopyprint?01.JavaScriptCore/bytecompiler/NodeCodeGen.cpp:
02.template <typename LexerType>
03.template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
04.{
05. failIfTrue(strictMode());
06. TreeConstDeclList constDecls = 0;
07. TreeConstDeclList tail = 0;
08. do {
09. next();
10. matchOrFail(IDENT);
11. const Identifier* name = m_token.m_data.ident;
12. next();
13. bool hasInitializer = match(EQUAL);
14. declareVariable(name);
15. context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
16. TreeExpression initializer = 0;
17. if (hasInitializer) {
18. next(TreeBuilder::DontBuildStrings); // consume '='
19. initializer = parseAssignmentExpression(context);
20. }
21. tail = context.appendConstDecl(m_lexer->lastLineNumber(), tail, name, initializer);
22. if (!constDecls)
23. constDecls = tail;
24. } while (match(COMMA));
25. return constDecls;
26.}
JavaScriptCore/bytecompiler/NodeCodeGen.cpp:
template <typename LexerType>
template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
{
failIfTrue(strictMode());
TreeConstDeclList constDecls = 0;
TreeConstDeclList tail = 0;
do {
next();
matchOrFail(IDENT);
const Identifier* name = m_token.m_data.ident;
next();
bool hasInitializer = match(EQUAL);
declareVariable(name);
context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
TreeExpression initializer = 0;
if (hasInitializer) {
next(TreeBuilder::DontBuildStrings); // consume '='
initializer = parseAssignmentExpression(context);
}
tail = context.appendConstDecl(m_lexer->lastLineNumber(), tail, name, initializer);
if (!constDecls)
constDecls = tail;
} while (match(COMMA));
return constDecls;
}
接下来,就会调用BytecodeGenerator::generate生成字节码,具体分下节分析。我们先看看下面来自JavaScript的一个个语法树节点生成字节码的过程:
JavaScriptCore/bytecompiler/NodeCodeGen.cpp:
RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
[cpp] view plaincopyprint?01.{
02. if (dst == generator.ignoredResult())
03. return 0;
04. return generator.emitLoad(dst, m_value);
05.}
{
if (dst == generator.ignoredResult())
return 0;
return generator.emitLoad(dst, m_value);
}
以下是我准备写的文章题目:
一、 JavaScriptCore的词法分析器工作流程分析;
二、 JavaScriptCore的语法分析器工作流程分析;
三、 JavaScriptCore的字节码生成流程分析;
四、 LLInt解释器工作流程分析;
五、 Baseline JIT编译器的工作流程分析;
六、 DFG JIT编译器的工作流程分析;
七、LLVM虚拟机的工作流程分析;
八、JavaScriptCore的未来展望;
文笔粗糙,不善表达,希望能越写越好。
引用:
1 https://www.webkit.org/blog/3271/webkit-css-selector-jit-compiler/
2 http://blog.csdn.net/horkychen/article/details/8928578
第一时间获得博客更新提醒,以及更多技术信息分享,欢迎关注个人微信公众平台:程序员互动联盟(coder_online),扫一扫下方二维码或搜索微信号coder_online即可关注,我们可以在线交流。
相关推荐
一个JavaScriptCore-Demo-master.zip的demo用来进行交互的
针对Android的JavaScriptCore构建脚本
使用 JavaScriptCore 的 Objective-C Wrapper for Prism(JavaScript 语法高亮器)。 什么? 是一个“轻量级、健壮、优雅的语法突出显示库”,它将代码片段呈现为语法突出显示的 HTML。 它由创建,用 JavaScript ...
JavaScriptCore Framework 是 iOS7 引入的新功能,其实就是基于 Webkit 中以 C/C++ 实现的 JavaScriptCore 的一个封装,大多数 iOS 比较熟悉的是它的 Objective-C API,可以用简洁的方式实现 JS 与Native 交互,其实...
JSC is now a public library on iOS and tvOS. Ejecta has switched to the JSC library provided by the System. It still has some limitations (no native Typed Array API)
JSExport协议提供了一种声明式的方法去向JavaScript代码导出Objective-C的实例类及其实例方法,类方法和属性。两种方式:1,.Block2.JSExportBlock的方式很简单,如下:Output:JSExport的方式需要通过继承JSExport...
附件名JavaScriptCore-721.26.tar.gz。是ios4.3.3系统的webkit相关润间源代码。
本文主要讲解iOS中的JavaScriptCore框架,正是它为iOS提供了执行JavaScript代码的能力。未来的技术日新月异,JavaScript与iOS正在碰撞出新的激情。JavaScriptCore是JavaScript的虚拟机,为JavaScript的执行提供底层...
javaScriptCore的mac os系统.是webkit的3个中的一个。
iOS:JavaScriptCore.framework的使用.OC篇.包括OC调用js方法(可传参),JS调用OC方法(可传参)
利用JavaScriptCore框架,及UI web view的代理实现与H5的交互,获取当前H5页面的链接,截取H5的方法
利用JavaScriptCore实现JS与OC相互调用的,简单好理解,实现协议的话方法千万要JS和OC保持一直,否则不生效,这要注意
在 Source/JavaScriptCore/JavaScriptCore-WP8.vxcproj 下找到 .sln 文件 要在 Windows 8 上构建项目,您需要: cygwin 与 bash、perl、python、ruby、make 安装在其中,然后将 cygwin/bin 添加到 PATH。 先构建...
应用JavaScriptCore和运行时来实现oc与web的交互
在Android 上,小程序的 javascript 代码是通过 X5 内核来解析 在开发工具上, 小程序的 javascript 代码是运行在 nwjs(chrome内核) 中 一、JavaScriptCore JavaScriptCores是开源的,下载地址是...
Swift使用JavaScriptCore与网页进行交互Swift使用JavaScriptCore与网页进行交互Swift使用JavaScriptCore与网页进行交互Swift使用JavaScriptCore与网页进行交互Swift使用JavaScriptCore与网页进行交互Swift使用...
WebKit是Mac OS X v10.3及以上版本所包含的软件框架(对v10.2.7及以上版本也可通过软件更新获取)。 同时,WebKit也是Mac OS X的Safari网页浏览器的基础。WebKit是一个开源项目,主要由KDE的KHTML修改而来并且包含了...
WebKit contains the WebCore and JavaScriptCore components that Apple uses in its Safari browser. Based on KHTML and KJS from KDE's Konqueror open source project, this software has enabled Nokia to ...
node-jsc使node.js能够使用JavaScriptCore,即WebKit的javascript引擎,允许node.js在iOS设备(以及node.js和JavaScriptCore支持的其他平台)上运行