JSC Opaque-type에 대하여

Dev 2009. 8. 25. 11:30
웹킷 JavaScriptCore 소스를 보면 JSValue 타입이 있고, JSValueRef 타입이 있다. 그리고 그 둘 사이에 형변환을 처리하는 toRef() 함수와 toJS() 함수가 제공된다. JSC에는 JSxxxxRef 스타일의 타입들이 몇개 더 있는데, 다음과 같다. JSValueRef, JSObjectRef, JSContextRef, JSGlobalContextRef, JSStringRef, JSClassRef.

웹킷 소스코드에서 JSValueRef와 JSObjectRef의 선언을 보면 다음과 같다.
typedef const struct OpaqueJSValue* JSValueRef;
typedef struct OpaqueJSValue* JSObjectRef;

그런데 소스코드 어디에도 struct OpaqueJSValue에 대한 정의는 없다.
OpaqueJSValue는 이름이 의미하듯 JSValue를 위한 모호한(Opaque) 타입이다.
위 JSValueRef와 JSObjectRef 선언 구문이 의미하는 바는 "JSValueRef is not JSObjectRef", 그리고 "JSObjectRef is JSValueRef" 이다. 즉, JSValueRef를 인자로 쓰는 모든 함수에는 JSObjectRef 변수들도 전달할 수 있지만, JSObjectRef를 인자로 쓰는 함수에는 JSValueRef 변수를 전달할 수 없다는 의미다.

JSC에는 JSValue* 타입과 JSObject* 타입을 인자로 쓰는 구현부와 JSValueRef 타입과 JSObjectRef를 인자로 쓰는 구현부가 달리 존재한다. 논리적인 이유에 의해 구분된 것이 아니고, 역사적인 이유에 의해 구분된 것이라 추측한다. 명쾌한 답은 찾지 못했다. 누군가 댓글이나 피드백으로 일러주면 고맙겠다.



(끝)
Posted by ingeeC
,

WebKit 메모리 릭에 대해

Dev 2009. 8. 13. 12:41

PC에서 Visual Studio 디버그 모드로 웹킷을 실행시켰다 종료시키면 기절할 정도로 많은 메모리 leak이 보고된다.
처음엔 명성 높은 웹킷 소스에서 그토록 많은 leak이 쏟아진다는 것이 믿어지지 않았다. 처음 프로그래밍을 배울 때 메모리 leak은 하나도 남김 없이 제거해야 할 절대 악으로 배웠다. 그래서 메모리 leak에 대해서는 강박관념에 가까운 혐오를 갖고 있다. 그런데 결론을 말하자면 WebKit 소스가 종료시 내는 leak은 의도적인 것이라고 한다. 종료 시점에 사용하던 메모리를 해지하는 절차를 생략함으로써 (해당 절차를 OS에게 맡김으로써) 처리 속도를 높이는 것이 설계 취지란다. 딱히 반박할 수도 없고... 경우에 따라서는 합리적인 판단일 수도 있겠다 하고 수긍하고 있다. 관련된 뉴스 그룹 기사는 다음과 같다.

http://www.nabble.com/freeing-static-variables-to24714380.html


뉴스 그룹 기사를 요약하면 다음과 같다.

static global 변수의 leak은 의도적이다 (by "Adam Treat-2")
* 웹킷은 static global 변수의 해지(clean up)에 관여하지 않는다. 해당 작업은 OS에게 맡긴다.

의도적인 leak에 대한 태클 (by "Zoltan" and "Antonio Gomes")
* 보고되는 leak이 너무 많아, 실제 주의해야 할 개발자의 실수에 의한 leak을 알아내기 어렵다.
* WebKit을 어플리케이션 형태가 아닌 다른 어플리케이션의 플러그인 형태로 사용할 경우, WebKit 플러그인을 내릴 때 leak이 발생하면 문제가 된다.


참고를 위해 뉴스 기사 원문을 아래와 같이 첨부한다.

_______________________________________________
freeing static variables 
by Zoltan Herczeg Jul 29, 2009; 05:05pm

Hi all,

Valgrind reports a lot of memory leaks when QtLauncher quits, because many
static local variables are not freed. I did a little research and realized
there is no consistent way to define static variables in webkit:

WebCore/css/CSSSelector.cpp: CSSSelector::extractPseudoType()
   using a DEFINE_STATIC_LOCAL() macro

WebCore/bindings/js/JSDOMWindowBase.cpp:
JSDOMWindowBase::commonJSGlobalData()
   static JSGlobalData* globalData;

