Skip to content

Commit

Permalink
Changing JsCreateString to create Utf8Strings directly
Browse files Browse the repository at this point in the history
Also refactoring JSRT script handling behavior to detect Utf8Strings and pass
them through without conversion to functions which can already deal with utf8 sources.

Ensuring that OOM handling is present when calling GetSz which may allocate
  • Loading branch information
MSLaguana committed Jul 26, 2018
1 parent 191fd92 commit 7715a6a
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 68 deletions.
142 changes: 75 additions & 67 deletions lib/Jsrt/Jsrt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3729,26 +3729,40 @@ JsErrorCode GetScriptBufferDetails(
}
const bool isUtf8 = !isString && !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded);

*script = isExternalArray ?
((Js::ExternalArrayBuffer*)(scriptVal))->GetBuffer() :
(const byte*)((Js::JavascriptString*)(scriptVal))->GetSz();
*cb = isExternalArray ?
((Js::ExternalArrayBuffer*)(scriptVal))->GetByteLength() :
((Js::JavascriptString*)(scriptVal))->GetSizeInBytes();

if (isExternalArray && isUtf8)
{
*scriptFlag = (LoadScriptFlag)(LoadScriptFlag_ExternalArrayBuffer | LoadScriptFlag_Utf8Source);
}
else if (isUtf8)
if (isExternalArray)
{
*scriptFlag = (LoadScriptFlag)(LoadScriptFlag_Utf8Source);
Js::ExternalArrayBuffer* scriptBuffer = (Js::ExternalArrayBuffer*)(scriptVal);
*script = scriptBuffer->GetBuffer();
*cb = scriptBuffer->GetByteLength();
if (isUtf8)
{
*scriptFlag = (LoadScriptFlag)(LoadScriptFlag_ExternalArrayBuffer | LoadScriptFlag_Utf8Source);
}
else
{
*scriptFlag = (LoadScriptFlag)(LoadScriptFlag_ExternalArrayBuffer);
}
}
else
{
*scriptFlag = LoadScriptFlag_None;
Js::JavascriptString* scriptString = (Js::JavascriptString*)(scriptVal);
if (Js::Utf8String::Is(scriptString))
{
Js::Utf8String * utf8String = Js::Utf8String::From(scriptString);
*script = (const byte*)utf8String->Utf8Buffer();
*cb = utf8String->Utf8Length();
*scriptFlag = (LoadScriptFlag)(LoadScriptFlag_Utf8Source);
}
else
{
return ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
*script = (const byte*)scriptString->GetSz();
*cb = scriptString->GetSizeInBytes();
*scriptFlag = LoadScriptFlag_None;
return JsNoError;
});
}
}

return JsNoError;
}

