Bug 64466 - Refactor JSC to replace JSCell::operator new with static create method
Summary: Refactor JSC to replace JSCell::operator new with static create method
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Mark Hahnenberg
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-07-13 10:48 PDT by Mark Hahnenberg
Modified: 2011-07-18 10:47 PDT (History)
3 users (show)

See Also:


Attachments
Proposed patch. (110.03 KB, patch)
2011-07-13 11:33 PDT, Mark Hahnenberg
no flags Details | Formatted Diff | Diff
Patch (138.12 KB, patch)
2011-07-13 19:00 PDT, Mark Hahnenberg
no flags Details | Formatted Diff | Diff
Patch (138.00 KB, patch)
2011-07-13 19:14 PDT, Mark Hahnenberg
no flags Details | Formatted Diff | Diff
Patch (138.54 KB, patch)
2011-07-14 13:57 PDT, Mark Hahnenberg
no flags Details | Formatted Diff | Diff
Patch (159.71 KB, patch)
2011-07-14 18:18 PDT, Mark Hahnenberg
no flags Details | Formatted Diff | Diff
Patch (160.13 KB, patch)
2011-07-14 19:10 PDT, Mark Hahnenberg
no flags Details | Formatted Diff | Diff
Patch (162.77 KB, patch)
2011-07-15 12:37 PDT, Mark Hahnenberg
no flags Details | Formatted Diff | Diff
Patch (163.30 KB, patch)
2011-07-15 13:17 PDT, Mark Hahnenberg
no flags Details | Formatted Diff | Diff
Patch (164.52 KB, patch)
2011-07-18 09:04 PDT, Mark Hahnenberg
darin: review+
webkit.review.bot: commit-queue-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Hahnenberg 2011-07-13 10:48:20 PDT
This is the first of a series of bugs to refactor JSC and its related DOM bindings to use static create methods when creating heap-allocated JS objects.  The goal of this bug is simply to replace all instances of JSCell::operator new within JSC with the new static create methods.
Comment 1 Mark Hahnenberg 2011-07-13 11:33:57 PDT
Created attachment 100695 [details]
Proposed patch.
Comment 2 WebKit Review Bot 2011-07-13 11:37:41 PDT
Attachment 100695 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/JavaScriptCore/API/JSCallbackConstr..." exit_code: 1

Source/JavaScriptCore/runtime/StringConstructor.h:32:  The parameter name "structure" adds no information, so it should be removed.  [readability/parameter_name] [5]
Source/JavaScriptCore/runtime/RegExpConstructor.h:60:  The parameter name "structure" adds no information, so it should be removed.  [readability/parameter_name] [5]
Source/JavaScriptCore/runtime/NumberConstructor.h:32:  The parameter name "structure" adds no information, so it should be removed.  [readability/parameter_name] [5]
Total errors found: 3 in 75 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 3 Darin Adler 2011-07-13 11:39:28 PDT
Comment on attachment 100695 [details]
Proposed patch.

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

> Source/JavaScriptCore/API/JSCallbackConstructor.h:36
> +        JSCallbackConstructor(JSGlobalObject*, Structure*, JSClassRef, JSObjectCallAsConstructorCallback);

Incorrect indentation here.

> Source/JavaScriptCore/API/JSCallbackConstructor.h:42
> +        JSCallbackConstructor* result = static_cast<JSCallbackConstructor*>(exec->heap()->allocate(sizeof(JSCallbackConstructor)));
> +        result->m_structure.clear();
> +        return new (result) JSCallbackConstructor(globalObject, structure, classRef, callback);

Before we repeat this idiom everywhere, I suggest we:

    1) Make a function that combines the allocation and the clear in a single function call.
    2) Make a function template that takes the type as an argument and does the sizeof and typecasting.

Then this function would be a one-liner:

    return new (allocateJSObject<JSCallbackConstructor>(exec)) JSCallbackConstructor(globalObject, structure, classRef, callback);