WebCore/platform/qt/CursorQt.cpp:
   Cursors* Cursors::s_self = 0; (no static keyword)

I belive it would be a good thing to define a template for static
variables, which can (optionally) free static variables (enabled in debug
mode, but sometimes it would be good to enable it in release mode as well)

And I am wondering whether it would be worth to free (some) static
variables if they are used in a given time period. This may help to reduce
the memory consumption in the long run. This would be an optional feature,
an extra flag (or timeout value) for the template, which can be enabled or
disabled at compile time. If disabled, the value of this flag is not used
at all.

Regards
Zoltan


_______________________________________________
Re: freeing static variables 
by Zoltan Herczeg Jul 30, 2009; 03:55pm

Hi,

any thoughts on this? I hope my qestion was clear :) I would like to pack
the static declarations into wrapper classes, so we can add platform
and/or compilation mode (debug/release) dependent functionality to all
static variables (i.e: freeing them on exit).

Zoltan


_______________________________________________
Re: freeing static variables 
by tonikitoo (Antonio Gomes) Jul 30, 2009; 11:06pm

Zoltan, I think it would be a great add from a embedder-dev point of view.

Particularly, such leaks have been faced here in a soon past, when we
were loading a webkit browser as a plugin, and not as an application
by itself. So, we the webkit plugin was unloaded, it used to left
behind lots of leaks affecting the (main)  loader application, and as
we you might imagine many of this leaks were from global vars
(including in dependency libs , e.g. fontconfig =/)

--Antonio Gomes


_______________________________________________
Re: freeing static variables 
by Adam Treat-2 Jul 30, 2009; 11:26pm

On Thursday 30 July 2009 02:55:18 am Zoltan Herczeg wrote:
> Hi,
>
> any thoughts on this? I hope my qestion was clear :) I would like to pack
> the static declarations into wrapper classes, so we can add platform
> and/or compilation mode (debug/release) dependent functionality to all
> static variables (i.e: freeing them on exit).
>
> Zoltan

I've tried this before and it didn't work out so well.  The order in which you
free them becomes very important and error prone.  

And, of course, whatever solution you make has to be optional and easy to
maintain as the default policy in WebKit is to not care - by design - about
cleaning up after static globals on exit as that is left to the OS.

Another strategy for the embedded case where you want to free everything on
exit is to create a custom memory handler that will do this for you.

Cheers,
Adam


_______________________________________________
Re: freeing static variables 
by Zoltan Herczeg Aug 05, 2009; 12:10am

Hi Adam,

thank you for your suggestions. I have something similar in my mind.

I have opened a bugzilla entry and submited an early patch draft about my
concept:
https://bugs.webkit.org/show_bug.cgi?id=27980

The patch frees memory objects in a reversed creation order, and seemed
working well with QtLauncher (although only a subset of static variables
are freed right now). Do you know about special cases when this approach
is not enough?

Actually it is hard to find real memory leaks in the output of valgrind
because many of them are related to static variables. I hope this feature
will help to the leak hunters in the future.

Cheers,
Zoltan

 (끝)

Posted by ingeeC
,
JavaScriptCore를 변형해 쓰기 위해 분석하고 있다. 다음은 JSC에 관한 간단한 클래스 다이어그램이다. 웹킷을 사용하는 엔지니어들에게 도움이 되면 좋겠다.


다음은 JSC관련 객체들의 라이프사이클에 관한 메모이다.
  • WebCore::JSDOMWindow 인스턴스는 (다시 말해 JSC::JSGlobalObject 인스턴스는) 페이지를 새로 로드할 때마다 새로 만든다.
  • JSC::GlobalData 인스턴스는 application과 life-cycle을 같이 한다 (즉, 한번 만들면 어플리케이션을 종료시킬 때까지 같은 놈을 사용한다).

 (끝)

Posted by ingeeC
,
WebKit을 갖고 작업할 때, 꼭 풀어야 하는 문제중 하나가 커스텀 JS Object를 추가하는 일이다. 관련 자료를 아래와 같이 요약한다.


JS Object 확장 방식

 

 

관련 뉴스그룹 기사

http://www.nabble.com/Extending-webkit-javascript-td21517784.html#a21536928

l  frameLoadDelegate2::didClearWindowObject() custom JS object JS context에 등록하는 최적의 자리다. 해당 함수는 현재 web 문서의 스크립트가 실행되기 직전에 호출된다.

 

 

커스텀 JS Object 추가 절차 요약

l  $/JavaScriptCore/API/tests/testapi.c 파일과
$/JavaScriptCore/API/JSObjectRef.h
파일에 유용한 정보가 있다.

