| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | 30 |
| 31 #include "bindings/core/v8/V8Binding.h" | 31 #include "bindings/core/v8/V8Binding.h" |
| 32 | 32 |
| 33 #include "bindings/core/v8/ScriptController.h" | |
| 34 #include "bindings/core/v8/V8AbstractEventListener.h" | |
| 35 #include "bindings/core/v8/V8ArrayBufferView.h" | |
| 36 #include "bindings/core/v8/V8BindingMacros.h" | 33 #include "bindings/core/v8/V8BindingMacros.h" |
| 37 #include "bindings/core/v8/V8Element.h" | |
| 38 #include "bindings/core/v8/V8EventTarget.h" | |
| 39 #include "bindings/core/v8/V8HTMLLinkElement.h" | |
| 40 #include "bindings/core/v8/V8NodeFilter.h" | |
| 41 #include "bindings/core/v8/V8NodeFilterCondition.h" | |
| 42 #include "bindings/core/v8/V8ObjectConstructor.h" | |
| 43 #include "bindings/core/v8/V8Window.h" | |
| 44 #include "bindings/core/v8/V8WorkerGlobalScope.h" | |
| 45 #include "bindings/core/v8/V8WorkletGlobalScope.h" | |
| 46 #include "bindings/core/v8/V8XPathNSResolver.h" | |
| 47 #include "bindings/core/v8/WindowProxy.h" | |
| 48 #include "bindings/core/v8/WorkerOrWorkletScriptController.h" | |
| 49 #include "bindings/core/v8/custom/V8CustomXPathNSResolver.h" | |
| 50 #include "core/dom/Document.h" | |
| 51 #include "core/dom/Element.h" | |
| 52 #include "core/dom/FlexibleArrayBufferView.h" | |
| 53 #include "core/dom/NodeFilter.h" | |
| 54 #include "core/dom/QualifiedName.h" | |
| 55 #include "core/frame/LocalDOMWindow.h" | |
| 56 #include "core/frame/LocalFrame.h" | |
| 57 #include "core/frame/LocalFrameClient.h" | |
| 58 #include "core/frame/Settings.h" | |
| 59 #include "core/inspector/InspectorTraceEvents.h" | |
| 60 #include "core/loader/FrameLoader.h" | |
| 61 #include "core/workers/WorkerGlobalScope.h" | |
| 62 #include "core/workers/WorkletGlobalScope.h" | |
| 63 #include "core/xml/XPathNSResolver.h" | |
| 64 #include "platform/instrumentation/tracing/TracedValue.h" | |
| 65 #include "platform/wtf/MathExtras.h" | |
| 66 #include "platform/wtf/StdLibExtras.h" | |
| 67 #include "platform/wtf/Threading.h" | |
| 68 #include "platform/wtf/text/AtomicString.h" | |
| 69 #include "platform/wtf/text/CString.h" | |
| 70 #include "platform/wtf/text/CharacterNames.h" | |
| 71 #include "platform/wtf/text/StringBuffer.h" | |
| 72 #include "platform/wtf/text/StringHash.h" | |
| 73 #include "platform/wtf/text/Unicode.h" | |
| 74 #include "platform/wtf/text/WTFString.h" | |
| 75 | 34 |
| 76 namespace blink { | 35 namespace blink { |
| 77 | 36 |
| 78 NodeFilter* ToNodeFilter(v8::Local<v8::Value> callback, | |
| 79 v8::Local<v8::Object> creation_context, | |
| 80 ScriptState* script_state) { | |
| 81 if (callback->IsNull()) | |
| 82 return nullptr; | |
| 83 NodeFilter* filter = NodeFilter::Create(); | |
| 84 | |
| 85 v8::Local<v8::Value> filter_wrapper = | |
| 86 ToV8(filter, creation_context, script_state->GetIsolate()); | |
| 87 if (filter_wrapper.IsEmpty()) | |
| 88 return nullptr; | |
| 89 | |
| 90 NodeFilterCondition* condition = V8NodeFilterCondition::Create( | |
| 91 callback, filter_wrapper.As<v8::Object>(), script_state); | |
| 92 filter->SetCondition(condition); | |
| 93 | |
| 94 return filter; | |
| 95 } | |
| 96 | |
| 97 bool ToBooleanSlow(v8::Isolate* isolate, | |
| 98 v8::Local<v8::Value> value, | |
| 99 ExceptionState& exception_state) { | |
| 100 DCHECK(!value->IsBoolean()); | |
| 101 v8::TryCatch block(isolate); | |
| 102 bool result = false; | |
| 103 if (!V8Call(value->BooleanValue(isolate->GetCurrentContext()), result, block)) | |
| 104 exception_state.RethrowV8Exception(block.Exception()); | |
| 105 return result; | |
| 106 } | |
| 107 | |
| 108 const int32_t kMaxInt32 = 0x7fffffff; | |
| 109 const int32_t kMinInt32 = -kMaxInt32 - 1; | |
| 110 const uint32_t kMaxUInt32 = 0xffffffff; | |
| 111 const int64_t kJSMaxInteger = | |
| 112 0x20000000000000LL - | |
| 113 1; // 2^53 - 1, maximum uniquely representable integer in ECMAScript. | |
| 114 | |
| 115 static double EnforceRange(double x, | |
| 116 double minimum, | |
| 117 double maximum, | |
| 118 const char* type_name, | |
| 119 ExceptionState& exception_state) { | |
| 120 if (std::isnan(x) || std::isinf(x)) { | |
| 121 exception_state.ThrowTypeError( | |
| 122 "Value is" + String(std::isinf(x) ? " infinite and" : "") + | |
| 123 " not of type '" + String(type_name) + "'."); | |
| 124 return 0; | |
| 125 } | |
| 126 x = trunc(x); | |
| 127 if (x < minimum || x > maximum) { | |
| 128 exception_state.ThrowTypeError("Value is outside the '" + | |
| 129 String(type_name) + "' value range."); | |
| 130 return 0; | |
| 131 } | |
| 132 return x; | |
| 133 } | |
| 134 | |
| 135 template <typename T> | |
| 136 struct IntTypeLimits {}; | |
| 137 | |
| 138 template <> | |
| 139 struct IntTypeLimits<int8_t> { | |
| 140 static const int8_t kMinValue = -128; | |
| 141 static const int8_t kMaxValue = 127; | |
| 142 static const unsigned kNumberOfValues = 256; // 2^8 | |
| 143 }; | |
| 144 | |
| 145 template <> | |
| 146 struct IntTypeLimits<uint8_t> { | |
| 147 static const uint8_t kMaxValue = 255; | |
| 148 static const unsigned kNumberOfValues = 256; // 2^8 | |
| 149 }; | |
| 150 | |
| 151 template <> | |
| 152 struct IntTypeLimits<int16_t> { | |
| 153 static const short kMinValue = -32768; | |
| 154 static const short kMaxValue = 32767; | |
| 155 static const unsigned kNumberOfValues = 65536; // 2^16 | |
| 156 }; | |
| 157 | |
| 158 template <> | |
| 159 struct IntTypeLimits<uint16_t> { | |
| 160 static const unsigned short kMaxValue = 65535; | |
| 161 static const unsigned kNumberOfValues = 65536; // 2^16 | |
| 162 }; | |
| 163 | |
| 164 template <typename T> | |
| 165 static inline T ToSmallerInt(v8::Isolate* isolate, | |
| 166 v8::Local<v8::Value> value, | |
| 167 IntegerConversionConfiguration configuration, | |
| 168 const char* type_name, | |
| 169 ExceptionState& exception_state) { | |
| 170 typedef IntTypeLimits<T> LimitsTrait; | |
| 171 | |
| 172 // Fast case. The value is already a 32-bit integer in the right range. | |
| 173 if (value->IsInt32()) { | |
| 174 int32_t result = value.As<v8::Int32>()->Value(); | |
| 175 if (result >= LimitsTrait::kMinValue && result <= LimitsTrait::kMaxValue) | |
| 176 return static_cast<T>(result); | |
| 177 if (configuration == kEnforceRange) { | |
| 178 exception_state.ThrowTypeError("Value is outside the '" + | |
| 179 String(type_name) + "' value range."); | |
| 180 return 0; | |
| 181 } | |
| 182 if (configuration == kClamp) | |
| 183 return clampTo<T>(result); | |
| 184 result %= LimitsTrait::kNumberOfValues; | |
| 185 return static_cast<T>(result > LimitsTrait::kMaxValue | |
| 186 ? result - LimitsTrait::kNumberOfValues | |
| 187 : result); | |
| 188 } | |
| 189 | |
| 190 v8::Local<v8::Number> number_object; | |
| 191 if (value->IsNumber()) { | |
| 192 number_object = value.As<v8::Number>(); | |
| 193 } else { | |
| 194 // Can the value be converted to a number? | |
| 195 v8::TryCatch block(isolate); | |
| 196 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object, | |
| 197 block)) { | |
| 198 exception_state.RethrowV8Exception(block.Exception()); | |
| 199 return 0; | |
| 200 } | |
| 201 } | |
| 202 DCHECK(!number_object.IsEmpty()); | |
| 203 | |
| 204 if (configuration == kEnforceRange) | |
| 205 return EnforceRange(number_object->Value(), LimitsTrait::kMinValue, | |
| 206 LimitsTrait::kMaxValue, type_name, exception_state); | |
| 207 | |
| 208 double number_value = number_object->Value(); | |
| 209 if (std::isnan(number_value) || !number_value) | |
| 210 return 0; | |
| 211 | |
| 212 if (configuration == kClamp) | |
| 213 return clampTo<T>(number_value); | |
| 214 | |
| 215 if (std::isinf(number_value)) | |
| 216 return 0; | |
| 217 | |
| 218 number_value = | |
| 219 number_value < 0 ? -floor(fabs(number_value)) : floor(fabs(number_value)); | |
| 220 number_value = fmod(number_value, LimitsTrait::kNumberOfValues); | |
| 221 | |
| 222 return static_cast<T>(number_value > LimitsTrait::kMaxValue | |
| 223 ? number_value - LimitsTrait::kNumberOfValues | |
| 224 : number_value); | |
| 225 } | |
| 226 | |
| 227 template <typename T> | |
| 228 static inline T ToSmallerUInt(v8::Isolate* isolate, | |
| 229 v8::Local<v8::Value> value, | |
| 230 IntegerConversionConfiguration configuration, | |
| 231 const char* type_name, | |
| 232 ExceptionState& exception_state) { | |
| 233 typedef IntTypeLimits<T> LimitsTrait; | |
| 234 | |
| 235 // Fast case. The value is a 32-bit signed integer - possibly positive? | |
| 236 if (value->IsInt32()) { | |
| 237 int32_t result = value.As<v8::Int32>()->Value(); | |
| 238 if (result >= 0 && result <= LimitsTrait::kMaxValue) | |
| 239 return static_cast<T>(result); | |
| 240 if (configuration == kEnforceRange) { | |
| 241 exception_state.ThrowTypeError("Value is outside the '" + | |
| 242 String(type_name) + "' value range."); | |
| 243 return 0; | |
| 244 } | |
| 245 if (configuration == kClamp) | |
| 246 return clampTo<T>(result); | |
| 247 return static_cast<T>(result); | |
| 248 } | |
| 249 | |
| 250 v8::Local<v8::Number> number_object; | |
| 251 if (value->IsNumber()) { | |
| 252 number_object = value.As<v8::Number>(); | |
| 253 } else { | |
| 254 // Can the value be converted to a number? | |
| 255 v8::TryCatch block(isolate); | |
| 256 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object, | |
| 257 block)) { | |
| 258 exception_state.RethrowV8Exception(block.Exception()); | |
| 259 return 0; | |
| 260 } | |
| 261 } | |
| 262 DCHECK(!number_object.IsEmpty()); | |
| 263 | |
| 264 if (configuration == kEnforceRange) | |
| 265 return EnforceRange(number_object->Value(), 0, LimitsTrait::kMaxValue, | |
| 266 type_name, exception_state); | |
| 267 | |
| 268 double number_value = number_object->Value(); | |
| 269 | |
| 270 if (std::isnan(number_value) || !number_value) | |
| 271 return 0; | |
| 272 | |
| 273 if (configuration == kClamp) | |
| 274 return clampTo<T>(number_value); | |
| 275 | |
| 276 if (std::isinf(number_value)) | |
| 277 return 0; | |
| 278 | |
| 279 number_value = | |
| 280 number_value < 0 ? -floor(fabs(number_value)) : floor(fabs(number_value)); | |
| 281 return static_cast<T>(fmod(number_value, LimitsTrait::kNumberOfValues)); | |
| 282 } | |
| 283 | |
| 284 int8_t ToInt8(v8::Isolate* isolate, | |
| 285 v8::Local<v8::Value> value, | |
| 286 IntegerConversionConfiguration configuration, | |
| 287 ExceptionState& exception_state) { | |
| 288 return ToSmallerInt<int8_t>(isolate, value, configuration, "byte", | |
| 289 exception_state); | |
| 290 } | |
| 291 | |
| 292 uint8_t ToUInt8(v8::Isolate* isolate, | |
| 293 v8::Local<v8::Value> value, | |
| 294 IntegerConversionConfiguration configuration, | |
| 295 ExceptionState& exception_state) { | |
| 296 return ToSmallerUInt<uint8_t>(isolate, value, configuration, "octet", | |
| 297 exception_state); | |
| 298 } | |
| 299 | |
| 300 int16_t ToInt16(v8::Isolate* isolate, | |
| 301 v8::Local<v8::Value> value, | |
| 302 IntegerConversionConfiguration configuration, | |
| 303 ExceptionState& exception_state) { | |
| 304 return ToSmallerInt<int16_t>(isolate, value, configuration, "short", | |
| 305 exception_state); | |
| 306 } | |
| 307 | |
| 308 uint16_t ToUInt16(v8::Isolate* isolate, | |
| 309 v8::Local<v8::Value> value, | |
| 310 IntegerConversionConfiguration configuration, | |
| 311 ExceptionState& exception_state) { | |
| 312 return ToSmallerUInt<uint16_t>(isolate, value, configuration, | |
| 313 "unsigned short", exception_state); | |
| 314 } | |
| 315 | |
| 316 int32_t ToInt32Slow(v8::Isolate* isolate, | |
| 317 v8::Local<v8::Value> value, | |
| 318 IntegerConversionConfiguration configuration, | |
| 319 ExceptionState& exception_state) { | |
| 320 DCHECK(!value->IsInt32()); | |
| 321 // Can the value be converted to a number? | |
| 322 v8::TryCatch block(isolate); | |
| 323 v8::Local<v8::Number> number_object; | |
| 324 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object, | |
| 325 block)) { | |
| 326 exception_state.RethrowV8Exception(block.Exception()); | |
| 327 return 0; | |
| 328 } | |
| 329 | |
| 330 DCHECK(!number_object.IsEmpty()); | |
| 331 | |
| 332 double number_value = number_object->Value(); | |
| 333 if (configuration == kEnforceRange) | |
| 334 return EnforceRange(number_value, kMinInt32, kMaxInt32, "long", | |
| 335 exception_state); | |
| 336 | |
| 337 if (std::isnan(number_value)) | |
| 338 return 0; | |
| 339 | |
| 340 if (configuration == kClamp) | |
| 341 return clampTo<int32_t>(number_value); | |
| 342 | |
| 343 if (std::isinf(number_value)) | |
| 344 return 0; | |
| 345 | |
| 346 int32_t result; | |
| 347 if (!V8Call(number_object->Int32Value(isolate->GetCurrentContext()), result, | |
| 348 block)) { | |
| 349 exception_state.RethrowV8Exception(block.Exception()); | |
| 350 return 0; | |
| 351 } | |
| 352 return result; | |
| 353 } | |
| 354 | |
| 355 uint32_t ToUInt32Slow(v8::Isolate* isolate, | |
| 356 v8::Local<v8::Value> value, | |
| 357 IntegerConversionConfiguration configuration, | |
| 358 ExceptionState& exception_state) { | |
| 359 DCHECK(!value->IsUint32()); | |
| 360 if (value->IsInt32()) { | |
| 361 DCHECK_NE(configuration, kNormalConversion); | |
| 362 int32_t result = value.As<v8::Int32>()->Value(); | |
| 363 if (result >= 0) | |
| 364 return result; | |
| 365 if (configuration == kEnforceRange) { | |
| 366 exception_state.ThrowTypeError( | |
| 367 "Value is outside the 'unsigned long' value range."); | |
| 368 return 0; | |
| 369 } | |
| 370 DCHECK_EQ(configuration, kClamp); | |
| 371 return clampTo<uint32_t>(result); | |
| 372 } | |
| 373 | |
| 374 // Can the value be converted to a number? | |
| 375 v8::TryCatch block(isolate); | |
| 376 v8::Local<v8::Number> number_object; | |
| 377 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object, | |
| 378 block)) { | |
| 379 exception_state.RethrowV8Exception(block.Exception()); | |
| 380 return 0; | |
| 381 } | |
| 382 DCHECK(!number_object.IsEmpty()); | |
| 383 | |
| 384 if (configuration == kEnforceRange) | |
| 385 return EnforceRange(number_object->Value(), 0, kMaxUInt32, "unsigned long", | |
| 386 exception_state); | |
| 387 | |
| 388 double number_value = number_object->Value(); | |
| 389 | |
| 390 if (std::isnan(number_value)) | |
| 391 return 0; | |
| 392 | |
| 393 if (configuration == kClamp) | |
| 394 return clampTo<uint32_t>(number_value); | |
| 395 | |
| 396 if (std::isinf(number_value)) | |
| 397 return 0; | |
| 398 | |
| 399 uint32_t result; | |
| 400 if (!V8Call(number_object->Uint32Value(isolate->GetCurrentContext()), result, | |
| 401 block)) { | |
| 402 exception_state.RethrowV8Exception(block.Exception()); | |
| 403 return 0; | |
| 404 } | |
| 405 return result; | |
| 406 } | |
| 407 | |
| 408 int64_t ToInt64Slow(v8::Isolate* isolate, | |
| 409 v8::Local<v8::Value> value, | |
| 410 IntegerConversionConfiguration configuration, | |
| 411 ExceptionState& exception_state) { | |
| 412 DCHECK(!value->IsInt32()); | |
| 413 | |
| 414 v8::Local<v8::Number> number_object; | |
| 415 // Can the value be converted to a number? | |
| 416 v8::TryCatch block(isolate); | |
| 417 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object, | |
| 418 block)) { | |
| 419 exception_state.RethrowV8Exception(block.Exception()); | |
| 420 return 0; | |
| 421 } | |
| 422 DCHECK(!number_object.IsEmpty()); | |
| 423 | |
| 424 double number_value = number_object->Value(); | |
| 425 | |
| 426 if (configuration == kEnforceRange) | |
| 427 return EnforceRange(number_value, -kJSMaxInteger, kJSMaxInteger, | |
| 428 "long long", exception_state); | |
| 429 | |
| 430 if (std::isnan(number_value) || std::isinf(number_value)) | |
| 431 return 0; | |
| 432 | |
| 433 // NaNs and +/-Infinity should be 0, otherwise modulo 2^64. | |
| 434 unsigned long long integer; | |
| 435 doubleToInteger(number_value, integer); | |
| 436 return integer; | |
| 437 } | |
| 438 | |
| 439 uint64_t ToUInt64Slow(v8::Isolate* isolate, | |
| 440 v8::Local<v8::Value> value, | |
| 441 IntegerConversionConfiguration configuration, | |
| 442 ExceptionState& exception_state) { | |
| 443 DCHECK(!value->IsUint32()); | |
| 444 if (value->IsInt32()) { | |
| 445 ASSERT(configuration != kNormalConversion); | |
| 446 int32_t result = value.As<v8::Int32>()->Value(); | |
| 447 if (result >= 0) | |
| 448 return result; | |
| 449 if (configuration == kEnforceRange) { | |
| 450 exception_state.ThrowTypeError( | |
| 451 "Value is outside the 'unsigned long long' value range."); | |
| 452 return 0; | |
| 453 } | |
| 454 DCHECK_EQ(configuration, kClamp); | |
| 455 return clampTo<uint64_t>(result); | |
| 456 } | |
| 457 | |
| 458 v8::Local<v8::Number> number_object; | |
| 459 // Can the value be converted to a number? | |
| 460 v8::TryCatch block(isolate); | |
| 461 if (!V8Call(value->ToNumber(isolate->GetCurrentContext()), number_object, | |
| 462 block)) { | |
| 463 exception_state.RethrowV8Exception(block.Exception()); | |
| 464 return 0; | |
| 465 } | |
| 466 DCHECK(!number_object.IsEmpty()); | |
| 467 | |
| 468 double number_value = number_object->Value(); | |
| 469 | |
| 470 if (configuration == kEnforceRange) | |
| 471 return EnforceRange(number_value, 0, kJSMaxInteger, "unsigned long long", | |
| 472 exception_state); | |
| 473 | |
| 474 if (std::isnan(number_value)) | |
| 475 return 0; | |
| 476 | |
| 477 if (configuration == kClamp) | |
| 478 return clampTo<uint64_t>(number_value); | |
| 479 | |
| 480 if (std::isinf(number_value)) | |
| 481 return 0; | |
| 482 | |
| 483 // NaNs and +/-Infinity should be 0, otherwise modulo 2^64. | |
| 484 unsigned long long integer; | |
| 485 doubleToInteger(number_value, integer); | |
| 486 return integer; | |
| 487 } | |
| 488 | |
| 489 float ToRestrictedFloat(v8::Isolate* isolate, | |
| 490 v8::Local<v8::Value> value, | |
| 491 ExceptionState& exception_state) { | |
| 492 float number_value = ToFloat(isolate, value, exception_state); | |
| 493 if (exception_state.HadException()) | |
| 494 return 0; | |
| 495 if (!std::isfinite(number_value)) { | |
| 496 exception_state.ThrowTypeError("The provided float value is non-finite."); | |
| 497 return 0; | |
| 498 } | |
| 499 return number_value; | |
| 500 } | |
| 501 | |
| 502 double ToDoubleSlow(v8::Isolate* isolate, | |
| 503 v8::Local<v8::Value> value, | |
| 504 ExceptionState& exception_state) { | |
| 505 DCHECK(!value->IsNumber()); | |
| 506 v8::TryCatch block(isolate); | |
| 507 v8::Local<v8::Number> number_value; | |
| 508 if (!value->ToNumber(isolate->GetCurrentContext()).ToLocal(&number_value)) { | |
| 509 exception_state.RethrowV8Exception(block.Exception()); | |
| 510 return 0; | |
| 511 } | |
| 512 return number_value->Value(); | |
| 513 } | |
| 514 | |
| 515 double ToRestrictedDouble(v8::Isolate* isolate, | |
| 516 v8::Local<v8::Value> value, | |
| 517 ExceptionState& exception_state) { | |
| 518 double number_value = ToDouble(isolate, value, exception_state); | |
| 519 if (exception_state.HadException()) | |
| 520 return 0; | |
| 521 if (!std::isfinite(number_value)) { | |
| 522 exception_state.ThrowTypeError("The provided double value is non-finite."); | |
| 523 return 0; | |
| 524 } | |
| 525 return number_value; | |
| 526 } | |
| 527 | |
| 528 String ToByteString(v8::Isolate* isolate, | |
| 529 v8::Local<v8::Value> value, | |
| 530 ExceptionState& exception_state) { | |
| 531 // Handle null default value. | |
| 532 if (value.IsEmpty()) | |
| 533 return String(); | |
| 534 | |
| 535 // From the Web IDL spec: http://heycam.github.io/webidl/#es-ByteString | |
| 536 if (value.IsEmpty()) | |
| 537 return String(); | |
| 538 | |
| 539 // 1. Let x be ToString(v) | |
| 540 v8::Local<v8::String> string_object; | |
| 541 if (value->IsString()) { | |
| 542 string_object = value.As<v8::String>(); | |
| 543 } else { | |
| 544 v8::TryCatch block(isolate); | |
| 545 if (!V8Call(value->ToString(isolate->GetCurrentContext()), string_object, | |
| 546 block)) { | |
| 547 exception_state.RethrowV8Exception(block.Exception()); | |
| 548 return String(); | |
| 549 } | |
| 550 } | |
| 551 | |
| 552 String x = ToCoreString(string_object); | |
| 553 | |
| 554 // 2. If the value of any element of x is greater than 255, then throw a | |
| 555 // TypeError. | |
| 556 if (!x.ContainsOnlyLatin1()) { | |
| 557 exception_state.ThrowTypeError("Value is not a valid ByteString."); | |
| 558 return String(); | |
| 559 } | |
| 560 | |
| 561 // 3. Return an IDL ByteString value whose length is the length of x, and | |
| 562 // where the value of each element is the value of the corresponding | |
| 563 // element of x. | |
| 564 // Blink: A ByteString is simply a String with a range constrained per the | |
| 565 // above, so this is the identity operation. | |
| 566 return x; | |
| 567 } | |
| 568 | |
| 569 static bool HasUnmatchedSurrogates(const String& string) { | |
| 570 // By definition, 8-bit strings are confined to the Latin-1 code page and | |
| 571 // have no surrogates, matched or otherwise. | |
| 572 if (string.Is8Bit()) | |
| 573 return false; | |
| 574 | |
| 575 const UChar* characters = string.Characters16(); | |
| 576 const unsigned length = string.length(); | |
| 577 | |
| 578 for (unsigned i = 0; i < length; ++i) { | |
| 579 UChar c = characters[i]; | |
| 580 if (U16_IS_SINGLE(c)) | |
| 581 continue; | |
| 582 if (U16_IS_TRAIL(c)) | |
| 583 return true; | |
| 584 ASSERT(U16_IS_LEAD(c)); | |
| 585 if (i == length - 1) | |
| 586 return true; | |
| 587 UChar d = characters[i + 1]; | |
| 588 if (!U16_IS_TRAIL(d)) | |
| 589 return true; | |
| 590 ++i; | |
| 591 } | |
| 592 return false; | |
| 593 } | |
| 594 | |
| 595 // Replace unmatched surrogates with REPLACEMENT CHARACTER U+FFFD. | |
| 596 static String ReplaceUnmatchedSurrogates(const String& string) { | |
| 597 // This roughly implements http://heycam.github.io/webidl/#dfn-obtain-unicode | |
| 598 // but since Blink strings are 16-bits internally, the output is simply | |
| 599 // re-encoded to UTF-16. | |
| 600 | |
| 601 // The concept of surrogate pairs is explained at: | |
| 602 // http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G2630 | |
| 603 | |
| 604 // Blink-specific optimization to avoid making an unnecessary copy. | |
| 605 if (!HasUnmatchedSurrogates(string)) | |
| 606 return string; | |
| 607 DCHECK(!string.Is8Bit()); | |
| 608 | |
| 609 // 1. Let S be the DOMString value. | |
| 610 const UChar* s = string.Characters16(); | |
| 611 | |
| 612 // 2. Let n be the length of S. | |
| 613 const unsigned n = string.length(); | |
| 614 | |
| 615 // 3. Initialize i to 0. | |
| 616 unsigned i = 0; | |
| 617 | |
| 618 // 4. Initialize U to be an empty sequence of Unicode characters. | |
| 619 StringBuilder u; | |
| 620 u.ReserveCapacity(n); | |
| 621 | |
| 622 // 5. While i < n: | |
| 623 while (i < n) { | |
| 624 // 1. Let c be the code unit in S at index i. | |
| 625 UChar c = s[i]; | |
| 626 // 2. Depending on the value of c: | |
| 627 if (U16_IS_SINGLE(c)) { | |
| 628 // c < 0xD800 or c > 0xDFFF | |
| 629 // Append to U the Unicode character with code point c. | |
| 630 u.Append(c); | |
| 631 } else if (U16_IS_TRAIL(c)) { | |
| 632 // 0xDC00 <= c <= 0xDFFF | |
| 633 // Append to U a U+FFFD REPLACEMENT CHARACTER. | |
| 634 u.Append(kReplacementCharacter); | |
| 635 } else { | |
| 636 // 0xD800 <= c <= 0xDBFF | |
| 637 DCHECK(U16_IS_LEAD(c)); | |
| 638 if (i == n - 1) { | |
| 639 // 1. If i = n-1, then append to U a U+FFFD REPLACEMENT CHARACTER. | |
| 640 u.Append(kReplacementCharacter); | |
| 641 } else { | |
| 642 // 2. Otherwise, i < n-1: | |
| 643 DCHECK_LT(i, n - 1); | |
| 644 // ....1. Let d be the code unit in S at index i+1. | |
| 645 UChar d = s[i + 1]; | |
| 646 if (U16_IS_TRAIL(d)) { | |
| 647 // 2. If 0xDC00 <= d <= 0xDFFF, then: | |
| 648 // ..1. Let a be c & 0x3FF. | |
| 649 // ..2. Let b be d & 0x3FF. | |
| 650 // ..3. Append to U the Unicode character with code point | |
| 651 // 2^16+2^10*a+b. | |
| 652 u.Append(U16_GET_SUPPLEMENTARY(c, d)); | |
| 653 // Blink: This is equivalent to u.append(c); u.append(d); | |
| 654 ++i; | |
| 655 } else { | |
| 656 // 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a U+FFFD | |
| 657 // REPLACEMENT CHARACTER. | |
| 658 u.Append(kReplacementCharacter); | |
| 659 } | |
| 660 } | |
| 661 } | |
| 662 // 3. Set i to i+1. | |
| 663 ++i; | |
| 664 } | |
| 665 | |
| 666 // 6. Return U. | |
| 667 DCHECK_EQ(u.length(), string.length()); | |
| 668 return u.ToString(); | |
| 669 } | |
| 670 | |
| 671 String ToUSVString(v8::Isolate* isolate, | |
| 672 v8::Local<v8::Value> value, | |
| 673 ExceptionState& exception_state) { | |
| 674 // http://heycam.github.io/webidl/#es-USVString | |
| 675 if (value.IsEmpty()) | |
| 676 return String(); | |
| 677 | |
| 678 v8::Local<v8::String> string_object; | |
| 679 if (value->IsString()) { | |
| 680 string_object = value.As<v8::String>(); | |
| 681 } else { | |
| 682 v8::TryCatch block(isolate); | |
| 683 if (!V8Call(value->ToString(isolate->GetCurrentContext()), string_object, | |
| 684 block)) { | |
| 685 exception_state.RethrowV8Exception(block.Exception()); | |
| 686 return String(); | |
| 687 } | |
| 688 } | |
| 689 | |
| 690 // USVString is identical to DOMString except that "convert a | |
| 691 // DOMString to a sequence of Unicode characters" is used subsequently | |
| 692 // when converting to an IDL value | |
| 693 String x = ToCoreString(string_object); | |
| 694 return ReplaceUnmatchedSurrogates(x); | |
| 695 } | |
| 696 | |
| 697 XPathNSResolver* ToXPathNSResolver(ScriptState* script_state, | |
| 698 v8::Local<v8::Value> value) { | |
| 699 XPathNSResolver* resolver = nullptr; | |
| 700 if (V8XPathNSResolver::hasInstance(value, script_state->GetIsolate())) | |
| 701 resolver = V8XPathNSResolver::toImpl(v8::Local<v8::Object>::Cast(value)); | |
| 702 else if (value->IsObject()) | |
| 703 resolver = | |
| 704 V8CustomXPathNSResolver::Create(script_state, value.As<v8::Object>()); | |
| 705 return resolver; | |
| 706 } | |
| 707 | |
| 708 DOMWindow* ToDOMWindow(v8::Isolate* isolate, v8::Local<v8::Value> value) { | |
| 709 if (value.IsEmpty() || !value->IsObject()) | |
| 710 return 0; | |
| 711 | |
| 712 v8::Local<v8::Object> window_wrapper = V8Window::findInstanceInPrototypeChain( | |
| 713 v8::Local<v8::Object>::Cast(value), isolate); | |
| 714 if (!window_wrapper.IsEmpty()) | |
| 715 return V8Window::toImpl(window_wrapper); | |
| 716 return 0; | |
| 717 } | |
| 718 | |
| 719 LocalDOMWindow* ToLocalDOMWindow(v8::Local<v8::Context> context) { | |
| 720 if (context.IsEmpty()) | |
| 721 return 0; | |
| 722 return ToLocalDOMWindow( | |
| 723 ToDOMWindow(context->GetIsolate(), context->Global())); | |
| 724 } | |
| 725 | |
| 726 LocalDOMWindow* EnteredDOMWindow(v8::Isolate* isolate) { | |
| 727 LocalDOMWindow* window = | |
| 728 ToLocalDOMWindow(isolate->GetEnteredOrMicrotaskContext()); | |
| 729 DCHECK(window); | |
| 730 return window; | |
| 731 } | |
| 732 | |
| 733 LocalDOMWindow* CurrentDOMWindow(v8::Isolate* isolate) { | |
| 734 return ToLocalDOMWindow(isolate->GetCurrentContext()); | |
| 735 } | |
| 736 | |
| 737 ExecutionContext* ToExecutionContext(v8::Local<v8::Context> context) { | |
| 738 if (context.IsEmpty()) | |
| 739 return 0; | |
| 740 v8::Local<v8::Object> global = context->Global(); | |
| 741 v8::Local<v8::Object> window_wrapper = | |
| 742 V8Window::findInstanceInPrototypeChain(global, context->GetIsolate()); | |
| 743 if (!window_wrapper.IsEmpty()) | |
| 744 return V8Window::toImpl(window_wrapper)->GetExecutionContext(); | |
| 745 v8::Local<v8::Object> worker_wrapper = | |
| 746 V8WorkerGlobalScope::findInstanceInPrototypeChain(global, | |
| 747 context->GetIsolate()); | |
| 748 if (!worker_wrapper.IsEmpty()) | |
| 749 return V8WorkerGlobalScope::toImpl(worker_wrapper)->GetExecutionContext(); | |
| 750 v8::Local<v8::Object> worklet_wrapper = | |
| 751 V8WorkletGlobalScope::findInstanceInPrototypeChain(global, | |
| 752 context->GetIsolate()); | |
| 753 if (!worklet_wrapper.IsEmpty()) | |
| 754 return V8WorkletGlobalScope::toImpl(worklet_wrapper); | |
| 755 // FIXME: Is this line of code reachable? | |
| 756 return nullptr; | |
| 757 } | |
| 758 | |
| 759 ExecutionContext* CurrentExecutionContext(v8::Isolate* isolate) { | |
| 760 return ToExecutionContext(isolate->GetCurrentContext()); | |
| 761 } | |
| 762 | |
| 763 LocalFrame* ToLocalFrameIfNotDetached(v8::Local<v8::Context> context) { | |
| 764 LocalDOMWindow* window = ToLocalDOMWindow(context); | |
| 765 if (window && window->IsCurrentlyDisplayedInFrame()) | |
| 766 return window->GetFrame(); | |
| 767 // We return 0 here because |context| is detached from the Frame. If we | |
| 768 // did return |frame| we could get in trouble because the frame could be | |
| 769 // navigated to another security origin. | |
| 770 return nullptr; | |
| 771 } | |
| 772 | |
| 773 void ToFlexibleArrayBufferView(v8::Isolate* isolate, | |
| 774 v8::Local<v8::Value> value, | |
| 775 FlexibleArrayBufferView& result, | |
| 776 void* storage) { | |
| 777 DCHECK(value->IsArrayBufferView()); | |
| 778 v8::Local<v8::ArrayBufferView> buffer = value.As<v8::ArrayBufferView>(); | |
| 779 if (!storage) { | |
| 780 result.SetFull(V8ArrayBufferView::toImpl(buffer)); | |
| 781 return; | |
| 782 } | |
| 783 size_t length = buffer->ByteLength(); | |
| 784 buffer->CopyContents(storage, length); | |
| 785 result.SetSmall(storage, length); | |
| 786 } | |
| 787 | |
| 788 static ScriptState* ToScriptStateImpl(LocalFrame* frame, | |
| 789 DOMWrapperWorld& world) { | |
| 790 if (!frame) | |
| 791 return nullptr; | |
| 792 v8::Local<v8::Context> context = ToV8ContextEvenIfDetached(frame, world); | |
| 793 if (context.IsEmpty()) | |
| 794 return nullptr; | |
| 795 ScriptState* script_state = ScriptState::From(context); | |
| 796 if (!script_state->ContextIsValid()) | |
| 797 return nullptr; | |
| 798 DCHECK_EQ(frame, ToLocalFrameIfNotDetached(context)); | |
| 799 return script_state; | |
| 800 } | |
| 801 | |
| 802 v8::Local<v8::Context> ToV8Context(ExecutionContext* context, | |
| 803 DOMWrapperWorld& world) { | |
| 804 DCHECK(context); | |
| 805 if (context->IsDocument()) { | |
| 806 if (LocalFrame* frame = ToDocument(context)->GetFrame()) | |
| 807 return ToV8Context(frame, world); | |
| 808 } else if (context->IsWorkerGlobalScope()) { | |
| 809 if (WorkerOrWorkletScriptController* script = | |
| 810 ToWorkerOrWorkletGlobalScope(context)->ScriptController()) { | |
| 811 if (script->GetScriptState()->ContextIsValid()) | |
| 812 return script->GetScriptState()->GetContext(); | |
| 813 } | |
| 814 } | |
| 815 return v8::Local<v8::Context>(); | |
| 816 } | |
| 817 | |
| 818 v8::Local<v8::Context> ToV8Context(LocalFrame* frame, DOMWrapperWorld& world) { | |
| 819 ScriptState* script_state = ToScriptStateImpl(frame, world); | |
| 820 if (!script_state) | |
| 821 return v8::Local<v8::Context>(); | |
| 822 return script_state->GetContext(); | |
| 823 } | |
| 824 | |
| 825 v8::Local<v8::Context> ToV8ContextEvenIfDetached(LocalFrame* frame, | |
| 826 DOMWrapperWorld& world) { | |
| 827 DCHECK(frame); | |
| 828 return frame->WindowProxy(world)->ContextIfInitialized(); | |
| 829 } | |
| 830 | |
| 831 ScriptState* ToScriptState(LocalFrame* frame, DOMWrapperWorld& world) { | |
| 832 v8::HandleScope handle_scope(ToIsolate(frame)); | |
| 833 return ToScriptStateImpl(frame, world); | |
| 834 } | |
| 835 | |
| 836 ScriptState* ToScriptStateForMainWorld(LocalFrame* frame) { | |
| 837 return ToScriptState(frame, DOMWrapperWorld::MainWorld()); | |
| 838 } | |
| 839 | |
| 840 bool IsValidEnum(const String& value, | |
| 841 const char** valid_values, | |
| 842 size_t length, | |
| 843 const String& enum_name, | |
| 844 ExceptionState& exception_state) { | |
| 845 for (size_t i = 0; i < length; ++i) { | |
| 846 // Avoid the strlen inside String::operator== (because of the StringView). | |
| 847 if (WTF::Equal(value.Impl(), valid_values[i])) | |
| 848 return true; | |
| 849 } | |
| 850 exception_state.ThrowTypeError("The provided value '" + value + | |
| 851 "' is not a valid enum value of type " + | |
| 852 enum_name + "."); | |
| 853 return false; | |
| 854 } | |
| 855 | |
| 856 bool IsValidEnum(const Vector<String>& values, | |
| 857 const char** valid_values, | |
| 858 size_t length, | |
| 859 const String& enum_name, | |
| 860 ExceptionState& exception_state) { | |
| 861 for (auto value : values) { | |
| 862 if (!IsValidEnum(value, valid_values, length, enum_name, exception_state)) | |
| 863 return false; | |
| 864 } | |
| 865 return true; | |
| 866 } | |
| 867 | |
| 868 v8::Local<v8::Function> GetBoundFunction(v8::Local<v8::Function> function) { | 37 v8::Local<v8::Function> GetBoundFunction(v8::Local<v8::Function> function) { |
| 869 v8::Local<v8::Value> bound_function = function->GetBoundFunction(); | 38 v8::Local<v8::Value> bound_function = function->GetBoundFunction(); |
| 870 return bound_function->IsFunction() | 39 return bound_function->IsFunction() |
| 871 ? v8::Local<v8::Function>::Cast(bound_function) | 40 ? v8::Local<v8::Function>::Cast(bound_function) |
| 872 : function; | 41 : function; |
| 873 } | 42 } |
| 874 | 43 |
| 875 v8::Local<v8::Object> GetEsIterator(v8::Isolate* isolate, | |
| 876 v8::Local<v8::Object> object, | |
| 877 ExceptionState& exception_state) { | |
| 878 v8::TryCatch block(isolate); | |
| 879 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
| 880 v8::Local<v8::Value> iterator_getter; | |
| 881 if (!object->Get(context, v8::Symbol::GetIterator(isolate)) | |
| 882 .ToLocal(&iterator_getter)) { | |
| 883 exception_state.RethrowV8Exception(block.Exception()); | |
| 884 return v8::Local<v8::Object>(); | |
| 885 } | |
| 886 if (!iterator_getter->IsFunction()) { | |
| 887 exception_state.ThrowTypeError("Iterator getter is not callable."); | |
| 888 return v8::Local<v8::Object>(); | |
| 889 } | |
| 890 | |
| 891 v8::Local<v8::Function> getter_function = iterator_getter.As<v8::Function>(); | |
| 892 v8::Local<v8::Value> iterator; | |
| 893 if (!V8ScriptRunner::CallFunction(getter_function, | |
| 894 ToExecutionContext(context), object, 0, | |
| 895 nullptr, isolate) | |
| 896 .ToLocal(&iterator)) { | |
| 897 exception_state.RethrowV8Exception(block.Exception()); | |
| 898 return v8::Local<v8::Object>(); | |
| 899 } | |
| 900 if (!iterator->IsObject()) { | |
| 901 exception_state.ThrowTypeError("Iterator is not an object."); | |
| 902 return v8::Local<v8::Object>(); | |
| 903 } | |
| 904 return iterator.As<v8::Object>(); | |
| 905 } | |
| 906 | |
| 907 bool HasCallableIteratorSymbol(v8::Isolate* isolate, | |
| 908 v8::Local<v8::Value> value, | |
| 909 ExceptionState& exception_state) { | |
| 910 if (!value->IsObject()) | |
| 911 return false; | |
| 912 v8::TryCatch block(isolate); | |
| 913 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
| 914 v8::Local<v8::Value> iterator_getter; | |
| 915 if (!value.As<v8::Object>() | |
| 916 ->Get(context, v8::Symbol::GetIterator(isolate)) | |
| 917 .ToLocal(&iterator_getter)) { | |
| 918 exception_state.RethrowV8Exception(block.Exception()); | |
| 919 return false; | |
| 920 } | |
| 921 return iterator_getter->IsFunction(); | |
| 922 } | |
| 923 | |
| 924 bool AddHiddenValueToArray(v8::Isolate* isolate, | 44 bool AddHiddenValueToArray(v8::Isolate* isolate, |
| 925 v8::Local<v8::Object> object, | 45 v8::Local<v8::Object> object, |
| 926 v8::Local<v8::Value> value, | 46 v8::Local<v8::Value> value, |
| 927 int array_index) { | 47 int array_index) { |
| 928 DCHECK(!value.IsEmpty()); | 48 DCHECK(!value.IsEmpty()); |
| 929 v8::Local<v8::Value> array_value = object->GetInternalField(array_index); | 49 v8::Local<v8::Value> array_value = object->GetInternalField(array_index); |
| 930 if (array_value->IsNull() || array_value->IsUndefined()) { | 50 if (array_value->IsNull() || array_value->IsUndefined()) { |
| 931 array_value = v8::Array::New(isolate); | 51 array_value = v8::Array::New(isolate); |
| 932 object->SetInternalField(array_index, array_value); | 52 object->SetInternalField(array_index, array_value); |
| 933 } | 53 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 949 v8::Local<v8::Value> item; | 69 v8::Local<v8::Value> item; |
| 950 if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&item)) | 70 if (!array->Get(isolate->GetCurrentContext(), i).ToLocal(&item)) |
| 951 return; | 71 return; |
| 952 if (item->StrictEquals(value)) { | 72 if (item->StrictEquals(value)) { |
| 953 array->Delete(isolate->GetCurrentContext(), i).ToChecked(); | 73 array->Delete(isolate->GetCurrentContext(), i).ToChecked(); |
| 954 return; | 74 return; |
| 955 } | 75 } |
| 956 } | 76 } |
| 957 } | 77 } |
| 958 | 78 |
| 959 void MoveEventListenerToNewWrapper(v8::Isolate* isolate, | |
| 960 v8::Local<v8::Object> object, | |
| 961 EventListener* old_value, | |
| 962 v8::Local<v8::Value> new_value, | |
| 963 int array_index) { | |
| 964 if (old_value) { | |
| 965 V8AbstractEventListener* old_listener = | |
| 966 V8AbstractEventListener::Cast(old_value); | |
| 967 if (old_listener) { | |
| 968 v8::Local<v8::Object> old_listener_object = | |
| 969 old_listener->GetExistingListenerObject(); | |
| 970 if (!old_listener_object.IsEmpty()) | |
| 971 RemoveHiddenValueFromArray(isolate, object, old_listener_object, | |
| 972 array_index); | |
| 973 } | |
| 974 } | |
| 975 // Non-callable input is treated as null and ignored | |
| 976 if (new_value->IsFunction()) | |
| 977 AddHiddenValueToArray(isolate, object, new_value, array_index); | |
| 978 } | |
| 979 | |
| 980 v8::Isolate* ToIsolate(ExecutionContext* context) { | |
| 981 if (context && context->IsDocument()) | |
| 982 return V8PerIsolateData::MainThreadIsolate(); | |
| 983 return v8::Isolate::GetCurrent(); | |
| 984 } | |
| 985 | |
| 986 v8::Isolate* ToIsolate(LocalFrame* frame) { | |
| 987 DCHECK(frame); | |
| 988 return frame->GetWindowProxyManager()->GetIsolate(); | |
| 989 } | |
| 990 | |
| 991 v8::Local<v8::Value> FreezeV8Object(v8::Local<v8::Value> value, | 79 v8::Local<v8::Value> FreezeV8Object(v8::Local<v8::Value> value, |
| 992 v8::Isolate* isolate) { | 80 v8::Isolate* isolate) { |
| 993 value.As<v8::Object>() | 81 value.As<v8::Object>() |
| 994 ->SetIntegrityLevel(isolate->GetCurrentContext(), | 82 ->SetIntegrityLevel(isolate->GetCurrentContext(), |
| 995 v8::IntegrityLevel::kFrozen) | 83 v8::IntegrityLevel::kFrozen) |
| 996 .ToChecked(); | 84 .ToChecked(); |
| 997 return value; | 85 return value; |
| 998 } | 86 } |
| 999 | 87 |
| 1000 v8::Local<v8::Value> FromJSONString(v8::Isolate* isolate, | |
| 1001 const String& stringified_json, | |
| 1002 ExceptionState& exception_state) { | |
| 1003 v8::Local<v8::Value> parsed; | |
| 1004 v8::TryCatch try_catch(isolate); | |
| 1005 if (!V8Call(v8::JSON::Parse(isolate, V8String(isolate, stringified_json)), | |
| 1006 parsed, try_catch)) { | |
| 1007 if (try_catch.HasCaught()) | |
| 1008 exception_state.RethrowV8Exception(try_catch.Exception()); | |
| 1009 } | |
| 1010 | |
| 1011 return parsed; | |
| 1012 } | |
| 1013 | |
| 1014 } // namespace blink | 88 } // namespace blink |
| OLD | NEW |