Expand Down Expand Up @@ -4781,9 +4795,17 @@ CHAKRA_API JsCreateString(

return ContextAPINoScriptWrapper([&](Js::ScriptContext *scriptContext, TTDRecorder& _actionEntryPopper) -> JsErrorCode {

Js::JavascriptString *stringValue = Js::LiteralStringWithPropertyStringPtr::
NewFromCString(content, (CharCount)length, scriptContext->GetLibrary());
char * recyclerBuffer = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char, length);
if (recyclerBuffer == nullptr)
{
Js::JavascriptError::ThrowOutOfMemoryError(scriptContext);
}

memcpy_s(recyclerBuffer, length, content, length);

Js::JavascriptString *stringValue = RecyclerNew(scriptContext->GetRecycler(), Js::Utf8String, recyclerBuffer, length, scriptContext->GetLibrary()->GetStringTypeStatic());

// TODO: With TTD enabled we immediately flatten these strings to utf16. Perhaps we should handle this differently.
PERFORM_JSRT_TTD_RECORD_ACTION(scriptContext, RecordJsRTCreateString, stringValue->GetSz(), stringValue->GetLength());

*value = stringValue;
Expand Down Expand Up @@ -4934,44 +4956,20 @@ _ALWAYSINLINE JsErrorCode CompileRun(
VALIDATE_JSREF(scriptVal);
PARAM_NOT_NULL(sourceUrl);

bool isExternalArray = Js::ExternalArrayBuffer::Is(scriptVal),
isString = false;
bool isUtf8 = !(parseAttributes & JsParseScriptAttributeArrayBufferIsUtf16Encoded);

LoadScriptFlag scriptFlag = LoadScriptFlag_None;
const byte* script;
size_t cb;
const WCHAR *url;

if (isExternalArray)
{
script = ((Js::ExternalArrayBuffer*)(scriptVal))->GetBuffer();

cb = ((Js::ExternalArrayBuffer*)(scriptVal))->GetByteLength();
JsErrorCode error = GetScriptBufferDetails(scriptVal, parseAttributes, &scriptFlag, &cb, &script);

scriptFlag = (LoadScriptFlag)(isUtf8 ?
LoadScriptFlag_ExternalArrayBuffer | LoadScriptFlag_Utf8Source :
LoadScriptFlag_ExternalArrayBuffer);
}
else
if (error != JsNoError)
{
isString = Js::JavascriptString::Is(scriptVal);
if (!isString)
{
return JsErrorInvalidArgument;
}
return error;
}

JsErrorCode error = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
if (isString)
{
Js::JavascriptString* jsString = Js::JavascriptString::FromVar(scriptVal);
script = (const byte*)jsString->GetSz();

// JavascriptString is 2 bytes (WCHAR/char16)
cb = jsString->GetLength() * sizeof(WCHAR);
}
const WCHAR *url;

error = GlobalAPIWrapper_NoRecord([&]() -> JsErrorCode {
if (!Js::JavascriptString::Is(sourceUrl))
{
return JsErrorInvalidArgument;
Expand Down Expand Up @@ -5165,14 +5163,23 @@ CHAKRA_API JsRunSerialized(
{
PARAM_NOT_NULL(bufferVal);
const WCHAR *url;
JsErrorCode errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {

if (sourceUrl && Js::JavascriptString::Is(sourceUrl))
{
url = ((Js::JavascriptString*)(sourceUrl))->GetSz();
}
else
if (sourceUrl && Js::JavascriptString::Is(sourceUrl))
{
url = ((Js::JavascriptString*)(sourceUrl))->GetSz();
}
else
{
return JsErrorInvalidArgument;
}

return JsNoError;
});

if (errorCode != JsNoError)
{
return JsErrorInvalidArgument;
return errorCode;
}

// JsParseSerialized only accepts ArrayBuffer (incl. ExternalArrayBuffer)
Expand Down Expand Up @@ -5689,12 +5696,23 @@ CHAKRA_API JsRunScriptWithParserState(
const WCHAR *url = nullptr;
uint sourceIndex = 0;

JsErrorCode errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {
const byte* bytes;
size_t cb;
LoadScriptFlag loadScriptFlag;
const byte* bytes;
size_t cb;
LoadScriptFlag loadScriptFlag;

JsErrorCode errorCode = GetScriptBufferDetails(script, parseAttributes, &loadScriptFlag, &cb, &bytes);
JsErrorCode errorCode = GetScriptBufferDetails(script, parseAttributes, &loadScriptFlag, &cb, &bytes);

if (errorCode != JsNoError)
{
return errorCode;
}

if (!Js::ExternalArrayBuffer::Is(parserState))
{
return JsErrorInvalidArgument;
}

errorCode = ContextAPINoScriptWrapper_NoRecord([&](Js::ScriptContext *scriptContext) -> JsErrorCode {

if (sourceUrl && Js::JavascriptString::Is(sourceUrl))
{
Expand All @@ -5705,11 +5723,6 @@ CHAKRA_API JsRunScriptWithParserState(
return JsErrorInvalidArgument;
}

if (errorCode != JsNoError)
{
return errorCode;
}

SourceContextInfo* sourceContextInfo = scriptContext->GetSourceContextInfo(sourceContext, nullptr);

if (sourceContextInfo == nullptr)
Expand Down Expand Up @@ -5761,11 +5774,6 @@ CHAKRA_API JsRunScriptWithParserState(
return errorCode;
}

if (!Js::ExternalArrayBuffer::Is(parserState))
{
return JsErrorInvalidArgument;
}

Js::ArrayBuffer* arrayBuffer = Js::ArrayBuffer::FromVar(parserState);
byte* buffer = arrayBuffer->GetBuffer();
JsSerializedLoadScriptCallback dummy = DummyScriptLoadSourceCallbackForRunScriptWithParserState;
Expand Down
14 changes: 13 additions & 1 deletion lib/Runtime/Library/Utf8String.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ namespace Js
// Fetching the char* from the Field(char*) first so we can then cast to LPCUTF8
const char* bufferStart = this->utf8String->buffer;
LPCUTF8 start = reinterpret_cast<LPCUTF8>(bufferStart);
utf8::DecodeUnitsIntoAndNullTerminateNoAdvance(buffer, start, start + this->utf8String->length);
size_t decodeLength = utf8::DecodeUnitsIntoAndNullTerminateNoAdvance(buffer, start, start + this->utf8String->length);

Assert(decodeLength == this->GetLength());

buffer[this->GetLength()] = 0;

Expand All @@ -114,6 +116,16 @@ namespace Js
return VirtualTableInfo<Js::Utf8String>::HasVirtualTable(obj);
}

static Utf8String* From(RecyclableObject* obj)
{
if (Utf8String::Is(obj))
{
return static_cast<Utf8String*>(obj);
}

return nullptr;
}

template <typename StringType>
static Utf8String * ConvertString(StringType * originalString, _In_reads_(utf8Length) char* buffer, size_t utf8Length)
{
Expand Down

0 comments on commit 7715a6a

Please sign in to comment.