l  JSClassDefinition 구조체의 staticValues 필드와 staticFunctions 필드를 이용하는 것이 커스텀 속성을 가진 커스텀 JS Object를 정의하는 가장 간단한 방법이다.

l  커스텀 속성을 가진 커스텀 객체를 정의하려면

n  커스텀 속성을 위한 get 함수와 set 함수를 준비한다 (ingeeGetPropFunc 함수)

n  커스텀 속성 테이블 JSStaticValue 배열을 준비한다 (ingeePorpArr 배열)

n  커스텀 객체를 위한 JSClassDefinition을 정의한다 (ingeeClassDef 변수)

n  적절한 시점에 JSClassCreate() 함수를 호출하여 타입을 등록한다

n  적절한 시점에 JSObjectMake() 함수를 호출하여 객체를 생성한다

 

static JSValueRef ingeeGetPropFunc

( JSContextRef ctx

, JSObjectRef object

, JSStringRef propertyName

, JSValueRef* exception

)

{

return JSValueMakeUndefined(ctx); //undefined-value 리턴 (단지 샘플...)

}

 

static JSStaticValue ingeePorpArr[]=

{ { "prop1", ingeeGetPropFunc, 0, kJSPropertyAttributeNone }

, { "prop2", ingeeGetPropFunc, 0, kJSPropertyAttributeNone }

, { "prop3", ingeeGetPropFunc, 0, kJSPropertyAttributeNone }

, { 0, 0, 0, 0 }

};

 

static JSClassDefinition ingeeClassDef=

{ 0 //ver

, kJSClassAttributeNone //attributes

, "PersonObject" //className

, 0 //parentClass

, ingeePorpArr //staticValues

, 0 //staticFunctions

, 0 //initialize

, 0 //finalize

, 0 //hasProperty

, 0 //getProperty

, 0 //setProperty

, 0 //deleteProperty

, 0 //getPropertyNames

, 0 //callAsFunction

, 0 //callAsConstructor

, 0 //hasInstance

, 0 //convertToType

};

 

JSValue* SomeFuncToCreateJSObject( ExecState* exec )

{

static JSClassRef ingeeClass;

if (!ingeeClass)

ingeeClass= JSClassCreate(&ingeeClassDef);

 

JSContextRef ctx= JSC::toRef(exec);

JSObjectRef objRef= JSObjectMake(ctx, ingeeClass, (void*)0/*someData*/ );

return JSC::toJS(objRef);

}

 

 

(끝)

Posted by ingeeC
,
용역 사업은 돈을 주고 일을 시키는 측과 돈을 받고 일을 하는 측 사이에 간격이 있을 수 밖에 없다. 문제는 두 당사자가 일을 바라 보는 관점이 오로지 경제 논리 뿐인 경우다. 일을 시키는 측은 가능한 돈을 적게 주고 많은 일을 시키는 것을 최고선으로 여기고, 일을 하는 측은 정해진 계약 금액을 받으면서 가능한 적게 일하는 것을 최고선으로 삼는다. 그럴 경우 양질의 결과물은 누가 만들 수 있을까?

용역 사업을 통해 양질의 결과물이 나올 수 없는 이유가 하나 더 있다. 용역 사업이 시작될 때, 용역을 발주하는 "갑"이 자기가 바라는 결과물의 모습을 모른다는 것이다. 일을 시키는 "갑"과 일을 진행하는 "을"이 서로 다른 이미지를 머릿속에 넣고 일을 진행한다. 대개 과제 마감이 가까와서야 갑은 갑대로, 을은 을대로 결과물의 모습을 어렴풋이 그리기 시작한다. 그럴 경우 양질의 결과물은 언제 나올 수 있을까?

S/W 개발 방법론이란 분야는 10 년 넘게 결과물이 쌓여온 완성된 학문이다. 갑이든 을이든 RUP, XP, SCRUM 등등의 방법론을 한번쯤 공부하고 업무에 임하면 어떨까 생각해본다. 한국의 S/W 산업도 10 년 넘게 무르익은 산업인데 왜 맨날 이모양인가? 가끔 S/W 업계에 종사하는 사람들이 무식하다는 생각이 들 때가 있다. 지식이 없어 무식하다고 하는게 아니다. 자기가 모른다는 사실을 모르기에 무식하다고 하는 것이다. 모른다는 사실을 깨달아야 공부할 것 아닌가?

어째... 단상 시리즈를 이어나가면 내게 불이익이 닥칠 것 같은 소심한 걱정이 스친다. (3)을 이을지 말지 고민해봐야겠다.
Posted by ingeeC
,