JavascriptExceptionMetadata.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. #include "RuntimeLibraryPch.h"
  7. #include "JavascriptExceptionMetadata.h"
  8. namespace Js {
  9. SimplePropertyDescriptor const ExceptionMetadataPropertyDescriptors[6] =
  10. {
  11. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::exception), PropertyWritable),
  12. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::source), PropertyWritable),
  13. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::line), PropertyWritable),
  14. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::column), PropertyWritable),
  15. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::length), PropertyWritable),
  16. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::url), PropertyWritable)
  17. };
  18. SimpleTypeHandler<6> JavascriptExceptionMetadata::ExceptionMetadataTypeHandler(NO_WRITE_BARRIER_TAG(ExceptionMetadataPropertyDescriptors));
  19. Var JavascriptExceptionMetadata::CreateMetadataVar(ScriptContext * scriptContext) {
  20. DynamicType* exceptionMetadataType = DynamicType::New(scriptContext, TypeIds_Object,
  21. scriptContext->GetLibrary()->GetNull(), nullptr, &JavascriptExceptionMetadata::ExceptionMetadataTypeHandler, true, true);
  22. return DynamicObject::New(scriptContext->GetRecycler(), exceptionMetadataType);
  23. }
  24. void JavascriptExceptionMetadata::PopulateMetadataFromCompileException(Var metadata, Var exception, ScriptContext * scriptContext) {
  25. Js::Var var;
  26. var = Js::JavascriptOperators::ToNumber(
  27. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::line, scriptContext),
  28. scriptContext);
  29. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::line, var, scriptContext);
  30. var = Js::JavascriptOperators::ToNumber(
  31. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::column, scriptContext),
  32. scriptContext);
  33. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::column, var, scriptContext);
  34. var = Js::JavascriptOperators::ToNumber(
  35. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::length, scriptContext),
  36. scriptContext);
  37. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::length, var, scriptContext);
  38. var = Js::JavascriptConversion::ToString(
  39. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::source, scriptContext),
  40. scriptContext);
  41. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::source, var, scriptContext);
  42. var = Js::JavascriptConversion::ToString(
  43. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::url, scriptContext),
  44. scriptContext);
  45. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::url, var, scriptContext);
  46. }
  47. bool JavascriptExceptionMetadata::PopulateMetadataFromException(Var metadata, JavascriptExceptionObject * recordedException, ScriptContext * scriptContext) {
  48. uint32 offset = recordedException->GetByteCodeOffset();
  49. FunctionBody * functionBody = recordedException->GetFunctionBody();
  50. ULONG line;
  51. LONG column;
  52. if (functionBody->GetUtf8SourceInfo()->GetIsLibraryCode() ||
  53. !functionBody->GetLineCharOffset(offset, &line, &column)) {
  54. line = 0;
  55. column = 0;
  56. }
  57. Js::Utf8SourceInfo* sourceInfo = functionBody->GetUtf8SourceInfo();
  58. sourceInfo->EnsureLineOffsetCache();
  59. LineOffsetCache *cache = sourceInfo->GetLineOffsetCache();
  60. if (line >= cache->GetLineCount())
  61. {
  62. return false;
  63. }
  64. uint32 nextLine;
  65. if (UInt32Math::Add(line, 1, &nextLine))
  66. {
  67. // Overflowed
  68. return false;
  69. }
  70. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::line,
  71. Js::JavascriptNumber::New(line, scriptContext), scriptContext);
  72. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::column,
  73. Js::JavascriptNumber::New(column, scriptContext), scriptContext);
  74. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::length,
  75. Js::JavascriptNumber::New(0, scriptContext), scriptContext);
  76. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::url,
  77. Js::JavascriptString::NewCopySz(functionBody->GetSourceName(), scriptContext), scriptContext);
  78. LPCUTF8 functionSource = sourceInfo->GetSource(_u("Jsrt::JsExperimentalGetAndClearExceptionWithMetadata"));
  79. charcount_t startByteOffset = 0;
  80. charcount_t endByteOffset = 0;
  81. charcount_t startCharOffset = 0;
  82. charcount_t endCharOffset = 0;
  83. startCharOffset = cache->GetCharacterOffsetForLine(line, &startByteOffset);
  84. if (nextLine >= cache->GetLineCount())
  85. {
  86. endByteOffset = functionBody->LengthInBytes() + functionBody->StartInDocument();
  87. endCharOffset = functionBody->LengthInChars() + functionBody->StartOffset();
  88. }
  89. else
  90. {
  91. endCharOffset = cache->GetCharacterOffsetForLine(nextLine, &endByteOffset);
  92. // The offsets above point to the start of the following line,
  93. // while we need to find the end of the current line.
  94. // To do so, just step back over the preceeding newline character(s)
  95. if (functionSource[endByteOffset - 1] == _u('\n'))
  96. {
  97. endCharOffset--;
  98. endByteOffset--;
  99. // This may have been \r\n
  100. if (endByteOffset > 0 && functionSource[endByteOffset - 1] == _u('\r'))
  101. {
  102. endCharOffset--;
  103. endByteOffset--;
  104. }
  105. }
  106. else
  107. {
  108. utf8::DecodeOptions options = utf8::doAllowThreeByteSurrogates;
  109. LPCUTF8 potentialNewlineStart = functionSource + endByteOffset - 3;
  110. char16 decodedCharacter = utf8::Decode(potentialNewlineStart, functionSource + endByteOffset, options);
  111. if (decodedCharacter == 0x2028 || decodedCharacter == 0x2029)
  112. {
  113. endCharOffset--;
  114. endByteOffset -= 3;
  115. }
  116. else if (functionSource[endByteOffset - 1] == _u('\r'))
  117. {
  118. endCharOffset--;
  119. endByteOffset--;
  120. }
  121. else
  122. {
  123. AssertMsg(FALSE, "Line ending logic out of sync between Js::JavascriptExceptionMetadata and Js::LineOffsetCache::GetCharacterOffsetForLine");
  124. return false;
  125. }
  126. }
  127. }
  128. LPCUTF8 functionStart = functionSource + startByteOffset;
  129. Js::BufferStringBuilder builder(endCharOffset - startCharOffset, scriptContext);
  130. utf8::DecodeOptions options = sourceInfo->IsCesu8() ? utf8::doAllowThreeByteSurrogates : utf8::doDefault;
  131. utf8::DecodeUnitsInto(builder.DangerousGetWritableBuffer(), functionStart, functionSource + endByteOffset, options);
  132. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::source,
  133. builder.ToString(), scriptContext);
  134. return true;
  135. }
  136. }