Home Web Front-end JS Tutorial How to perform function serialization in javascript SpiderMonkey_Basic knowledge

How to perform function serialization in javascript SpiderMonkey_Basic knowledge

May 16, 2016 pm 05:47 PM

In Javascript, functions can be easily serialized (stringified), that is, the source code of the function can be obtained. But in fact, the internal implementation (engine implementation) of this operation is not as simple as you think. A total of two are used in SpiderMonkey There are three function serialization technologies: one is to use a decompiler to decompile the compiled bytecode of the function into a source code string, and the other is to compress the function source code before compiling the function into bytecode. And store it, then decompress and restore it when used.

How to serialize functions
In SpiderMonkey, there are three methods or functions that can serialize functions: Function. prototype.toString, Function.prototype.toSource, uneval. Only the toString method is standard, that is, it is common to all engines. However, there are only a few words about the Function.prototype.toString method in the ES standard (ES5 15.3.4.2). In other words, there is basically no standard, and the engine decides how to implement it.

The role of function serialization
The main role of function serialization should be to use the functions generated by serialization source code to redefine this function.

Copy the code The code is as follows:

function a() {
...
alert("a")
...
}

a() //"a" may pop up during execution

a = eval("(" a.toString().replace('alert("a")', 'alert("b")') ")")

a() //When executing "b" may pop up

You may be thinking: "I have been writing Javascript for so many years, why haven't I encountered this kind of demand?" Indeed, if it is your own website, you have complete control over the js File, there is no need to modify the function in this patching method, just modify it directly. But if the source file is not under your control, it is very likely to be done like this. For example, the greasemonkey script is commonly used: You may need to disable or modify a function in a website. There are also Firefox extensions: you need to modify a certain function of Firefox itself (it can be said that Firefox is written in JS). Here is an example I wrote myself Example of Firefox script:
Copy code The code is as follows:
location == "chrome:/ /browser/content/browser.xul" && eval("gURLBar.handleCommand=" gURLBar.handleCommand.toString().replace(/^s*(load. );/gm, "/^javascript:/.test(url )||(content.location=='about:blank'||content.location=='about:newtab')?$1:gBrowser.loadOneTab(url,{postData:postData,inBackground:false, allowThirdPartyFixup: true}) ;"))

The function of this code is: when pressing Enter on the address bar, let Firefox open the page in a new tab instead of occupying the current tab. The way to achieve this is to use the toString method to read gURLBar. The source code of the handleCommand function is then replaced with regular expressions and passed to eval to redefine the function.

Why not define it directly, that is, rewrite the function directly:

gURLBar.handleCommand = function(){...//Change the original function in a small place}
The reason why we cannot do this is because we have to consider compatibility. We should change the source code of this function as little as possible. If so As written, once the source code of Firefox's gURLBar.handleCommand changes, this script will become invalid. For example, both Firefox3 and Firefox4 have this function, but the content of the function is very different. However, if you use regular expressions to replace some keywords, as long as this is replaced If this keyword does not change, there will be no incompatibility.

Decompile bytecode
In SpiderMonkey, the function will be compiled after being parsed into bytecode (bytecode), that is to say, the original function source code is stored in the memory. There is a decompiler in SpiderMonkey, and its main function is to decompile the bytecode of the function into the form of function source code.

In Firefox16 and previous versions, SpiderMonkey uses this method. If you are using these versions of Firefox, you can try the following code:
Copy code The code is as follows:

alert(function () {
"String";
//Comment
return 1 2 3
}.toString())
The returned string is

function () {
return 6;
}

The output is completely different from other browsers:

1. Meaningless primitive value literals will be deleted during compilation, in this example it is the " character String".

You may think: "It doesn't seem to be a problem, anyway, these values ​​​​have no meaning for the operation of the function." Wait, did you forget something? It means strict What to do with the pattern string "use strict"?

In versions that do not support strict mode, such as Firefox 3.6, this "use strict" is no different from other strings and will be deleted during compilation. .After SpiderMonkey implements strict mode, although the string "use strict" will also be ignored during compilation, it will be judged during decompilation. If this function is in strict mode, it will be in the function body at the beginning. Add "use strict" in one line, and the following is the corresponding engine source code.

static JSBool
Copy code The code is as follows:

DecompileBody(JSPrinter *jp, JSScript *script, jsbytecode *pc)
{
/* Print a strict mode code directive, if needed. */
if (script->strictModeCode && !jp->strict) {
if (jp->fun && (jp->fun->flags & JSFUN_EXPR_CLOSURE)) {
/*
* We have no syntax for strict function expressions;
* at least give a hint.
*/
js_printf(jp, "t/* use strict */ n");
} else {
js_printf(jp, "t"use strict";n");
}
jp->strict = true;
}

jsbytecode *end = script-> ;code script->length;
return DecompileCode(jp, script, pc, end - pc, 0);
}

2. Comments during compilation It will also be deleted

This doesn’t seem to have much impact, but some people are willing to use function comments to implement multi-line strings. This method is not available in versions before Firefox 17.
Copy code The code is as follows:

function hereDoc(f) { 
return f.toString( ).replace(/^. s/,"").replace(/. $/,"");
}
var string = hereDoc(function () {/*
i
You
He
*/});
console.log(string)

I
You
He
3. Original value Literal operations will be performed at compile time.

This is an optimization method. "High Performance JavaScript" mentioned:

Decompiled Disadvantages
Due to the emergence of new technologies (such as strict mode) and when modifying other related bugs, the implementation of this part of the decompiler often needs to be changed. Changes may produce new bugs. I have personally experienced this I encountered a bug. It was probably around Firefox 10. I can’t remember the specific problem clearly. Anyway, it was about whether the parentheses should be retained during decompilation. It probably looked like this:
Copy code The code is as follows:

>(function (a,b,c){return (a b) c}).toString ()
"function (a, b, c) {
return a b c;
}"