Comment 4 Oliver Hunt 2011-07-13 11:57:26 PDT
Comment on attachment 100695 [details]
Proposed patch.

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

In general this patch is correct, there are just a few overall refinements i'd recommend

* You don't need to clear the structure everytime, that's only needed as a workaround for the existing sequencing issues.
* Given you don't need to clear the structure a single function along the lines of template <typename T> void* allocateCell<T>(exec/globalData/heap/whatever) can just be used for all allocations, and the create methods become 
return new (allocateCell<type goes here>(exec/globalData/whatever)) Constructor(...)

That should simplify the creation routines quite a bit.

If you use the webkit-patch script it will run the style checker before uploading so you can correct any style issues before submitting for review (the commit queue is meant to reject patches with style errors so theoretically wouldn't accept a patch with such errors)

> Source/JavaScriptCore/ChangeLog:6
> +

There needs to be a description of the change here, look for other changelog entries for examples of the level of detail that's expected.  While this is mostly a mechanical change, so doesn't require huge amounts of elaboration, we typically expect a reasonable amount of detail from new-ish contributors.

> Source/JavaScriptCore/API/JSCallbackConstructor.h:41
> +        result->m_structure.clear();

You don't need these calls to clear the structure -- they exist in operator new() to mitigate the problem that this patch is fixing.

> Source/JavaScriptCore/API/JSCallbackObject.h:136
> +    static JSCallbackObject* allocCallbackObj(ExecState* exec)
> +    {
> +        JSCallbackObject* result = static_cast<JSCallbackObject*>(exec->heap()->allocate(sizeof(JSCallbackObject)));
> +        result->m_structure.clear();
> +        return result;
> +    }
> +public:
> +    static JSCallbackObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSClassRef classRef, void* data)
> +    {
> +        return new (allocCallbackObj(exec)) JSCallbackObject(exec, globalObject, structure, classRef, data);
> +    }
> +    static JSCallbackObject* create(JSGlobalData* globalData, JSClassRef classRef, Structure* structure)
> +    {
> +        return new (globalData) JSCallbackObject(*globalData, classRef, structure);
> +    }

i think allocCallbackObj can be private, and you should kill off the new (globalData) usage

> Source/JavaScriptCore/runtime/ArrayPrototype.cpp:585
> +    JSArray* resObj = JSArray::create(exec, exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount, CreateCompact);

The additional exec shouldn't be necessary.

> Source/JavaScriptCore/runtime/BooleanObject.h:33
> +        static BooleanObject* create(ExecState* exec, JSGlobalData& globalData, Structure* structure)

You don't need the exec parameter -- just use globalData.heap (exec->heap() is actually doing exec->globalData().heap)

> Source/JavaScriptCore/runtime/DateInstance.h:37
> +        static DateInstance* allocDateInstance(ExecState* exec)

This can probably be private.

> Source/JavaScriptCore/runtime/Error.cpp:172
> +    : InternalFunction(&exec->globalData(), globalObject, structure, exec->globalData().propertyNames->emptyIdentifier)
> +    , m_message(message)

should be indented

> Source/JavaScriptCore/runtime/Executable.h:327
> +            ProgramExecutable* result = static_cast<ProgramExecutable*>(exec->heap()->allocate(sizeof(ProgramExecutable)));

The more i look at this pattern the more i wonder if we want to add a void* allocate<T>() { return allocate(sizeof(T)); } style function to heap.

