OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/inspector/v8-debugger-script.h" | 5 #include "src/inspector/v8-debugger-script.h" |
6 | 6 |
7 #include "src/inspector/string-util.h" | 7 #include "src/inspector/string-util.h" |
8 | 8 |
9 namespace v8_inspector { | 9 namespace v8_inspector { |
10 | 10 |
11 static const char hexDigits[17] = "0123456789ABCDEF"; | 11 namespace { |
12 | 12 |
13 static void appendUnsignedAsHex(uint64_t number, String16Builder* destination) { | 13 const char hexDigits[17] = "0123456789ABCDEF"; |
| 14 |
| 15 void appendUnsignedAsHex(uint64_t number, String16Builder* destination) { |
14 for (size_t i = 0; i < 8; ++i) { | 16 for (size_t i = 0; i < 8; ++i) { |
15 UChar c = hexDigits[number & 0xF]; | 17 UChar c = hexDigits[number & 0xF]; |
16 destination->append(c); | 18 destination->append(c); |
17 number >>= 4; | 19 number >>= 4; |
18 } | 20 } |
19 } | 21 } |
20 | 22 |
21 // Hash algorithm for substrings is described in "Über die Komplexität der | 23 // Hash algorithm for substrings is described in "Über die Komplexität der |
22 // Multiplikation in | 24 // Multiplikation in |
23 // eingeschränkten Branchingprogrammmodellen" by Woelfe. | 25 // eingeschränkten Branchingprogrammmodellen" by Woelfe. |
24 // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECT
ION00832000000000000000 | 26 // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECT
ION00832000000000000000 |
25 static String16 calculateHash(const String16& str) { | 27 String16 calculateHash(const String16& str) { |
26 static uint64_t prime[] = {0x3FB75161, 0xAB1F4E4F, 0x82675BC5, 0xCD924D35, | 28 static uint64_t prime[] = {0x3FB75161, 0xAB1F4E4F, 0x82675BC5, 0xCD924D35, |
27 0x81ABE279}; | 29 0x81ABE279}; |
28 static uint64_t random[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, | 30 static uint64_t random[] = {0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, |
29 0xC3D2E1F0}; | 31 0xC3D2E1F0}; |
30 static uint32_t randomOdd[] = {0xB4663807, 0xCC322BF5, 0xD4F91BBD, 0xA7BEA11D, | 32 static uint32_t randomOdd[] = {0xB4663807, 0xCC322BF5, 0xD4F91BBD, 0xA7BEA11D, |
31 0x8F462907}; | 33 0x8F462907}; |
32 | 34 |
33 uint64_t hashes[] = {0, 0, 0, 0, 0}; | 35 uint64_t hashes[] = {0, 0, 0, 0, 0}; |
34 uint64_t zi[] = {1, 1, 1, 1, 1}; | 36 uint64_t zi[] = {1, 1, 1, 1, 1}; |
35 | 37 |
(...skipping 23 matching lines...) Expand all Loading... |
59 } | 61 } |
60 | 62 |
61 for (size_t i = 0; i < hashesSize; ++i) | 63 for (size_t i = 0; i < hashesSize; ++i) |
62 hashes[i] = (hashes[i] + zi[i] * (prime[i] - 1)) % prime[i]; | 64 hashes[i] = (hashes[i] + zi[i] * (prime[i] - 1)) % prime[i]; |
63 | 65 |
64 String16Builder hash; | 66 String16Builder hash; |
65 for (size_t i = 0; i < hashesSize; ++i) appendUnsignedAsHex(hashes[i], &hash); | 67 for (size_t i = 0; i < hashesSize; ++i) appendUnsignedAsHex(hashes[i], &hash); |
66 return hash.toString(); | 68 return hash.toString(); |
67 } | 69 } |
68 | 70 |
69 V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, | 71 class ActualScript : public V8DebuggerScript { |
70 v8::Local<v8::debug::Script> script, | 72 friend class V8DebuggerScript; |
71 bool isLiveEdit) { | 73 |
72 m_isolate = script->GetIsolate(); | 74 public: |
73 m_id = String16::fromInteger(script->Id()); | 75 ActualScript(v8::Isolate* isolate, v8::Local<v8::debug::Script> script, |
74 v8::Local<v8::String> tmp; | 76 bool isLiveEdit) |
75 if (script->Name().ToLocal(&tmp)) m_url = toProtocolString(tmp); | 77 : V8DebuggerScript(isolate, String16::fromInteger(script->Id()), |
76 if (script->SourceURL().ToLocal(&tmp)) { | 78 GetNameOrSourceUrl(script)), |
77 m_sourceURL = toProtocolString(tmp); | 79 m_isLiveEdit(isLiveEdit) { |
78 if (m_url.isEmpty()) m_url = toProtocolString(tmp); | 80 v8::Local<v8::String> tmp; |
79 } | 81 if (script->SourceURL().ToLocal(&tmp)) m_sourceURL = toProtocolString(tmp); |
80 if (script->SourceMappingURL().ToLocal(&tmp)) | 82 if (script->SourceMappingURL().ToLocal(&tmp)) |
81 m_sourceMappingURL = toProtocolString(tmp); | 83 m_sourceMappingURL = toProtocolString(tmp); |
82 m_startLine = script->LineOffset(); | 84 m_startLine = script->LineOffset(); |
83 m_startColumn = script->ColumnOffset(); | 85 m_startColumn = script->ColumnOffset(); |
84 std::vector<int> lineEnds = script->LineEnds(); | 86 std::vector<int> lineEnds = script->LineEnds(); |
85 CHECK(lineEnds.size()); | 87 CHECK(lineEnds.size()); |
86 int source_length = lineEnds[lineEnds.size() - 1]; | 88 int source_length = lineEnds[lineEnds.size() - 1]; |
87 if (lineEnds.size()) { | 89 if (lineEnds.size()) { |
88 m_endLine = static_cast<int>(lineEnds.size()) + m_startLine - 1; | 90 m_endLine = static_cast<int>(lineEnds.size()) + m_startLine - 1; |
89 if (lineEnds.size() > 1) { | 91 if (lineEnds.size() > 1) { |
90 m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1; | 92 m_endColumn = source_length - lineEnds[lineEnds.size() - 2] - 1; |
| 93 } else { |
| 94 m_endColumn = source_length + m_startColumn; |
| 95 } |
91 } else { | 96 } else { |
92 m_endColumn = source_length + m_startColumn; | 97 m_endLine = m_startLine; |
| 98 m_endColumn = m_startColumn; |
93 } | 99 } |
94 } else { | 100 |
95 m_endLine = m_startLine; | 101 if (script->ContextData().ToLocal(&tmp)) { |
96 m_endColumn = m_startColumn; | 102 String16 contextData = toProtocolString(tmp); |
| 103 size_t firstComma = contextData.find(",", 0); |
| 104 size_t secondComma = firstComma != String16::kNotFound |
| 105 ? contextData.find(",", firstComma + 1) |
| 106 : String16::kNotFound; |
| 107 if (secondComma != String16::kNotFound) { |
| 108 String16 executionContextId = |
| 109 contextData.substring(firstComma + 1, secondComma - firstComma - 1); |
| 110 bool isOk = false; |
| 111 m_executionContextId = executionContextId.toInteger(&isOk); |
| 112 if (!isOk) m_executionContextId = 0; |
| 113 m_executionContextAuxData = contextData.substring(secondComma + 1); |
| 114 } |
| 115 } |
| 116 |
| 117 if (script->Source().ToLocal(&tmp)) { |
| 118 m_sourceObj.Reset(m_isolate, tmp); |
| 119 String16 source = toProtocolString(tmp); |
| 120 // V8 will not count last line if script source ends with \n. |
| 121 if (source.length() > 1 && source[source.length() - 1] == '\n') { |
| 122 m_endLine++; |
| 123 m_endColumn = 0; |
| 124 } |
| 125 } |
| 126 |
| 127 m_script.Reset(m_isolate, script); |
97 } | 128 } |
98 | 129 |
99 if (script->ContextData().ToLocal(&tmp)) { | 130 bool isLiveEdit() const override { return m_isLiveEdit; } |
100 String16 contextData = toProtocolString(tmp); | 131 |
101 size_t firstComma = contextData.find(",", 0); | 132 const String16& executionContextAuxData() const override { |
102 size_t secondComma = firstComma != String16::kNotFound | 133 return m_executionContextAuxData; |
103 ? contextData.find(",", firstComma + 1) | |
104 : String16::kNotFound; | |
105 if (secondComma != String16::kNotFound) { | |
106 String16 executionContextId = | |
107 contextData.substring(firstComma + 1, secondComma - firstComma - 1); | |
108 bool isOk = false; | |
109 m_executionContextId = executionContextId.toInteger(&isOk); | |
110 if (!isOk) m_executionContextId = 0; | |
111 m_executionContextAuxData = contextData.substring(secondComma + 1); | |
112 } | |
113 } | 134 } |
114 | 135 |
115 m_isLiveEdit = isLiveEdit; | 136 const String16& sourceMappingURL() const override { |
116 | 137 return m_sourceMappingURL; |
117 if (script->Source().ToLocal(&tmp)) { | |
118 m_sourceObj.Reset(m_isolate, tmp); | |
119 String16 source = toProtocolString(tmp); | |
120 // V8 will not count last line if script source ends with \n. | |
121 if (source.length() > 1 && source[source.length() - 1] == '\n') { | |
122 m_endLine++; | |
123 m_endColumn = 0; | |
124 } | |
125 } | 138 } |
126 | 139 |
127 m_script.Reset(m_isolate, script); | 140 String16 source(v8::Isolate* isolate) const override { |
| 141 if (!m_sourceObj.IsEmpty()) |
| 142 return toProtocolString(m_sourceObj.Get(isolate)); |
| 143 return V8DebuggerScript::source(isolate); |
| 144 } |
| 145 |
| 146 void setSourceMappingURL(const String16& sourceMappingURL) override { |
| 147 m_sourceMappingURL = sourceMappingURL; |
| 148 } |
| 149 |
| 150 void setSource(v8::Local<v8::String> source) override { |
| 151 m_source = String16(); |
| 152 m_sourceObj.Reset(m_isolate, source); |
| 153 m_hash = String16(); |
| 154 } |
| 155 |
| 156 bool getPossibleBreakpoints( |
| 157 const v8::debug::Location& start, const v8::debug::Location& end, |
| 158 std::vector<v8::debug::Location>* locations) override { |
| 159 v8::HandleScope scope(m_isolate); |
| 160 v8::Local<v8::debug::Script> script = m_script.Get(m_isolate); |
| 161 return script->GetPossibleBreakpoints(start, end, locations); |
| 162 } |
| 163 |
| 164 private: |
| 165 String16 GetNameOrSourceUrl(v8::Local<v8::debug::Script> script) { |
| 166 v8::Local<v8::String> name; |
| 167 if (script->Name().ToLocal(&name) || script->SourceURL().ToLocal(&name)) |
| 168 return toProtocolString(name); |
| 169 return String16(); |
| 170 } |
| 171 |
| 172 String16 m_sourceMappingURL; |
| 173 v8::Global<v8::String> m_sourceObj; |
| 174 String16 m_executionContextAuxData; |
| 175 bool m_isLiveEdit = false; |
| 176 v8::Global<v8::debug::Script> m_script; |
| 177 }; |
| 178 |
| 179 class WasmVirtualScript : public V8DebuggerScript { |
| 180 friend class V8DebuggerScript; |
| 181 |
| 182 public: |
| 183 WasmVirtualScript(v8::Isolate* isolate, |
| 184 v8::Local<v8::debug::WasmScript> script, String16 id, |
| 185 String16 url, String16 source) |
| 186 : V8DebuggerScript(isolate, std::move(id), std::move(url)), |
| 187 m_script(isolate, script) { |
| 188 int num_lines = 0; |
| 189 int last_newline = -1; |
| 190 size_t next_newline = source.find('\n', last_newline + 1); |
| 191 while (next_newline != String16::kNotFound) { |
| 192 last_newline = static_cast<int>(next_newline); |
| 193 next_newline = source.find('\n', last_newline + 1); |
| 194 ++num_lines; |
| 195 } |
| 196 m_endLine = num_lines; |
| 197 m_endColumn = static_cast<int>(source.length()) - last_newline - 1; |
| 198 m_source = std::move(source); |
| 199 } |
| 200 |
| 201 const String16& sourceMappingURL() const override { return emptyString(); } |
| 202 const String16& executionContextAuxData() const override { |
| 203 return emptyString(); |
| 204 } |
| 205 bool isLiveEdit() const override { return false; } |
| 206 void setSourceMappingURL(const String16&) override {} |
| 207 |
| 208 bool getPossibleBreakpoints( |
| 209 const v8::debug::Location& start, const v8::debug::Location& end, |
| 210 std::vector<v8::debug::Location>* locations) override { |
| 211 // TODO(clemensh): Returning false produces the protocol error "Internal |
| 212 // error". Implement and fix expected output of |
| 213 // wasm-get-breakable-locations.js. |
| 214 return false; |
| 215 } |
| 216 |
| 217 private: |
| 218 static const String16& emptyString() { |
| 219 static const String16 singleEmptyString; |
| 220 return singleEmptyString; |
| 221 } |
| 222 |
| 223 v8::Global<v8::debug::WasmScript> m_script; |
| 224 }; |
| 225 |
| 226 } // namespace |
| 227 |
| 228 std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create( |
| 229 v8::Isolate* isolate, v8::Local<v8::debug::Script> scriptObj, |
| 230 bool isLiveEdit) { |
| 231 return std::unique_ptr<ActualScript>( |
| 232 new ActualScript(isolate, scriptObj, isLiveEdit)); |
128 } | 233 } |
129 | 234 |
130 V8DebuggerScript::V8DebuggerScript(String16 id, String16 url, String16 source) | 235 std::unique_ptr<V8DebuggerScript> V8DebuggerScript::CreateWasm( |
131 : m_id(std::move(id)), m_url(std::move(url)), m_source(std::move(source)) { | 236 v8::Isolate* isolate, v8::Local<v8::debug::WasmScript> underlyingScript, |
132 int num_lines = 0; | 237 String16 id, String16 url, String16 source) { |
133 int last_newline = -1; | 238 return std::unique_ptr<WasmVirtualScript>( |
134 size_t next_newline = m_source.find('\n', last_newline + 1); | 239 new WasmVirtualScript(isolate, underlyingScript, std::move(id), |
135 while (next_newline != String16::kNotFound) { | 240 std::move(url), std::move(source))); |
136 last_newline = static_cast<int>(next_newline); | |
137 next_newline = m_source.find('\n', last_newline + 1); | |
138 ++num_lines; | |
139 } | |
140 m_endLine = num_lines; | |
141 m_endColumn = static_cast<int>(m_source.length()) - last_newline - 1; | |
142 } | 241 } |
143 | 242 |
| 243 V8DebuggerScript::V8DebuggerScript(v8::Isolate* isolate, String16 id, |
| 244 String16 url) |
| 245 : m_id(std::move(id)), m_url(std::move(url)), m_isolate(isolate) {} |
| 246 |
144 V8DebuggerScript::~V8DebuggerScript() {} | 247 V8DebuggerScript::~V8DebuggerScript() {} |
145 | 248 |
146 const String16& V8DebuggerScript::sourceURL() const { | 249 const String16& V8DebuggerScript::sourceURL() const { |
147 return m_sourceURL.isEmpty() ? m_url : m_sourceURL; | 250 return m_sourceURL.isEmpty() ? m_url : m_sourceURL; |
148 } | 251 } |
149 | 252 |
150 String16 V8DebuggerScript::source(v8::Isolate* isolate) const { | |
151 if (m_sourceObj.IsEmpty()) return m_source; | |
152 return toProtocolString(m_sourceObj.Get(isolate)); | |
153 } | |
154 | |
155 const String16& V8DebuggerScript::hash(v8::Isolate* isolate) const { | 253 const String16& V8DebuggerScript::hash(v8::Isolate* isolate) const { |
156 if (m_hash.isEmpty()) m_hash = calculateHash(source(isolate)); | 254 if (m_hash.isEmpty()) m_hash = calculateHash(source(isolate)); |
157 DCHECK(!m_hash.isEmpty()); | 255 DCHECK(!m_hash.isEmpty()); |
158 return m_hash; | 256 return m_hash; |
159 } | 257 } |
160 | 258 |
161 void V8DebuggerScript::setSourceURL(const String16& sourceURL) { | 259 void V8DebuggerScript::setSourceURL(const String16& sourceURL) { |
162 m_sourceURL = sourceURL; | 260 m_sourceURL = sourceURL; |
163 } | 261 } |
164 | 262 |
165 void V8DebuggerScript::setSourceMappingURL(const String16& sourceMappingURL) { | |
166 m_sourceMappingURL = sourceMappingURL; | |
167 } | |
168 | |
169 void V8DebuggerScript::setSource(v8::Local<v8::String> source) { | |
170 m_source = String16(); | |
171 m_sourceObj.Reset(m_isolate, source); | |
172 m_hash = String16(); | |
173 } | |
174 | |
175 bool V8DebuggerScript::getPossibleBreakpoints( | |
176 const v8::debug::Location& start, const v8::debug::Location& end, | |
177 std::vector<v8::debug::Location>* locations) { | |
178 v8::HandleScope scope(m_isolate); | |
179 v8::Local<v8::debug::Script> script = m_script.Get(m_isolate); | |
180 return script->GetPossibleBreakpoints(start, end, locations); | |
181 } | |
182 | |
183 } // namespace v8_inspector | 263 } // namespace v8_inspector |
OLD | NEW |