When decompiling, the parentheses in (a b) are omitted , since the additive associativity goes from left to right, it doesn’t matter. But the bug I encountered is this:
Copy code The code is as follows:

>(function (a,b,c){return a (b c)}).toString()
"function (a, b, c) {
return a b c;
}"

This doesn’t work. a b c is not equal to a (b c). For example, in the case of a=1, b=2, c="3", a b c is equal to "33", and a (b c) is equal to "123 ".

Regarding decompilers, Mozilla engineer Luke Wagner pointed out that decompilers have greatly hindered them from implementing some new features, and often have some bugs:

Not to pile on , but I too have felt an immense drag from the decompiler in the last year. Testing coverage is also poor and any non-trivial change inevitably produces fuzz bugs. The sooner we remove this drag the sooner we start reaping the benefits. In particular, I think now is a much better time to remove it than after doing significant frontend/bytecode hacking for new language features.

Brendan Eich also said that the decompiler does have many shortcomings:

I have no love for the decompiler, it has been hacked over for 17 years. Storage function source code
After Firefox17, SpiderMonkey changed to the second implementation method. Other browsers should also implement it this way. Function sequence The resulting string is completely consistent with the source code, including whitespace characters, comments, etc. In this case, most of the problems should disappear. However, it seems that I have another question. It is about strict mode.

For example:
Copy code The code is as follows:

(function A() {
"use strict";
alert("A");
}) ""

Of course, the returned source code should also have "use strict", which is true for all browsers This is achieved:
Copy code The code is as follows:

function A() {
"use strict";
alert("A");
}

But what if this is the case:
Copy Code The code is as follows:

(function A() {
"use strict";
return function B() {
alert( "B")
}
})() ""

Internal function B is also in strict mode. Should "use strict" be added to the function source code that outputs B? .Try it out:

As mentioned above, versions before Firefox17 and after Firefox4 decide whether to output "use strict" by judging whether the current function is in strict mode. Function B inherits the strict mode of function A. So there will be "use strict".

At the same time, the function source code is strictly indented, because during decompilation, SpiderMonkey will format the decompiled source code, even if the previous source code has no indentation at all It doesn't matter:
Copy code The code is as follows:

function B() {
" use strict";
alert("B");
}

Will versions after Firefox17 have "use strict"? Because the function source code is saved directly Yes, and there is indeed no "use strict" in function B. The test result is: "use strict" will be added, but there is a problem with the indentation, because there is no formatting step.
Copy code The code is as follows:

function B() {
"use strict";

alert(" B")
}

SpiderMonkey's latest version of jsfun.cpp source code has corresponding comments

// If an upper-level function of a function has "use strict ", then this function inherits the strict mode of the upper function.
// We will also insert "use strict" in the function body of this internal function.
// This ensures that if the toString of this function When the return value of the method is re-evaluated,
// the regenerated function will have the same semantics as the original function.


The difference is that other browsers do not have " use strict":
Copy code The code is as follows:

function B() {
alert("B")
}

Although this will not have much impact, I think Firefox's implementation is more reasonable.
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What should I do if I encounter garbled code printing for front-end thermal paper receipts? What should I do if I encounter garbled code printing for front-end thermal paper receipts? Apr 04, 2025 pm 02:42 PM

Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

Who gets paid more Python or JavaScript? Who gets paid more Python or JavaScript? Apr 04, 2025 am 12:09 AM

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

How to merge array elements with the same ID into one object using JavaScript? How to merge array elements with the same ID into one object using JavaScript? Apr 04, 2025 pm 05:09 PM

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

Demystifying JavaScript: What It Does and Why It Matters Demystifying JavaScript: What It Does and Why It Matters Apr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

The difference in console.log output result: Why are the two calls different? The difference in console.log output result: Why are the two calls different? Apr 04, 2025 pm 05:12 PM

In-depth discussion of the root causes of the difference in console.log output. This article will analyze the differences in the output results of console.log function in a piece of code and explain the reasons behind it. �...

How to achieve parallax scrolling and element animation effects, like Shiseido's official website?
or:
How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? How to achieve parallax scrolling and element animation effects, like Shiseido's official website? or: How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? Apr 04, 2025 pm 05:36 PM

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

Can PowerPoint run JavaScript? Can PowerPoint run JavaScript? Apr 01, 2025 pm 05:17 PM

JavaScript can be run in PowerPoint, and can be implemented by calling external JavaScript files or embedding HTML files through VBA. 1. To use VBA to call JavaScript files, you need to enable macros and have VBA programming knowledge. 2. Embed HTML files containing JavaScript, which are simple and easy to use but are subject to security restrictions. Advantages include extended functions and flexibility, while disadvantages involve security, compatibility and complexity. In practice, attention should be paid to security, compatibility, performance and user experience.

Is JavaScript hard to learn? Is JavaScript hard to learn? Apr 03, 2025 am 12:20 AM

Learning JavaScript is not difficult, but it is challenging. 1) Understand basic concepts such as variables, data types, functions, etc. 2) Master asynchronous programming and implement it through event loops. 3) Use DOM operations and Promise to handle asynchronous requests. 4) Avoid common mistakes and use debugging techniques. 5) Optimize performance and follow best practices.

See all articles