Also these casts are unnecessary, void* is fine (as you don't need to clear the structure)

> Source/JavaScriptCore/runtime/GetterSetter.h:43
> +        : JSCell(exec->globalData(), exec->globalData().getterSetterStructure.get())
> +        {
> +        }

indentation

> Source/JavaScriptCore/runtime/JSCell.h:89
>      protected:
>          enum VPtrStealingHackType { VPtrStealingHack };
> -
> +        
>      private:
>          explicit JSCell(VPtrStealingHackType) { }
>          JSCell(JSGlobalData&, Structure*);
>          JSCell(JSGlobalData&, Structure*, CreatingEarlyCellTag);
>          virtual ~JSCell();
>          static const ClassInfo s_dummyCellInfo;
> -
> +        
> +        

Random whitespace changes == badness

> Source/JavaScriptCore/runtime/JSCell.h:-168
> +        WriteBarrier<Structure> m_structure;
>  
>      private:
>          // Base implementation; for non-object classes implements getPropertySlot.
>          virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
>          virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
>          
> -        WriteBarrier<Structure> m_structure;

This should be unnecessary once you remove the extraneous calls to clear()
Comment 5 Mark Hahnenberg 2011-07-13 19:00:32 PDT
Created attachment 100754 [details]
Patch
Comment 6 WebKit Review Bot 2011-07-13 19:03:34 PDT
Attachment 100754 [details] did not pass style-queue:

Failed to run "['Tools/Scripts/check-webkit-style', '--diff-files', u'Source/JavaScriptCore/API/JSCallbackConstr..." exit_code: 1

Source/JavaScriptCore/runtime/StringConstructor.h:32:  The parameter name "structure" adds no information, so it should be removed.  [readability/parameter_name] [5]
Source/JavaScriptCore/runtime/RegExpConstructor.h:60:  The parameter name "structure" adds no information, so it should be removed.  [readability/parameter_name] [5]
Source/JavaScriptCore/runtime/NumberConstructor.h:32:  The parameter name "structure" adds no information, so it should be removed.  [readability/parameter_name] [5]
Total errors found: 3 in 87 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 7 Mark Hahnenberg 2011-07-13 19:05:50 PDT
On a side note, I don't think that I added the additional parameters that the style bot is talking about.  Superficially it does appear that they aren't used, but I didn't want to mess with it right now.
Comment 8 Mark Hahnenberg 2011-07-13 19:11:28 PDT
Never mind, upon closer scrutiny I guess I did accidentally add the parameter name.
Comment 9 Mark Hahnenberg 2011-07-13 19:14:06 PDT
Created attachment 100755 [details]
Patch
Comment 10 Early Warning System Bot 2011-07-13 19:41:52 PDT
Comment on attachment 100755 [details]
Patch

Attachment 100755 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/9019859
Comment 11 Darin Adler 2011-07-13 20:58:14 PDT
Comment on attachment 100755 [details]
Patch

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

This looks good.

There are some calls to new inside WebCore/bridge/qt/qt_runtime.cpp that need to be changed to use create instead.

review+ but you’ll need to at least fix the Qt build issue.

> Source/JavaScriptCore/jsc.cpp:147
> +protected:
>      GlobalObject(JSGlobalData&, Structure*, const Vector<UString>& arguments);

I suggest you make these constructors private rather than protected in classes where there is no derived class. Generally speaking we would like to use private more often than protected.

> Source/JavaScriptCore/jsc.cpp:152
> +        return new (allocateCell<GlobalObject>(&(globalData.heap))) GlobalObject(globalData, structure, arguments);

This has one extra set of parentheses, around globalData.heap, and I think it would read better without them. There are similar extra parentheses in other places in the patch.

> Source/JavaScriptCore/API/JSCallbackObject.h:123
> +    // pseudo-placement version of operator new
> +    void* operator new(size_t, void* ptr) { return ptr; }

Why is this needed? What about the real placement new? Why can’t we use that?

This comment is a “what” comment, and instead we want our comments to be “why” comments. Also we normally want our comments to be sentence style with a first capital letter and a period.

> Source/JavaScriptCore/runtime/JSCell.h:379
> +    template <typename T> void* allocateCell(Heap* heap)

I think we should use a reference to a heap here instead of a pointer to a heap.
Comment 12 Mark Hahnenberg 2011-07-14 13:57:03 PDT
Created attachment 100855 [details]
Patch
Comment 13 Darin Adler 2011-07-14 14:07:23 PDT
Comment on attachment 100855 [details]
Patch

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

> Source/JavaScriptCore/bytecode/CodeBlock.cpp:1738
> +    JSActivation* activation = JSActivation::create(&(callFrame->globalData()), callFrame, static_cast<FunctionExecutable*>(ownerExecutable()));

This still has extra parentheses.

> Source/JavaScriptCore/interpreter/Interpreter.cpp:5070
> +        JSValue arguments = JSValue(Arguments::create(&(callFrame->globalData()), functionCallFrame));

This still has extra parentheses.

> Source/JavaScriptCore/interpreter/Interpreter.cpp:5076
> +    Arguments* arguments = Arguments::create(&(functionCallFrame->globalData()), functionCallFrame);

This still has extra parentheses.

> Source/JavaScriptCore/jit/JITStubs.cpp:2065
> +    JSActivation* activation = JSActivation::create(&(stackFrame.callFrame->globalData()), stackFrame.callFrame, static_cast<FunctionExecutable*>(stackFrame.callFrame->codeBlock()->ownerExecutable()));

This still has extra parentheses.

> Source/JavaScriptCore/runtime/Arguments.h:72
> +        static Arguments* create(JSGlobalData* globalData, CallFrame* callFrame, NoParametersType noParams)
> +        {
> +            return new (allocateCell<Arguments>(globalData->heap)) Arguments(callFrame, noParams);
> +        }

For "new" we need to use an extra argument because it’s a way to make a named constructor.

But for a create function, we can actually name the create function in a way that makes clear what these two different types of creation are and thus we don’t need to use the “extra argument” technique.

> Source/JavaScriptCore/runtime/JSActivation.cpp:223
> +    JSValue arguments = JSValue(Arguments::create(&(callFrame->globalData()), callFrame));

This still has extra parentheses.

> Source/JavaScriptCore/runtime/JSString.h:351
> +        static JSString* create(JSGlobalData* globalData, const UString& value, HasOtherOwnerType hasOtherOwnerType)
> +        {
> +            return new (allocateCell<JSString>(globalData->heap)) JSString(globalData, value, hasOtherOwnerType);
> +        }
> +        static JSString* create(JSGlobalData* globalData, PassRefPtr<StringImpl> value, HasOtherOwnerType hasOtherOwnerType)
> +        {
> +            return new (allocateCell<JSString>(globalData->heap)) JSString(globalData, value, hasOtherOwnerType);
> +        }

Same comment here as above. In a create function we can use a sensible function name rather than an extra parameter as the way to implement alternate constructors.

This lets us limit the awkward “extra parameter” technique to local use inside a class, and the type used for that technique can even be private to the class.

> Source/JavaScriptCore/runtime/NumberObject.h:30
>          explicit NumberObject(JSGlobalData&, Structure*);

It makes no sense to have “explicit” on a constructor with multiple arguments, so we really ought to remove this.
Comment 14 Mark Hahnenberg 2011-07-14 18:18:10 PDT
I thought the main reason for the additional argument to operator new was to intercept the allocation request so that we can allocate the memory for the new object on our own GC-managed heap?
Comment 15 Mark Hahnenberg 2011-07-14 18:18:35 PDT
Created attachment 100909 [details]
Patch
Comment 16 Darin Adler 2011-07-14 18:29:13 PDT
Comment on attachment 100909 [details]
Patch

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

Sorry to drive you crazy with new comments each time. I noticed some other things I missed last time.

> Source/JavaScriptCore/jsc.cpp:146
> -public:
>      GlobalObject(JSGlobalData&, Structure*, const Vector<UString>& arguments);

We are normally explicit about private even at the top of a class.

> Source/JavaScriptCore/API/JSCallbackObject.h:123
> +    // This version of operator new is necessary because we can't tell statically 
> +    // that Base will inherit the correct placement version of operator new from JSCell.

The wording here is confusing. I think what you mean to say is that we would like to use the placement version of operator new in JSCell, but can’t because Base is a template argument.

> Source/JavaScriptCore/API/JSContextRef.cpp:100
> +    JSGlobalObject* globalObject = JSCallbackObject<JSGlobalObject>::create(*globalData.get(), globalObjectClass, JSCallbackObject<JSGlobalObject>::createStructure(*globalData, jsNull()));

I am surprised that this .get() is needed. Are you sure you needed to add it?

> Source/JavaScriptCore/runtime/ArrayConstructor.h:31
> -    public:
>          ArrayConstructor(ExecState*, JSGlobalObject*, Structure*, ArrayPrototype*);

Same issue here, where in this project we would normally make private explicit rather than depending on the "first things in a class are private" feature.

> Source/JavaScriptCore/runtime/ArrayPrototype.h:-30
> -    public:

Here too.

> Source/JavaScriptCore/runtime/BooleanConstructor.h:-31
> -    public:

Again. I won’t call out the other cases.

> Source/JavaScriptCore/runtime/RegExp.h:82
> +        // Normally this method would be called create, but we have to avoid a potential conflict with the 
> +        // normal public create method that handles caching as well.
> +        static RegExp* allocateAndInit(JSGlobalData&, const UString&, RegExpFlags);

Given that description I would name it createWithoutCaching or something like that.
Comment 17 Mark Hahnenberg 2011-07-14 19:10:21 PDT
Created attachment 100914 [details]
Patch
Comment 18 Darin Adler 2011-07-14 20:20:45 PDT
(In reply to comment #14)
> I thought the main reason for the additional argument to operator new was to intercept the allocation request so that we can allocate the memory for the new object on our own GC-managed heap?

The reason for the argument is to tell that we want it on our own heap. The clearest way to do that would be to name the function to state that we want it this way. The use of an argument instead is an alternative that’s used because it’s a constructor and we don’t have the option of renaming it.
Comment 19 Darin Adler 2011-07-14 20:21:12 PDT
Comment on attachment 100914 [details]
Patch

Windows build is failing:


2>   Creating library C:\cygwin\home\buildbot\WebKitBuild\Debug\lib\JavaScriptCore.lib and object C:\cygwin\home\buildbot\WebKitBuild\Debug\lib\JavaScriptCore.exp
2>JavaScriptCore.exp : error LNK2001: unresolved external symbol "public: __thiscall JSC::DateInstance::DateInstance(class JSC::ExecState *,class JSC::Structure *,double)" (??0DateInstance@JSC@@QAE@PAVExecState@1@PAVStructure@1@N@Z)
2>JavaScriptCore.exp : error LNK2001: unresolved external symbol "public: __thiscall JSC::JSArray::JSArray(class JSC::JSGlobalData &,class JSC::Structure *)" (??0JSArray@JSC@@QAE@AAVJSGlobalData@1@PAVStructure@1@@Z)
2>JavaScriptCore.exp : error LNK2001: unresolved external symbol "public: __thiscall JSC::JSArray::JSArray(class JSC::JSGlobalData &,class JSC::Structure *,class JSC::ArgList const &)" (??0JSArray@JSC@@QAE@AAVJSGlobalData@1@PAVStructure@1@ABVArgList@1@@Z)
2>JavaScriptCore.exp : error LNK2001: unresolved external symbol "public: __thiscall JSC::JSFunction::JSFunction(class JSC::ExecState *,class JSC::JSGlobalObject *,class JSC::Structure *,int,class JSC::Identifier const &,__int64 (__fastcall*)(class JSC::ExecState *))" (??0JSFunction@JSC@@QAE@PAVExecState@1@PAVJSGlobalObject@1@PAVStructure@1@HABVIdentifier@1@P6I_J0@Z@Z)
2>JavaScriptCore.exp : error LNK2001: unresolved external symbol "public: __thiscall JSC::RegExpObject::RegExpObject(class JSC::JSGlobalObject *,class JSC::Structure *,class JSC::RegExp *)" (??0RegExpObject@JSC@@QAE@PAVJSGlobalObject@1@PAVStructure@1@PAVRegExp@1@@Z)
2>JavaScriptCore.exp : error LNK2001: unresolved external symbol "public: __thiscall JSC::StringObject::StringObject(class JSC::ExecState *,class JSC::Structure *,class JSC::UString const &)" (??0StringObject@JSC@@QAE@PAVExecState@1@PAVStructure@1@ABVUString@1@@Z)
2>JavaScriptCore.exp : error LNK2001: unresolved external symbol "public: static void * __cdecl JSC::JSGlobalObject::operator new(unsigned int,class JSC::JSGlobalData *)" (??2JSGlobalObject@JSC@@SAPAXIPAVJSGlobalData@1@@Z)
2>JavaScriptCore.exp : error LNK2001: unresolved external symbol "public: static class JSC::RegExp * __cdecl JSC::RegExp::create(class JSC::JSGlobalData *,class JSC::UString const &,enum JSC::RegExpFlags)" (?create@RegExp@JSC@@SAPAV12@PAVJSGlobalData@2@ABVUString@2@W4RegExpFlags@2@@Z)
Comment 20 Darin Adler 2011-07-14 20:21:44 PDT
Comment on attachment 100914 [details]
Patch

You’ll need to update the Windows export file to fix the Windows build.
Comment 21 Mark Hahnenberg 2011-07-15 12:37:16 PDT
Created attachment 101025 [details]
Patch
Comment 22 Mark Hahnenberg 2011-07-15 12:38:38 PDT
Ignore the last patch, review is unnecessary.  There's more link errors on Windows.  I'm just using the build bots to give me copy & paste-able text.  The Windows try bot is rather painful to use for this purpose.
Comment 23 Mark Hahnenberg 2011-07-15 12:53:46 PDT
(In reply to comment #18)
> (In reply to comment #14)
> > I thought the main reason for the additional argument to operator new was to intercept the allocation request so that we can allocate the memory for the new object on our own GC-managed heap?
> 
> The reason for the argument is to tell that we want it on our own heap. The clearest way to do that would be to name the function to state that we want it this way. The use of an argument instead is an alternative that’s used because it’s a constructor and we don’t have the option of renaming it.

So I should rename all of the create functions to createInGCHeap (or something similar) or individually name each create function (e.g. JSString::createFromUString(...) vs. JSString::createFromRope(...))?
Comment 24 Mark Hahnenberg 2011-07-15 13:17:55 PDT
Created attachment 101031 [details]
Patch
Comment 25 Mark Hahnenberg 2011-07-15 13:18:53 PDT
Again, ignore the patch, still testing builds until I get my Windows VM setup :-)
Comment 26 Mark Hahnenberg 2011-07-18 09:04:12 PDT
Created attachment 101166 [details]
Patch
Comment 27 WebKit Review Bot 2011-07-18 10:29:14 PDT
Comment on attachment 101166 [details]
Patch

Rejecting attachment 101166 [details] from commit-queue.

Failed to run "['./Tools/Scripts/webkit-patch', '--status-host=queues.webkit.org', '--bot-id=ec2-cq-01', '--port..." exit_code: 1

Last 500 characters of output:
g does not appear to be a valid reviewer according to committers.py.
ERROR: /mnt/git/webkit-commit-queue/Source/JavaScriptCore/ChangeLog neither lists a valid reviewer nor contains the string "Unreviewed" or "Rubber stamp" (case insensitive).
Updating OpenSource
Current branch master is up to date.
Updating chromium port dependencies using gclient...

________ running '/usr/bin/python gyp_webkit' in '/mnt/git/webkit-commit-queue/Source/WebKit/chromium'
Updating webkit projects from gyp files...

Full output: http://queues.webkit.org/results/9114381
Comment 28 Oliver Hunt 2011-07-18 10:47:18 PDT
Landing manually
Comment 29 Oliver Hunt 2011-07-18 10:47:42 PDT
Committed r91194