Bug 40300 - Web Inspector: [JSC] implement script source editing
Summary: Web Inspector: [JSC] implement script source editing
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2010-06-08 07:41 PDT by Yury Semikhatsky
Modified: 2017-01-18 23:38 PST (History)
25 users (show)

See Also:


Attachments
Patch (14.35 KB, patch)
2012-06-20 01:48 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (22.92 KB, patch)
2012-06-21 05:02 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (22.84 KB, patch)
2012-06-21 06:12 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (22.22 KB, patch)
2012-06-24 20:00 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (22.21 KB, patch)
2012-06-24 22:31 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (23.58 KB, patch)
2012-06-25 00:35 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (23.47 KB, patch)
2012-06-25 01:58 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (24.06 KB, patch)
2012-07-05 00:06 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (23.89 KB, patch)
2012-07-05 00:54 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (24.01 KB, patch)
2012-07-05 20:16 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (24.25 KB, patch)
2012-07-11 19:59 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (24.23 KB, patch)
2012-07-12 19:44 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
test case (579 bytes, text/html)
2012-07-23 16:53 PDT, Geoffrey Garen
no flags Details
Patch (26.46 KB, patch)
2012-07-30 21:35 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (26.75 KB, patch)
2012-07-30 23:12 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (26.75 KB, patch)
2012-07-31 00:06 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (26.75 KB, patch)
2012-07-31 01:09 PDT, Peter Wang
no flags Details | Formatted Diff | Diff
Patch (26.75 KB, patch)
2012-07-31 02:23 PDT, Peter Wang
oliver: review-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Yury Semikhatsky 2010-06-08 07:41:42 PDT
Should be possible to edit script sources on the fly.
Comment 1 kangax 2011-11-05 14:42:18 PDT
This is now implemented, isn't it?
Comment 2 Timothy Hatcher 2012-05-30 13:24:15 PDT
Not for JSC.
Comment 3 Peter Wang 2012-06-20 01:48:48 PDT
Created attachment 148524 [details]
Patch
Comment 4 WebKit Review Bot 2012-06-20 01:50:52 PDT
Attachment 148524 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/JavaScriptCore/ChangeLog', u'Source..." exit_code: 1
Source/WebCore/ChangeLog:8:  You should remove the 'No new tests' and either add and list tests, or explain why no new tests were possible.  [changelog/nonewtests] [5]
Total errors found: 1 in 13 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 5 Gustavo Noronha (kov) 2012-06-20 01:58:03 PDT
Comment on attachment 148524 [details]
Patch

Attachment 148524 [details] did not pass gtk-ews (gtk):
Output: http://queues.webkit.org/results/12995175
Comment 6 Early Warning System Bot 2012-06-20 01:58:38 PDT
Comment on attachment 148524 [details]
Patch

Attachment 148524 [details] did not pass qt-wk2-ews (qt):
Output: http://queues.webkit.org/results/13003142
Comment 7 Early Warning System Bot 2012-06-20 01:59:15 PDT
Comment on attachment 148524 [details]
Patch

Attachment 148524 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/12995174
Comment 8 Build Bot 2012-06-20 02:04:11 PDT
Comment on attachment 148524 [details]
Patch

Attachment 148524 [details] did not pass mac-ews (mac):
Output: http://queues.webkit.org/results/13009130
Comment 9 Build Bot 2012-06-20 02:13:11 PDT
Comment on attachment 148524 [details]
Patch

Attachment 148524 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/12997162
Comment 10 Yury Semikhatsky 2012-06-20 02:21:51 PDT
Comment on attachment 148524 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=148524&action=review

> Source/WebCore/bindings/js/PageScriptDebugServer.cpp:91
> +    const ScriptValue& value = frame->script()->executeScript(newContent);

This will just re-evaluate the script as if you were running it in the inspector console while setScriptSource command should allow you to modify a function that may have already been run and leave other stuff untouched if its source doesn't change. E.g. changing 

"var count = 1;
function foo()
{
    count++;
}"

to

"var count = 1;
function foo()
{
    count--;
}"

shouldn't reset value of the count variable to 1.
Comment 11 Peter Wang 2012-06-20 02:25:46 PDT
(In reply to comment #10)
> (From update of attachment 148524 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=148524&action=review
> 
> > Source/WebCore/bindings/js/PageScriptDebugServer.cpp:91
> > +    const ScriptValue& value = frame->script()->executeScript(newContent);
> 
> This will just re-evaluate the script as if you were running it in the inspector console while setScriptSource command should allow you to modify a function that may have already been run and leave other stuff untouched if its source doesn't change. E.g. changing 
> 
> "var count = 1;
> function foo()
> {
>     count++;
> }"
> 
> to
> 
> "var count = 1;
> function foo()
> {
>     count--;
> }"
> 
> shouldn't reset value of the count variable to 1.
I see... Thx.
Comment 12 Peter Wang 2012-06-21 05:02:19 PDT
Created attachment 148768 [details]
Patch
Comment 13 Build Bot 2012-06-21 05:21:35 PDT
Comment on attachment 148768 [details]
Patch

Attachment 148768 [details] did not pass mac-ews (mac):
Output: http://queues.webkit.org/results/13026083
Comment 14 Build Bot 2012-06-21 05:28:58 PDT
Comment on attachment 148768 [details]
Patch

Attachment 148768 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13025089
Comment 15 Peter Wang 2012-06-21 06:12:26 PDT
Created attachment 148778 [details]
Patch
Comment 16 Build Bot 2012-06-21 06:33:07 PDT
Comment on attachment 148778 [details]
Patch

Attachment 148778 [details] did not pass mac-ews (mac):
Output: http://queues.webkit.org/results/13038077
Comment 17 Build Bot 2012-06-21 06:33:45 PDT
Comment on attachment 148778 [details]
Patch

Attachment 148778 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13033086
Comment 18 Early Warning System Bot 2012-06-21 06:53:55 PDT
Comment on attachment 148778 [details]
Patch

Attachment 148778 [details] did not pass qt-wk2-ews (qt):
Output: http://queues.webkit.org/results/13028122
Comment 19 Early Warning System Bot 2012-06-21 07:02:12 PDT
Comment on attachment 148778 [details]
Patch

Attachment 148778 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/13035089
Comment 20 Gyuyoung Kim 2012-06-21 07:20:55 PDT
Comment on attachment 148778 [details]
Patch

Attachment 148778 [details] did not pass efl-ews (efl):
Output: http://queues.webkit.org/results/13027109
Comment 21 WebKit Review Bot 2012-06-21 07:21:24 PDT
Comment on attachment 148778 [details]
Patch

Attachment 148778 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/13025119
Comment 22 Vsevolod Vlasov 2012-06-21 08:29:52 PDT
Comment on attachment 148778 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=148778&action=review

> Source/WebCore/bindings/js/PageScriptDebugServer.cpp:85
> +{

You should change the script with given sourceID live, you are evaluating newContent here, basically creating a new script instead of changing the old one.
Comment 23 Peter Wang 2012-06-24 19:28:33 PDT
(In reply to comment #22)
> (From update of attachment 148778 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=148778&action=review
> 
> > Source/WebCore/bindings/js/PageScriptDebugServer.cpp:85
> > +{
> 
> You should change the script with given sourceID live, you are evaluating newContent here, basically creating a new script instead of changing the old one.

I agree that your description is the ideal solution. But it seems impossible for JSC, since neither JSC nor Frame will cache the JS code they executed. JSC just read the string of JS code, "compile" it into Identifiers and executable code blocks, save these things in Global Data structure, and execute. 

My solution is taking an advantage of JSC: when JSC is "compiling" JS code, if there is an Identifier with an existent name in Global Data, JSC will replace the old with the new.

So I did a little modification of "Interpreter::execute": if we just need to recompile, we send a flag to it to let it just replace the old Identifiers and executable code blocks but don't really execute them. By that way we implement the effect of "editing live js code".
Comment 24 Peter Wang 2012-06-24 20:00:21 PDT
Created attachment 149225 [details]
Patch
Comment 25 Early Warning System Bot 2012-06-24 20:10:55 PDT
Comment on attachment 149225 [details]
Patch

Attachment 149225 [details] did not pass qt-wk2-ews (qt):
Output: http://queues.webkit.org/results/13026992
Comment 26 Early Warning System Bot 2012-06-24 20:13:11 PDT
Comment on attachment 149225 [details]
Patch

Attachment 149225 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/13094006
Comment 27 Build Bot 2012-06-24 20:16:43 PDT
Comment on attachment 149225 [details]
Patch

Attachment 149225 [details] did not pass mac-ews (mac):
Output: http://queues.webkit.org/results/13090023
Comment 28 Build Bot 2012-06-24 20:22:45 PDT
Comment on attachment 149225 [details]
Patch

Attachment 149225 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13087071
Comment 29 Gyuyoung Kim 2012-06-24 20:41:17 PDT
Comment on attachment 149225 [details]
Patch

Attachment 149225 [details] did not pass efl-ews (efl):
Output: http://queues.webkit.org/results/13089037
Comment 30 Peter Wang 2012-06-24 22:31:02 PDT
Created attachment 149240 [details]
Patch
Comment 31 Build Bot 2012-06-24 22:58:49 PDT
Comment on attachment 149240 [details]
Patch

Attachment 149240 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13098014
Comment 32 Peter Wang 2012-06-25 00:35:24 PDT
Created attachment 149259 [details]
Patch
Comment 33 Build Bot 2012-06-25 01:07:21 PDT
Comment on attachment 149259 [details]
Patch

Attachment 149259 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13090081
Comment 34 Peter Wang 2012-06-25 01:58:37 PDT
Created attachment 149263 [details]
Patch
Comment 35 Vsevolod Vlasov 2012-06-25 05:02:56 PDT
Someone who knows JSC better should take a look on this.
Comment 36 Geoffrey Garen 2012-06-25 12:05:20 PDT
<rdar://problem/11741197>
Comment 37 Peter Wang 2012-07-02 04:25:20 PDT
The main modifications of this patch are:
(1) Add a flag to JSC::Interpret::execute, if this flag is true that means we want to compile the code only. 
(2) In PageScriptDebugServer, record the map between frame and sourceID of JS to ensure the modified JS code will be recompiled in same world. 
(3) Implement WebCore::ScriptDebugServer::setScriptSource by calling JSC::Interpret::execute with a flag.


This solution takes the advantage that when JSC compile the same script it will replace the old Identifier with the new one.
Comment 38 Yong Li 2012-07-04 07:35:56 PDT
Comment on attachment 149263 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=149263&action=review

> Source/JavaScriptCore/ChangeLog:8
> +2012-06-21  Peter Wang  <peter.wang@torchmobile.com.cn>
> +
> +        [JSC] Web Inspector: implement script source editing
> +        https://bugs.webkit.org/show_bug.cgi?id=40300
> +
> +        Reviewed by NOBODY (OOPS!).
> +
> +        * debugger/DebuggerCallFrame.cpp:

Can you add more details in changelog?

> Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool justRecompile)

I believe "fooOnly" is more popular pattern in webkit.

> Source/JavaScriptCore/runtime/Completion.h:37
> +    JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, ScopeChainNode*, const SourceCode&, bool, JSValue thisValue = JSValue(), JSValue* exception = 0);
>  } // namespace JSC

Why isn't justRecompile the last argument here?

> Source/WebCore/bindings/js/PageScriptDebugServer.h:58
> +    typedef HashMap<String, Frame*> SourceIdToGlobalObjectMap;

should be SourceIDToGlobalObjectMap?

Are we sure using Frame* is always safe? I.E. no frame can be freed during the life time of this map?

Also, is it possible that one script (or one script ID) can be shared by multiple frames?

> Source/WebCore/bindings/js/ScriptController.cpp:130
> +
> +    RefPtr<Frame> protect(m_frame);

why do we need this? I don't see how recompiling a script can free the Frame object.

> Source/WebCore/bindings/js/ScriptController.h:89
> +    JSC::ExecState* getScriptState();

WebKit doesn't use "getFoo" to name such a getter that passes result only through return value. it could be mainThreadNormalWorldState() -- probably too long? :)

> Source/WebCore/bindings/js/ScriptDebugServer.cpp:201
>  bool ScriptDebugServer::canSetScriptSource()
>  {
> -    return false;
> +    return true;
>  }

why return true here?

> Source/WebCore/bindings/js/ScriptDebugServer.cpp:206
>  bool ScriptDebugServer::setScriptSource(const String&, const String&, bool, String*, ScriptValue*, ScriptObject*)
>  {
> -    // FIXME(40300): implement this.
> -    return false;
> +    return true;
>  }

why return true here but nothing is done?
Comment 39 Yong Li 2012-07-04 07:40:13 PDT
Comment on attachment 149263 [details]
Patch

r- for lack of detailed descriptions in changelog. Also, can you provide a test case (even manual one) or mention how others can test it?
Comment 40 Peter Wang 2012-07-04 20:07:30 PDT
(In reply to comment #38)
> (From update of attachment 149263 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=149263&action=review
> 
> > Source/JavaScriptCore/ChangeLog:8
> > +2012-06-21  Peter Wang  <peter.wang@torchmobile.com.cn>
> > +
> > +        [JSC] Web Inspector: implement script source editing
> > +        https://bugs.webkit.org/show_bug.cgi?id=40300
> > +
> > +        Reviewed by NOBODY (OOPS!).
> > +
> > +        * debugger/DebuggerCallFrame.cpp:
> 
> Can you add more details in changelog?
ok. 
> > Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> > +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool justRecompile)
> 
> I believe "fooOnly" is more popular pattern in webkit.
ok, thx. 
> > Source/JavaScriptCore/runtime/Completion.h:37
> > +    JS_EXPORT_PRIVATE JSValue evaluate(ExecState*, ScopeChainNode*, const SourceCode&, bool, JSValue thisValue = JSValue(), JSValue* exception = 0);
> >  } // namespace JSC
> 
> Why isn't justRecompile the last argument here?
Because the last two parameters have default value, if we pull justRecompile in last position we have to set a default value otherwise it causes a compiling error. 
> > Source/WebCore/bindings/js/PageScriptDebugServer.h:58
> > +    typedef HashMap<String, Frame*> SourceIdToGlobalObjectMap;
> 
> should be SourceIDToGlobalObjectMap?
sure, thx. 
> Are we sure using Frame* is always safe? I.E. no frame can be freed during the life time of this map?
Yes, if the frame is freed the inspector will refresh. So if you can see the source code in inspector, the related frame must exists.
> Also, is it possible that one script (or one script ID) can be shared by multiple frames?
Never. Actually the ID here is the address of SourceProvider of a JS code block. We take it as a index to record from which frame this piece of JS code is executed.  
> > Source/WebCore/bindings/js/ScriptController.cpp:130
> > +
> > +    RefPtr<Frame> protect(m_frame);
> 
> why do we need this? I don't see how recompiling a script can free the Frame object.
Yes, thx. It's the code from my old patch. It's useless now and should be removed.
> > Source/WebCore/bindings/js/ScriptController.h:89
> > +    JSC::ExecState* getScriptState();
> 
> WebKit doesn't use "getFoo" to name such a getter that passes result only through return value. it could be mainThreadNormalWorldState() -- probably too long? :)
ok. 
> > Source/WebCore/bindings/js/ScriptDebugServer.cpp:201
> >  bool ScriptDebugServer::canSetScriptSource()
> >  {
> > -    return false;
> > +    return true;
> >  }
> 
> why return true here?
It's a legacy code, since JSC doesn't support this feature but V8 support. Inpsector uses this interface to probe it. If this bug is fixed, this function plus related JS code of front-end will be removed in a dependent bug report.     
> > Source/WebCore/bindings/js/ScriptDebugServer.cpp:206
> >  bool ScriptDebugServer::setScriptSource(const String&, const String&, bool, String*, ScriptValue*, ScriptObject*)
> >  {
> > -    // FIXME(40300): implement this.
> > -    return false;
> > +    return true;
> >  }
> 
> why return true here but nothing is done?
This function is never be invoked. Its override in PageScriptDebugServer will play the rule. For JSC we cannot implement the feature at "ScriptDebugServer" level as V8 does, since V8 seems have a extra shell layer to record the origin of JS source code.
Comment 41 Peter Wang 2012-07-05 00:06:17 PDT
Created attachment 150884 [details]
Patch
Comment 42 Build Bot 2012-07-05 00:34:23 PDT
Comment on attachment 150884 [details]
Patch

Attachment 150884 [details] did not pass mac-ews (mac):
Output: http://queues.webkit.org/results/13145031
Comment 43 Peter Wang 2012-07-05 00:54:08 PDT
Created attachment 150887 [details]
Patch
Comment 44 Yong Li 2012-07-05 07:22:29 PDT
(In reply to comment #40)
> (In reply to comment #38)
> > Why isn't justRecompile the last argument here?
> Because the last two parameters have default value, if we pull justRecompile in last position we have to set a default value otherwise it causes a compiling error. 

Then we can give a default value? or move arg to the similar position for other functions? It is better to see consistent order.

> > > Source/WebCore/bindings/js/ScriptDebugServer.cpp:201
> > >  bool ScriptDebugServer::canSetScriptSource()
> > >  {
> > > -    return false;
> > > +    return true;
> > >  }
> > 
> > why return true here?
> It's a legacy code, since JSC doesn't support this feature but V8 support. Inpsector uses this interface to probe it. If this bug is fixed, this function plus related JS code of front-end will be removed in a dependent bug report.

I see we are using PageScriptDebugServer. Can we make it virtual and leave the base class to return false?

> > > Source/WebCore/bindings/js/ScriptDebugServer.cpp:206
> > >  bool ScriptDebugServer::setScriptSource(const String&, const String&, bool, String*, ScriptValue*, ScriptObject*)
> > >  {
> > > -    // FIXME(40300): implement this.
> > > -    return false;
> > > +    return true;
> > >  }
> > 
> > why return true here but nothing is done?
> This function is never be invoked. Its override in PageScriptDebugServer will play the rule. For JSC we cannot implement the feature at "ScriptDebugServer" level as V8 does, since V8 seems have a extra shell layer to record the origin of JS source code.

If it is never invoked, why do we change it? A pure virtual function or ASSERT_NOT_REACHED may be better.

> > 
> > should be SourceIDToGlobalObjectMap?
> sure, thx. 

m_sourceIdToGlobalObjectMap is still there :)
Comment 45 Peter Wang 2012-07-05 18:00:08 PDT
(In reply to comment #44)
> (In reply to comment #40)
> > (In reply to comment #38)
> > > Why isn't justRecompile the last argument here?
> > Because the last two parameters have default value, if we pull justRecompile in last position we have to set a default value otherwise it causes a compiling error. 
> 
> Then we can give a default value? or move arg to the similar position for other functions? It is better to see consistent order.

Yes, but there is a trivial reason causes we cannot do that. Firstly, we have to keep the old interface untouched:
evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0);
Otherwise we will break the windows porting since it's a interface of DLL.
Then if we put "compileOnly" in last position with a default value, looks like this: 
evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0, bool compileOnly = false);
The compiler will confused it with the old interface and complain. 
> > > > Source/WebCore/bindings/js/ScriptDebugServer.cpp:201
> > > >  bool ScriptDebugServer::canSetScriptSource()
> > > >  {
> > > > -    return false;
> > > > +    return true;
> > > >  }
> > > 
> > > why return true here?
> > It's a legacy code, since JSC doesn't support this feature but V8 support. Inpsector uses this interface to probe it. If this bug is fixed, this function plus related JS code of front-end will be removed in a dependent bug report.
> 
> I see we are using PageScriptDebugServer. Can we make it virtual and leave the base class to return false?
Don't worry this function too much. It will be removed soon after this bug fixed, like what we did in bug#88759 
> > > > Source/WebCore/bindings/js/ScriptDebugServer.cpp:206
> > > >  bool ScriptDebugServer::setScriptSource(const String&, const String&, bool, String*, ScriptValue*, ScriptObject*)
> > > >  {
> > > > -    // FIXME(40300): implement this.
> > > > -    return false;
> > > > +    return true;
> > > >  }
> > > 
> > > why return true here but nothing is done?
> > This function is never be invoked. Its override in PageScriptDebugServer will play the rule. For JSC we cannot implement the feature at "ScriptDebugServer" level as V8 does, since V8 seems have a extra shell layer to record the origin of JS source code.
> 
> If it is never invoked, why do we change it? A pure virtual function or ASSERT_NOT_REACHED may be better.
Agree with ASSERT_NOT_REACHED, it tells design intension more clearly. Thx.  
> > > 
> > > should be SourceIDToGlobalObjectMap?
> > sure, thx. 
> 
> m_sourceIdToGlobalObjectMap is still there :)
I'm so sorry. It'll be corrected.
Comment 46 Peter Wang 2012-07-05 20:16:20 PDT
Created attachment 151015 [details]
Patch
Comment 47 Yong Li 2012-07-06 07:12:42 PDT
(In reply to comment #45)
> (In reply to comment #44)
> > (In reply to comment #40)
> > > (In reply to comment #38)
> > > > Why isn't justRecompile the last argument here?
> > > Because the last two parameters have default value, if we pull justRecompile in last position we have to set a default value otherwise it causes a compiling error. 
> > 
> > Then we can give a default value? or move arg to the similar position for other functions? It is better to see consistent order.
> 
> Yes, but there is a trivial reason causes we cannot do that. Firstly, we have to keep the old interface untouched:
> evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0);
> Otherwise we will break the windows porting since it's a interface of DLL.
> Then if we put "compileOnly" in last position with a default value, looks like this: 
> evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0, bool compileOnly = false);
> The compiler will confused it with the old interface and complain. 

Can't we change the DLL interface or ask Apple gentlemen for help?

> > > > > Source/WebCore/bindings/js/ScriptDebugServer.cpp:201
> > > > >  bool ScriptDebugServer::canSetScriptSource()
> > > > >  {
> > > > > -    return false;
> > > > > +    return true;
> > > > >  }
> > > > 
> > > > why return true here?
> > > It's a legacy code, since JSC doesn't support this feature but V8 support. Inpsector uses this interface to probe it. If this bug is fixed, this function plus related JS code of front-end will be removed in a dependent bug report.
> > 
> > I see we are using PageScriptDebugServer. Can we make it virtual and leave the base class to return false?
> Don't worry this function too much. It will be removed soon after this bug fixed, like what we did in bug#88759 

We shouldn't push unfinished thing into the repo. Logically ScriptDebugServer doesn't support setScriptSource() by itself.
Comment 48 Konrad Piascik 2012-07-06 07:43:30 PDT
Comment on attachment 151015 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=151015&action=review

> Source/WebCore/ChangeLog:12
> +        The related test cases already exist.

Do the tests need to be enalbed on JSC builds? ie unskipped?
Comment 49 Yong Li 2012-07-06 07:48:24 PDT
Comment on attachment 151015 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=151015&action=review

> Source/WebCore/bindings/js/ScriptDebugServer.cpp:207
>  bool ScriptDebugServer::setScriptSource(const String&, const String&, bool, String*, ScriptValue*, ScriptObject*)
>  {
> -    // FIXME(40300): implement this.
> +    ASSERT_NOT_REACHED();
>      return false;
>  }

As pointed by Konrad, ASSERT_NOT_REACHED() looks weird here because pure virtual function makes more sense. sorry for my old suggestion.
Comment 50 Yong Li 2012-07-06 07:50:22 PDT
Can JSC experts put some comments? Is it the right approach?
Comment 51 Peter Wang 2012-07-06 16:20:06 PDT
(In reply to comment #48)
> (From update of attachment 151015 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=151015&action=review
> 
> > Source/WebCore/ChangeLog:12
> > +        The related test cases already exist.
> 
> Do the tests need to be enalbed on JSC builds? ie unskipped?

Frankly speaking, I don't plan to unskip related test case here, since at least Qt porting still has some problems to support some inspector test, like bug#89056. I'm planning to enable it in an independent bug report to make it more clear.
Comment 52 Peter Wang 2012-07-06 16:24:54 PDT
(In reply to comment #49)
> (From update of attachment 151015 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=151015&action=review
> 
> > Source/WebCore/bindings/js/ScriptDebugServer.cpp:207
> >  bool ScriptDebugServer::setScriptSource(const String&, const String&, bool, String*, ScriptValue*, ScriptObject*)
> >  {
> > -    // FIXME(40300): implement this.
> > +    ASSERT_NOT_REACHED();
> >      return false;
> >  }
> 
> As pointed by Konrad, ASSERT_NOT_REACHED() looks weird here because pure virtual function makes more sense. sorry for my old suggestion.

I agree with Konrad that pure virtual function is better, but some porting derived their own new class form "ScriptDebugServer", pure virtual function will break their own code :(.
Comment 53 Peter Wang 2012-07-11 19:59:57 PDT
Created attachment 151849 [details]
Patch
Comment 54 Peter Wang 2012-07-11 21:08:23 PDT
(In reply to comment #53)
> Created an attachment (id=151849) [details]
> Patch

Since the interface "setScriptSource" for JSC is implemented in "PageScriptDebugServer", so set it as pure virtual function to avoid misuse and make the meaning of code more clear.
Comment 55 Yong Li 2012-07-12 07:25:05 PDT
So, we don't worry about this any more? "some porting derived their own new class form "ScriptDebugServer"

Also ScriptDebugServer::canSetScriptSource() should be virtual. It is weird that the base class forces all derived classes to support it. If so, why do we even call this method?

Back to the approach you are doing, have you tested the case that the script has been referenced by other scripts? I am afraid some JIT assemblies can still be using the old executable, or even worse, linking to freed memory.
Comment 56 Filip Pizlo 2012-07-12 14:49:05 PDT
Comment on attachment 151849 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=151849&action=review

> Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
> +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool compileOnly)

It would be better if we created a compile() helper, preferably outside of the Interpreter class if it's easy.  That way instead of saying execute(blah, true) you'd say compile().

> Source/JavaScriptCore/runtime/Completion.cpp:-56
> -    JSLockHolder lock(exec);

Did you put in some locking elsewhere to justify the removal of this lock acquisition?
Comment 57 Peter Wang 2012-07-12 19:03:16 PDT
(In reply to comment #55)
> So, we don't worry about this any more? "some porting derived their own new class form "ScriptDebugServer"
> 
> Also ScriptDebugServer::canSetScriptSource() should be virtual. It is weird that the base class forces all derived classes to support it. If so, why do we even call this method?

Like bug#88759, this bug removed an interface ScriptDebugServer::supportsNativeBreakpoints(), this interface existed just because JSC didn't support a feature that V8 supports. As JSC started to support it, this interface became useless and was removed.
We'll do the same thing to canSetScriptSource(). 
These interfaces are just transitions, so eventually they will be removed.    

 
> Back to the approach you are doing, have you tested the case that the script has been referenced by other scripts? I am afraid some JIT assemblies can still be using the old executable, or even worse, linking to freed memory.
Yes, I did. 
My approach is almost executing the same piece of JS again, just skip the step of creating a new call frame and reading the executable to evaluate. All the operations that can change the executable are still included, so I think it's safe.
Comment 58 Peter Wang 2012-07-12 19:34:09 PDT
(In reply to comment #56)
> (From update of attachment 151849 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=151849&action=review
> 
> > Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> > -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
> > +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool compileOnly)
> 
> It would be better if we created a compile() helper, preferably outside of the Interpreter class if it's easy.  That way instead of saying execute(blah, true) you'd say compile().

I considered this way once. But Interpreter::execute implements all steps of compiling, so that if I want to write an independent compile(), I just need to copy Interpreter::execute and delete several lines, it looks ugly.
It's the reason.  

> 
> > Source/JavaScriptCore/runtime/Completion.cpp:-56
> > -    JSLockHolder lock(exec);
> 
> Did you put in some locking elsewhere to justify the removal of this lock acquisition?

Oops, sorry. It's supposed to be here. It's a mistake, seems imported from attachment 149263 [details]. I'll correct it.
Comment 59 Peter Wang 2012-07-12 19:44:43 PDT
Created attachment 152134 [details]
Patch
Comment 60 Filip Pizlo 2012-07-12 19:51:26 PDT
Comment on attachment 152134 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=152134&action=review

> Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
> +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool compileOnly)

Split this into two methods, one that compiles, and the other that compiles and executes.
Comment 61 Filip Pizlo 2012-07-12 19:51:51 PDT
(In reply to comment #58)
> (In reply to comment #56)
> > (From update of attachment 151849 [details] [details])
> > View in context: https://bugs.webkit.org/attachment.cgi?id=151849&action=review
> > 
> > > Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> > > -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
> > > +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool compileOnly)
> > 
> > It would be better if we created a compile() helper, preferably outside of the Interpreter class if it's easy.  That way instead of saying execute(blah, true) you'd say compile().
> 
> I considered this way once. But Interpreter::execute implements all steps of compiling, so that if I want to write an independent compile(), I just need to copy Interpreter::execute and delete several lines, it looks ugly.
> It's the reason.  

Are you joking?

> 
> > 
> > > Source/JavaScriptCore/runtime/Completion.cpp:-56
> > > -    JSLockHolder lock(exec);
> > 
> > Did you put in some locking elsewhere to justify the removal of this lock acquisition?
> 
> Oops, sorry. It's supposed to be here. It's a mistake, seems imported from attachment 149263 [details]. I'll correct it.
Comment 62 Peter Wang 2012-07-12 20:09:49 PDT
(In reply to comment #61)
> (In reply to comment #58)
> > (In reply to comment #56)
> > > (From update of attachment 151849 [details] [details] [details])
> > > View in context: https://bugs.webkit.org/attachment.cgi?id=151849&action=review
> > > 
> > > > Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> > > > -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
> > > > +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool compileOnly)
> > > 
> > > It would be better if we created a compile() helper, preferably outside of the Interpreter class if it's easy.  That way instead of saying execute(blah, true) you'd say compile().
> > 
> > I considered this way once. But Interpreter::execute implements all steps of compiling, so that if I want to write an independent compile(), I just need to copy Interpreter::execute and delete several lines, it looks ugly.
> > It's the reason.  
> 
> Are you joking?
> 
?? 
No. I'm serious. Parsing, Building AST, Generiting bytecode, creating call frame to evaluate the executable. Except the last step, Interpreter::execute does all steps of compiling.
Comment 63 Filip Pizlo 2012-07-12 20:11:31 PDT
(In reply to comment #62)
> (In reply to comment #61)
> > (In reply to comment #58)
> > > (In reply to comment #56)
> > > > (From update of attachment 151849 [details] [details] [details] [details])
> > > > View in context: https://bugs.webkit.org/attachment.cgi?id=151849&action=review
> > > > 
> > > > > Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> > > > > -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
> > > > > +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool compileOnly)
> > > > 
> > > > It would be better if we created a compile() helper, preferably outside of the Interpreter class if it's easy.  That way instead of saying execute(blah, true) you'd say compile().
> > > 
> > > I considered this way once. But Interpreter::execute implements all steps of compiling, so that if I want to write an independent compile(), I just need to copy Interpreter::execute and delete several lines, it looks ugly.
> > > It's the reason.  
> > 
> > Are you joking?
> > 
> ?? 
> No. I'm serious. Parsing, Building AST, Generiting bytecode, creating call frame to evaluate the executable. Except the last step, Interpreter::execute does all steps of compiling.

Invoking a method called "execute" in order to compile something is bizarre.
Comment 64 Peter Wang 2012-07-12 20:34:47 PDT
(In reply to comment #63)
> (In reply to comment #62)
> > (In reply to comment #61)
> > > (In reply to comment #58)
> > > > (In reply to comment #56)
> > > > > (From update of attachment 151849 [details] [details] [details] [details] [details])
> > > > > View in context: https://bugs.webkit.org/attachment.cgi?id=151849&action=review
> > > > > 
> > > > > > Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> > > > > > -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
> > > > > > +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool compileOnly)
> > > > > 
> > > > > It would be better if we created a compile() helper, preferably outside of the Interpreter class if it's easy.  That way instead of saying execute(blah, true) you'd say compile().
> > > > 
> > > > I considered this way once. But Interpreter::execute implements all steps of compiling, so that if I want to write an independent compile(), I just need to copy Interpreter::execute and delete several lines, it looks ugly.
> > > > It's the reason.  
> > > 
> > > Are you joking?
> > > 
> > ?? 
> > No. I'm serious. Parsing, Building AST, Generiting bytecode, creating call frame to evaluate the executable. Except the last step, Interpreter::execute does all steps of compiling.
> 
> Invoking a method called "execute" in order to compile something is bizarre.

Yes, so I'd like to discuss. Based on the current situation, by my opinion, I think there are three ways to solve it:
(1) Have independent compile() and execute() with a big block of same code.
(2) Have execute() with a parameter.
(3) Move compiling related code to an independent function compile(), and let execute() to invoke it.    
I said the reason why I don't choose (1). I prefer (2) because it brings minimal modification. Do you mean you prefer (3)? I just concern there is too big modification.
Comment 65 Filip Pizlo 2012-07-12 20:43:19 PDT
(In reply to comment #64)
> (In reply to comment #63)
> > (In reply to comment #62)
> > > (In reply to comment #61)
> > > > (In reply to comment #58)
> > > > > (In reply to comment #56)
> > > > > > (From update of attachment 151849 [details] [details] [details] [details] [details] [details])
> > > > > > View in context: https://bugs.webkit.org/attachment.cgi?id=151849&action=review
> > > > > > 
> > > > > > > Source/JavaScriptCore/interpreter/Interpreter.cpp:1094
> > > > > > > -JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj)
> > > > > > > +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, bool compileOnly)
> > > > > > 
> > > > > > It would be better if we created a compile() helper, preferably outside of the Interpreter class if it's easy.  That way instead of saying execute(blah, true) you'd say compile().
> > > > > 
> > > > > I considered this way once. But Interpreter::execute implements all steps of compiling, so that if I want to write an independent compile(), I just need to copy Interpreter::execute and delete several lines, it looks ugly.
> > > > > It's the reason.  
> > > > 
> > > > Are you joking?
> > > > 
> > > ?? 
> > > No. I'm serious. Parsing, Building AST, Generiting bytecode, creating call frame to evaluate the executable. Except the last step, Interpreter::execute does all steps of compiling.
> > 
> > Invoking a method called "execute" in order to compile something is bizarre.
> 
> Yes, so I'd like to discuss. Based on the current situation, by my opinion, I think there are three ways to solve it:
> (1) Have independent compile() and execute() with a big block of same code.

Bad.

> (2) Have execute() with a parameter.

Bad.

> (3) Move compiling related code to an independent function compile(), and let execute() to invoke it.    

That's what I'm asking for.

> I said the reason why I don't choose (1). I prefer (2) because it brings minimal modification. Do you mean you prefer (3)? I just concern there is too big modification.

(3) is the only sensible path.
Comment 66 Peter Wang 2012-07-12 20:57:20 PDT
(In reply to comment #65)
> (In reply to comment #64)
> > (In reply to comment #63)
> > > (In reply to comment #62)
> > > > (In reply to comment #61)
> > > > > (In reply to comment #58)
> > > > > > (In reply to comment #56)
> > > > > > > (From update of attachment 151849 [details] [details] [details] [details] [details] [details] [details])
> > > > > > > View in context: https://bugs.webkit.org/attachment.cgi?id=151849&action=review
> > > > > > > 
> > > > > > > > Source/JavaScriptCore/interpreter/Interpreter.cpp:1094

> > (3) Move compiling related code to an independent function compile(), and let execute() to invoke it.    
> 
> That's what I'm asking for.
> 
> > I said the reason why I don't choose (1). I prefer (2) because it brings minimal modification. Do you mean you prefer (3)? I just concern there is too big modification.
> 
> (3) is the only sensible path.

Ok, I understand what you mean now. I'll try to make a new patch.
Comment 67 Geoffrey Garen 2012-07-16 12:27:03 PDT
Comment on attachment 152134 [details]
Patch

It looks like this patch will recompile a top-level program and then replace all global functions declared by that program using the function keyword. Is that really how this feature is supposed to work? What happens to non-global functions and functions declared using the var keyword?
Comment 68 Peter Wang 2012-07-23 05:21:11 PDT
(In reply to comment #67)
> (From update of attachment 152134 [details])
> It looks like this patch will recompile a top-level program and then replace all global functions declared by that program using the function keyword. Is that really how this feature is supposed to work? What happens to non-global functions and functions declared using the var keyword?

Sorry for reply your comments so late. I did a test again, my patch can pass the test cases you mentioned. Since the Identifier of old function is replaced, the function body will also be recompiled.
Comment 69 Geoffrey Garen 2012-07-23 16:53:20 PDT
Created attachment 153900 [details]
test case

I believe this test case will fail, given your approach to code editing.
Comment 70 Peter Wang 2012-07-23 18:59:46 PDT
(In reply to comment #69)
> Created an attachment (id=153900) [details]
> test case
> 
> I believe this test case will fail, given your approach to code editing.

I did a test, my patch can pass this test. :)
Comment 71 Peter Wang 2012-07-30 21:35:59 PDT
Created attachment 155436 [details]
Patch
Comment 72 Build Bot 2012-07-30 21:58:02 PDT
Comment on attachment 155436 [details]
Patch

Attachment 155436 [details] did not pass mac-ews (mac):
Output: http://queues.webkit.org/results/13390639
Comment 73 Build Bot 2012-07-30 22:10:32 PDT
Comment on attachment 155436 [details]
Patch

Attachment 155436 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13387652
Comment 74 Peter Wang 2012-07-30 23:12:15 PDT
Created attachment 155446 [details]
Patch
Comment 75 Build Bot 2012-07-30 23:35:52 PDT
Comment on attachment 155446 [details]
Patch

Attachment 155446 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13392599
Comment 76 Peter Wang 2012-07-31 00:06:52 PDT
Created attachment 155450 [details]
Patch
Comment 77 Build Bot 2012-07-31 00:24:25 PDT
Comment on attachment 155450 [details]
Patch

Attachment 155450 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13385801
Comment 78 Peter Wang 2012-07-31 01:09:02 PDT
Created attachment 155460 [details]
Patch
Comment 79 Build Bot 2012-07-31 01:27:48 PDT
Comment on attachment 155460 [details]
Patch

Attachment 155460 [details] did not pass win-ews (win):
Output: http://queues.webkit.org/results/13396564
Comment 80 Peter Wang 2012-07-31 02:23:28 PDT
Created attachment 155472 [details]
Patch
Comment 81 Geoffrey Garen 2012-08-16 09:49:11 PDT
> > I believe this test case will fail, given your approach to code editing.
> 
> I did a test, my patch can pass this test. :)

I don't think you ran the test right. I don't see any code in this patch that would make it work.
Comment 82 Peter Wang 2012-08-27 05:11:32 PDT
(In reply to comment #81)
> > > I believe this test case will fail, given your approach to code editing.
> > 
> > I did a test, my patch can pass this test. :)
> 
> I don't think you ran the test right. I don't see any code in this patch that would make it work.

Sorry, I did a test again with newest code, my patch doesn't pass this test, and V8 can pass it. :(

However, the reason is not that the embedded functions aren't be recompiled. In JSC, the expression  
var aa = function button1Click() {...};
is compiled as there is a function declaration with name "aa" (refer to JSC::AssignResolveNode::emitBytecode). And we need "execute" these bytecodes to make "aa" to become related with the new function body.

The book "JavaScript: The Definitive Guide" says, for that type of expression, like 
var aa = function button1Click() {...}; 
"aa" should work like a pointer to the function. 
I'm not expert of javascript syntax, maybe it's a defect of JSC implementation?
Comment 83 Geoffrey Garen 2012-08-27 17:50:05 PDT
> I'm not expert of javascript syntax, maybe it's a defect of JSC implementation?

No, you've just misdiagnosed the issue.
Comment 84 Peter Wang 2012-08-27 18:27:50 PDT
(In reply to comment #83)
> > I'm not expert of javascript syntax, maybe it's a defect of JSC implementation?
> 
> No, you've just misdiagnosed the issue.

Sorry, I'm a little confused. You mean:
(1) The way to implementation of "setScriptSource" is wrong, I shouldn't implement it by recompiling?
(2) Or, I don't understand this feature well? I think it gives user a chance to modify some function or expression and see what will happen if these function or expression triggered. Do you think it's right?
Comment 85 Peter Wang 2012-10-09 03:05:15 PDT
(In reply to comment #83)
> > I'm not expert of javascript syntax, maybe it's a defect of JSC implementation?
> 
> No, you've just misdiagnosed the issue.

Agree, I understand it now, thank you very much.
Comment 86 Pavel Feldman 2012-12-14 00:20:16 PST
It requires a JSC reviewer, changing the component to remove it off the inspector dashboard.
Comment 87 Timothy Hatcher 2013-01-23 12:03:36 PST
Can someone on the JSC team take a look at the latest patch?
Comment 88 Oliver Hunt 2013-01-23 12:05:17 PST
Comment on attachment 155472 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=155472&action=review

I've redone how compilation works since this patch was put up so a lot of the refactoring can probably go away :-/

> Source/JavaScriptCore/interpreter/Interpreter.cpp:1131
> -                    if (i == 0) {
> +                    if (!i) {

Don't change this, while it's a style violation we don't really like changes just to appease the style bot.
Comment 89 kangax 2013-12-10 01:57:51 PST
Any news on this?
Comment 90 Peter Wang 2013-12-11 19:07:43 PST
(In reply to comment #89)
> Any news on this?
The patches of mine cannot cover all the cases, so just ignore them. I'm not sure if JSC supports live-editing js code right now. If not, maybe, I should spend sometime to investigate and try again.
Comment 91 Timothy Hatcher 2013-12-11 19:44:14 PST
JSC does not support live-editing right now. It is a complex problem (especially when closures are involved.)