Document::securityOrigin() should return a reference.
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMBinding.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004-2011, 2013, 2016 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
5  *  Copyright (C) 2013 Michael Pruett <michael@68k.org>
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "config.h"
23 #include "JSDOMBinding.h"
24
25 #include "CachedScript.h"
26 #include "CommonVM.h"
27 #include "DOMConstructorWithDocument.h"
28 #include "ExceptionCode.h"
29 #include "ExceptionCodeDescription.h"
30 #include "ExceptionHeaders.h"
31 #include "ExceptionInterfaces.h"
32 #include "Frame.h"
33 #include "HTMLParserIdioms.h"
34 #include "IDBDatabaseException.h"
35 #include "JSDOMConvert.h"
36 #include "JSDOMPromise.h"
37 #include "JSDOMWindowCustom.h"
38 #include "JSExceptionBase.h"
39 #include "SecurityOrigin.h"
40 #include <bytecode/CodeBlock.h>
41 #include <inspector/ScriptCallStack.h>
42 #include <inspector/ScriptCallStackFactory.h>
43 #include <runtime/DateInstance.h>
44 #include <runtime/Error.h>
45 #include <runtime/ErrorHandlingScope.h>
46 #include <runtime/ErrorInstance.h>
47 #include <runtime/Exception.h>
48 #include <runtime/ExceptionHelpers.h>
49 #include <runtime/JSFunction.h>
50 #include <stdarg.h>
51 #include <wtf/MathExtras.h>
52 #include <wtf/unicode/CharacterNames.h>
53 #include <wtf/text/StringBuilder.h>
54
55 using namespace JSC;
56 using namespace Inspector;
57
58 namespace WebCore {
59
60 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DOMConstructorObject);
61 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(DOMConstructorWithDocument);
62
63 void addImpureProperty(const AtomicString& propertyName)
64 {
65     commonVM().addImpureProperty(propertyName);
66 }
67
68 JSValue jsOwnedStringOrNull(ExecState* exec, const String& s)
69 {
70     if (s.isNull())
71         return jsNull();
72     return jsOwnedString(exec, s);
73 }
74
75 JSValue jsStringOrUndefined(ExecState* exec, const String& s)
76 {
77     if (s.isNull())
78         return jsUndefined();
79     return jsStringWithCache(exec, s);
80 }
81
82 JSValue jsString(ExecState* exec, const URL& url)
83 {
84     return jsStringWithCache(exec, url.string());
85 }
86
87 JSValue jsStringOrUndefined(ExecState* exec, const URL& url)
88 {
89     if (url.isNull())
90         return jsUndefined();
91     return jsStringWithCache(exec, url.string());
92 }
93
94 static inline String stringToByteString(ExecState& state, JSC::ThrowScope& scope, String&& string)
95 {
96     if (!string.containsOnlyLatin1()) {
97         throwTypeError(&state, scope);
98         return { };
99     }
100
101     return string;
102 }
103
104 String identifierToByteString(ExecState& state, const Identifier& identifier)
105 {
106     VM& vm = state.vm();
107     auto scope = DECLARE_THROW_SCOPE(vm);
108
109     String string = identifier.string();
110     return stringToByteString(state, scope, WTFMove(string));
111 }
112
113 String valueToByteString(ExecState& state, JSValue value)
114 {
115     VM& vm = state.vm();
116     auto scope = DECLARE_THROW_SCOPE(vm);
117
118     String string = value.toWTFString(&state);
119     RETURN_IF_EXCEPTION(scope, { });
120
121     return stringToByteString(state, scope, WTFMove(string));
122 }
123
124 static inline bool hasUnpairedSurrogate(StringView string)
125 {
126     // Fast path for 8-bit strings; they can't have any surrogates.
127     if (string.is8Bit())
128         return false;
129     for (auto codePoint : string.codePoints()) {
130         if (U_IS_SURROGATE(codePoint))
131             return true;
132     }
133     return false;
134 }
135
136 static inline String stringToUSVString(String&& string)
137 {
138     // Fast path for the case where there are no unpaired surrogates.
139     if (!hasUnpairedSurrogate(string))
140         return string;
141
142     // Slow path: http://heycam.github.io/webidl/#dfn-obtain-unicode
143     // Replaces unpaired surrogates with the replacement character.
144     StringBuilder result;
145     result.reserveCapacity(string.length());
146     StringView view { string };
147     for (auto codePoint : view.codePoints()) {
148         if (U_IS_SURROGATE(codePoint))
149             result.append(replacementCharacter);
150         else
151             result.append(codePoint);
152     }
153     return result.toString();
154 }
155
156 String identifierToUSVString(ExecState&, const Identifier& identifier)
157 {
158     String string = identifier.string();
159     return stringToUSVString(WTFMove(string));
160 }
161
162 String valueToUSVString(ExecState& state, JSValue value)
163 {
164     VM& vm = state.vm();
165     auto scope = DECLARE_THROW_SCOPE(vm);
166
167     String string = value.toWTFString(&state);
168     RETURN_IF_EXCEPTION(scope, { });
169
170     return stringToUSVString(WTFMove(string));
171 }
172
173 JSValue jsDate(ExecState* exec, double value)
174 {
175     return DateInstance::create(exec->vm(), exec->lexicalGlobalObject()->dateStructure(), value);
176 }
177
178 double valueToDate(ExecState* exec, JSValue value)
179 {
180     if (value.isNumber())
181         return value.asNumber();
182     if (!value.inherits(DateInstance::info()))
183         return std::numeric_limits<double>::quiet_NaN();
184     return static_cast<DateInstance*>(value.toObject(exec))->internalNumber();
185 }
186
187 void reportException(ExecState* exec, JSValue exceptionValue, CachedScript* cachedScript)
188 {
189     VM& vm = exec->vm();
190     RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
191     auto* exception = jsDynamicDowncast<JSC::Exception*>(exceptionValue);
192     if (!exception) {
193         exception = vm.lastException();
194         if (!exception)
195             exception = JSC::Exception::create(exec->vm(), exceptionValue, JSC::Exception::DoNotCaptureStack);
196     }
197
198     reportException(exec, exception, cachedScript);
199 }
200
201 String retrieveErrorMessage(ExecState& state, VM& vm, JSValue exception, CatchScope& catchScope)
202 {
203     if (auto* exceptionBase = toExceptionBase(exception))
204         return exceptionBase->toString();
205
206     // FIXME: <http://webkit.org/b/115087> Web Inspector: WebCore::reportException should not evaluate JavaScript handling exceptions
207     // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
208     String errorMessage;
209     if (auto* error = jsDynamicDowncast<ErrorInstance*>(exception))
210         errorMessage = error->sanitizedToString(&state);
211     else
212         errorMessage = exception.toWTFString(&state);
213
214     // We need to clear any new exception that may be thrown in the toString() call above.
215     // reportException() is not supposed to be making new exceptions.
216     catchScope.clearException();
217     vm.clearLastException();
218     return errorMessage;
219 }
220
221 void reportException(ExecState* exec, JSC::Exception* exception, CachedScript* cachedScript, ExceptionDetails* exceptionDetails)
222 {
223     VM& vm = exec->vm();
224     auto scope = DECLARE_CATCH_SCOPE(vm);
225
226     RELEASE_ASSERT(vm.currentThreadIsHoldingAPILock());
227     if (isTerminatedExecutionException(exception))
228         return;
229
230     ErrorHandlingScope errorScope(exec->vm());
231
232     RefPtr<ScriptCallStack> callStack(createScriptCallStackFromException(exec, exception, ScriptCallStack::maxCallStackSizeToCapture));
233     scope.clearException();
234     vm.clearLastException();
235
236     JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
237     if (JSDOMWindow* window = jsDynamicDowncast<JSDOMWindow*>(globalObject)) {
238         if (!window->wrapped().isCurrentlyDisplayedInFrame())
239             return;
240     }
241
242     int lineNumber = 0;
243     int columnNumber = 0;
244     String exceptionSourceURL;
245     if (const ScriptCallFrame* callFrame = callStack->firstNonNativeCallFrame()) {
246         lineNumber = callFrame->lineNumber();
247         columnNumber = callFrame->columnNumber();
248         exceptionSourceURL = callFrame->sourceURL();
249     }
250
251     String errorMessage = retrieveErrorMessage(*exec, vm, exception->value(), scope);
252     ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
253     scriptExecutionContext->reportException(errorMessage, lineNumber, columnNumber, exceptionSourceURL, exception, callStack->size() ? callStack : nullptr, cachedScript);
254
255     if (exceptionDetails) {
256         exceptionDetails->message = errorMessage;
257         exceptionDetails->lineNumber = lineNumber;
258         exceptionDetails->columnNumber = columnNumber;
259         exceptionDetails->sourceURL = exceptionSourceURL;
260     }
261 }
262
263 void reportCurrentException(ExecState* exec)
264 {
265     VM& vm = exec->vm();
266     auto scope = DECLARE_CATCH_SCOPE(vm);
267     auto* exception = scope.exception();
268     scope.clearException();
269     reportException(exec, exception);
270 }
271
272 static JSValue createDOMException(ExecState* exec, ExceptionCode ec, const String* message = nullptr)
273 {
274     if (!ec || ec == ExistingExceptionError)
275         return jsUndefined();
276
277     // FIXME: Handle other WebIDL exception types.
278     if (ec == TypeError) {
279         if (!message || message->isEmpty())
280             return createTypeError(exec);
281         return createTypeError(exec, *message);
282     }
283
284     if (ec == RangeError) {
285         if (!message || message->isEmpty())
286             return createRangeError(exec, ASCIILiteral("Bad value"));
287         return createRangeError(exec, *message);
288     }
289
290     if (ec == StackOverflowError)
291         return createStackOverflowError(exec);
292
293     // FIXME: All callers to createDOMException need to pass in the correct global object.
294     // For now, we're going to assume the lexicalGlobalObject. Which is wrong in cases like this:
295     // frames[0].document.createElement(null, null); // throws an exception which should have the subframe's prototypes.
296     JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec);
297
298     ExceptionCodeDescription description(ec);
299
300     CString messageCString;
301     if (message)
302         messageCString = message->utf8();
303     if (message && !message->isEmpty()) {
304         // It is safe to do this because the char* contents of the CString are copied into a new WTF::String before the CString is destroyed.
305         description.description = messageCString.data();
306     }
307
308     JSValue errorObject;
309     switch (description.type) {
310     case DOMCoreExceptionType:
311 #if ENABLE(INDEXED_DATABASE)
312     case IDBDatabaseExceptionType:
313 #endif
314         errorObject = toJS(exec, globalObject, DOMCoreException::create(description));
315         break;
316     case FileExceptionType:
317         errorObject = toJS(exec, globalObject, FileException::create(description));
318         break;
319     case SQLExceptionType:
320         errorObject = toJS(exec, globalObject, SQLException::create(description));
321         break;
322     case SVGExceptionType:
323         errorObject = toJS(exec, globalObject, SVGException::create(description));
324         break;
325     case XPathExceptionType:
326         errorObject = toJS(exec, globalObject, XPathException::create(description));
327         break;
328     }
329     
330     ASSERT(errorObject);
331     addErrorInfo(exec, asObject(errorObject), true);
332     return errorObject;
333 }
334
335 JSValue createDOMException(ExecState* exec, ExceptionCode ec, const String& message)
336 {
337     return createDOMException(exec, ec, &message);
338 }
339
340 JSValue createDOMException(ExecState& state, Exception&& exception)
341 {
342     return createDOMException(&state, exception.code(), exception.releaseMessage());
343 }
344
345 void propagateExceptionSlowPath(JSC::ExecState& state, JSC::ThrowScope& throwScope, Exception&& exception)
346 {
347     ASSERT(!throwScope.exception());
348     throwException(&state, throwScope, createDOMException(state, WTFMove(exception)));
349 }
350
351 bool hasIteratorMethod(JSC::ExecState& state, JSC::JSValue value)
352 {
353     auto& vm = state.vm();
354     auto scope = DECLARE_THROW_SCOPE(vm);
355
356     if (!value.isObject())
357         return false;
358
359     JSObject* object = JSC::asObject(value);
360     CallData callData;
361     CallType callType;
362     JSValue applyMethod = object->getMethod(&state, callData, callType, vm.propertyNames->iteratorSymbol, ASCIILiteral("Symbol.iterator property should be callable"));
363     RETURN_IF_EXCEPTION(scope, false);
364
365     return !applyMethod.isUndefined();
366 }
367
368 bool BindingSecurity::shouldAllowAccessToFrame(ExecState& state, Frame& frame, String& message)
369 {
370     if (BindingSecurity::shouldAllowAccessToFrame(&state, &frame, DoNotReportSecurityError))
371         return true;
372     message = frame.document()->domWindow()->crossDomainAccessErrorMessage(activeDOMWindow(&state));
373     return false;
374 }
375
376 bool BindingSecurity::shouldAllowAccessToDOMWindow(ExecState& state, DOMWindow& globalObject, String& message)
377 {
378     if (BindingSecurity::shouldAllowAccessToDOMWindow(&state, globalObject, DoNotReportSecurityError))
379         return true;
380     message = globalObject.crossDomainAccessErrorMessage(activeDOMWindow(&state));
381     return false;
382 }
383
384 void printErrorMessageForFrame(Frame* frame, const String& message)
385 {
386     if (!frame)
387         return;
388     frame->document()->domWindow()->printErrorMessage(message);
389 }
390
391 Structure* getCachedDOMStructure(JSDOMGlobalObject& globalObject, const ClassInfo* classInfo)
392 {
393     JSDOMStructureMap& structures = globalObject.structures(NoLockingNecessary);
394     return structures.get(classInfo).get();
395 }
396
397 Structure* cacheDOMStructure(JSDOMGlobalObject& globalObject, Structure* structure, const ClassInfo* classInfo)
398 {
399     auto locker = lockDuringMarking(globalObject.vm().heap, globalObject.gcLock());
400     JSDOMStructureMap& structures = globalObject.structures(locker);
401     ASSERT(!structures.contains(classInfo));
402     return structures.set(classInfo, WriteBarrier<Structure>(globalObject.vm(), &globalObject, structure)).iterator->value.get();
403 }
404
405 static const int32_t kMaxInt32 = 0x7fffffff;
406 static const int32_t kMinInt32 = -kMaxInt32 - 1;
407 static const uint32_t kMaxUInt32 = 0xffffffffU;
408 static const int64_t kJSMaxInteger = 0x20000000000000LL - 1; // 2^53 - 1, largest integer exactly representable in ECMAScript.
409
410 static String rangeErrorString(double value, double min, double max)
411 {
412     return makeString("Value ", String::numberToStringECMAScript(value), " is outside the range [", String::numberToStringECMAScript(min), ", ", String::numberToStringECMAScript(max), "]");
413 }
414
415 static double enforceRange(ExecState& state, double x, double minimum, double maximum)
416 {
417     VM& vm = state.vm();
418     auto scope = DECLARE_THROW_SCOPE(vm);
419
420     if (std::isnan(x) || std::isinf(x)) {
421         throwTypeError(&state, scope, rangeErrorString(x, minimum, maximum));
422         return 0;
423     }
424     x = trunc(x);
425     if (x < minimum || x > maximum) {
426         throwTypeError(&state, scope, rangeErrorString(x, minimum, maximum));
427         return 0;
428     }
429     return x;
430 }
431
432 template <typename T>
433 struct IntTypeLimits {
434 };
435
436 template <>
437 struct IntTypeLimits<int8_t> {
438     static const int8_t minValue = -128;
439     static const int8_t maxValue = 127;
440     static const unsigned numberOfValues = 256; // 2^8
441 };
442
443 template <>
444 struct IntTypeLimits<uint8_t> {
445     static const uint8_t maxValue = 255;
446     static const unsigned numberOfValues = 256; // 2^8
447 };
448
449 template <>
450 struct IntTypeLimits<int16_t> {
451     static const short minValue = -32768;
452     static const short maxValue = 32767;
453     static const unsigned numberOfValues = 65536; // 2^16
454 };
455
456 template <>
457 struct IntTypeLimits<uint16_t> {
458     static const unsigned short maxValue = 65535;
459     static const unsigned numberOfValues = 65536; // 2^16
460 };
461
462 template <typename T>
463 static inline T toSmallerInt(ExecState& state, JSValue value, IntegerConversionConfiguration configuration)
464 {
465     VM& vm = state.vm();
466     auto scope = DECLARE_THROW_SCOPE(vm);
467
468     static_assert(std::is_signed<T>::value && std::is_integral<T>::value, "Should only be used for signed integral types");
469
470     typedef IntTypeLimits<T> LimitsTrait;
471     // Fast path if the value is already a 32-bit signed integer in the right range.
472     if (value.isInt32()) {
473         int32_t d = value.asInt32();
474         if (d >= LimitsTrait::minValue && d <= LimitsTrait::maxValue)
475             return static_cast<T>(d);
476         switch (configuration) {
477         case IntegerConversionConfiguration::Normal:
478             break;
479         case IntegerConversionConfiguration::EnforceRange:
480             throwTypeError(&state, scope);
481             return 0;
482         case IntegerConversionConfiguration::Clamp:
483             return d < LimitsTrait::minValue ? LimitsTrait::minValue : LimitsTrait::maxValue;
484         }
485         d %= LimitsTrait::numberOfValues;
486         return static_cast<T>(d > LimitsTrait::maxValue ? d - LimitsTrait::numberOfValues : d);
487     }
488
489     double x = value.toNumber(&state);
490     RETURN_IF_EXCEPTION(scope, 0);
491
492     switch (configuration) {
493     case IntegerConversionConfiguration::Normal:
494         break;
495     case IntegerConversionConfiguration::EnforceRange:
496         return enforceRange(state, x, LimitsTrait::minValue, LimitsTrait::maxValue);
497     case IntegerConversionConfiguration::Clamp:
498         return std::isnan(x) ? 0 : clampTo<T>(x);
499     }
500
501     if (std::isnan(x) || std::isinf(x) || !x)
502         return 0;
503
504     x = x < 0 ? -floor(fabs(x)) : floor(fabs(x));
505     x = fmod(x, LimitsTrait::numberOfValues);
506
507     return static_cast<T>(x > LimitsTrait::maxValue ? x - LimitsTrait::numberOfValues : x);
508 }
509
510 template <typename T>
511 static inline T toSmallerUInt(ExecState& state, JSValue value, IntegerConversionConfiguration configuration)
512 {
513     VM& vm = state.vm();
514     auto scope = DECLARE_THROW_SCOPE(vm);
515
516     static_assert(std::is_unsigned<T>::value && std::is_integral<T>::value, "Should only be used for unsigned integral types");
517
518     typedef IntTypeLimits<T> LimitsTrait;
519     // Fast path if the value is already a 32-bit unsigned integer in the right range.
520     if (value.isUInt32()) {
521         uint32_t d = value.asUInt32();
522         if (d <= LimitsTrait::maxValue)
523             return static_cast<T>(d);
524         switch (configuration) {
525         case IntegerConversionConfiguration::Normal:
526             return static_cast<T>(d);
527         case IntegerConversionConfiguration::EnforceRange:
528             throwTypeError(&state, scope);
529             return 0;
530         case IntegerConversionConfiguration::Clamp:
531             return LimitsTrait::maxValue;
532         }
533     }
534
535     double x = value.toNumber(&state);
536     RETURN_IF_EXCEPTION(scope, 0);
537
538     switch (configuration) {
539     case IntegerConversionConfiguration::Normal:
540         break;
541     case IntegerConversionConfiguration::EnforceRange:
542         return enforceRange(state, x, 0, LimitsTrait::maxValue);
543     case IntegerConversionConfiguration::Clamp:
544         return std::isnan(x) ? 0 : clampTo<T>(x);
545     }
546
547     if (std::isnan(x) || std::isinf(x) || !x)
548         return 0;
549
550     x = x < 0 ? -floor(fabs(x)) : floor(fabs(x));
551     return static_cast<T>(fmod(x, LimitsTrait::numberOfValues));
552 }
553
554 int8_t toInt8EnforceRange(JSC::ExecState& state, JSValue value)
555 {
556     return toSmallerInt<int8_t>(state, value, IntegerConversionConfiguration::EnforceRange);
557 }
558
559 uint8_t toUInt8EnforceRange(JSC::ExecState& state, JSValue value)
560 {
561     return toSmallerUInt<uint8_t>(state, value, IntegerConversionConfiguration::EnforceRange);
562 }
563
564 int8_t toInt8Clamp(JSC::ExecState& state, JSValue value)
565 {
566     return toSmallerInt<int8_t>(state, value, IntegerConversionConfiguration::Clamp);
567 }
568
569 uint8_t toUInt8Clamp(JSC::ExecState& state, JSValue value)
570 {
571     return toSmallerUInt<uint8_t>(state, value, IntegerConversionConfiguration::Clamp);
572 }
573
574 // http://www.w3.org/TR/WebIDL/#es-byte
575 int8_t toInt8(ExecState& state, JSValue value)
576 {
577     return toSmallerInt<int8_t>(state, value, IntegerConversionConfiguration::Normal);
578 }
579
580 // http://www.w3.org/TR/WebIDL/#es-octet
581 uint8_t toUInt8(ExecState& state, JSValue value)
582 {
583     return toSmallerUInt<uint8_t>(state, value, IntegerConversionConfiguration::Normal);
584 }
585
586 int16_t toInt16EnforceRange(ExecState& state, JSValue value)
587 {
588     return toSmallerInt<int16_t>(state, value, IntegerConversionConfiguration::EnforceRange);
589 }
590
591 uint16_t toUInt16EnforceRange(ExecState& state, JSValue value)
592 {
593     return toSmallerUInt<uint16_t>(state, value, IntegerConversionConfiguration::EnforceRange);
594 }
595
596 int16_t toInt16Clamp(ExecState& state, JSValue value)
597 {
598     return toSmallerInt<int16_t>(state, value, IntegerConversionConfiguration::Clamp);
599 }
600
601 uint16_t toUInt16Clamp(ExecState& state, JSValue value)
602 {
603     return toSmallerUInt<uint16_t>(state, value, IntegerConversionConfiguration::Clamp);
604 }
605
606 // http://www.w3.org/TR/WebIDL/#es-short
607 int16_t toInt16(ExecState& state, JSValue value)
608 {
609     return toSmallerInt<int16_t>(state, value, IntegerConversionConfiguration::Normal);
610 }
611
612 // http://www.w3.org/TR/WebIDL/#es-unsigned-short
613 uint16_t toUInt16(ExecState& state, JSValue value)
614 {
615     return toSmallerUInt<uint16_t>(state, value, IntegerConversionConfiguration::Normal);
616 }
617
618 // http://www.w3.org/TR/WebIDL/#es-long
619 int32_t toInt32EnforceRange(ExecState& state, JSValue value)
620 {
621     VM& vm = state.vm();
622     auto scope = DECLARE_THROW_SCOPE(vm);
623
624     if (value.isInt32())
625         return value.asInt32();
626
627     double x = value.toNumber(&state);
628     RETURN_IF_EXCEPTION(scope, 0);
629     return enforceRange(state, x, kMinInt32, kMaxInt32);
630 }
631
632 int32_t toInt32Clamp(ExecState& state, JSValue value)
633 {
634     if (value.isInt32())
635         return value.asInt32();
636
637     double x = value.toNumber(&state);
638     return std::isnan(x) ? 0 : clampTo<int32_t>(x);
639 }
640
641 uint32_t toUInt32Clamp(ExecState& state, JSValue value)
642 {
643     if (value.isUInt32())
644         return value.asUInt32();
645
646     double x = value.toNumber(&state);
647     return std::isnan(x) ? 0 : clampTo<uint32_t>(x);
648 }
649
650 // http://www.w3.org/TR/WebIDL/#es-unsigned-long
651 uint32_t toUInt32EnforceRange(ExecState& state, JSValue value)
652 {
653     VM& vm = state.vm();
654     auto scope = DECLARE_THROW_SCOPE(vm);
655
656     if (value.isUInt32())
657         return value.asUInt32();
658
659     double x = value.toNumber(&state);
660     RETURN_IF_EXCEPTION(scope, 0);
661     return enforceRange(state, x, 0, kMaxUInt32);
662 }
663
664 int64_t toInt64EnforceRange(ExecState& state, JSC::JSValue value)
665 {
666     VM& vm = state.vm();
667     auto scope = DECLARE_THROW_SCOPE(vm);
668
669     double x = value.toNumber(&state);
670     RETURN_IF_EXCEPTION(scope, 0);
671     return enforceRange(state, x, -kJSMaxInteger, kJSMaxInteger);
672 }
673
674 uint64_t toUInt64EnforceRange(ExecState& state, JSC::JSValue value)
675 {
676     VM& vm = state.vm();
677     auto scope = DECLARE_THROW_SCOPE(vm);
678
679     double x = value.toNumber(&state);
680     RETURN_IF_EXCEPTION(scope, 0);
681     return enforceRange(state, x, 0, kJSMaxInteger);
682 }
683
684 int64_t toInt64Clamp(ExecState& state, JSC::JSValue value)
685 {
686     double x = value.toNumber(&state);
687     return std::isnan(x) ? 0 : static_cast<int64_t>(std::min<double>(std::max<double>(x, -kJSMaxInteger), kJSMaxInteger));
688 }
689
690 uint64_t toUInt64Clamp(ExecState& state, JSC::JSValue value)
691 {
692     double x = value.toNumber(&state);
693     return std::isnan(x) ? 0 : static_cast<uint64_t>(std::min<double>(std::max<double>(x, 0), kJSMaxInteger));
694 }
695
696 // http://www.w3.org/TR/WebIDL/#es-long-long
697 int64_t toInt64(ExecState& state, JSValue value)
698 {
699     double x = value.toNumber(&state);
700
701     // Map NaNs and +/-Infinity to 0; convert finite values modulo 2^64.
702     unsigned long long n;
703     doubleToInteger(x, n);
704     return n;
705 }
706
707 // http://www.w3.org/TR/WebIDL/#es-unsigned-long-long
708 uint64_t toUInt64(ExecState& state, JSValue value)
709 {
710     double x = value.toNumber(&state);
711
712     // Map NaNs and +/-Infinity to 0; convert finite values modulo 2^64.
713     unsigned long long n;
714     doubleToInteger(x, n);
715     return n;
716 }
717
718 class GetCallerGlobalObjectFunctor {
719 public:
720     GetCallerGlobalObjectFunctor() = default;
721
722     StackVisitor::Status operator()(StackVisitor& visitor) const
723     {
724         if (!m_hasSkippedFirstFrame) {
725             m_hasSkippedFirstFrame = true;
726             return StackVisitor::Continue;
727         }
728
729         if (auto* codeBlock = visitor->codeBlock())
730             m_globalObject = codeBlock->globalObject();
731         else {
732             ASSERT(visitor->callee());
733             // FIXME: Callee is not an object if the caller is Web Assembly.
734             // Figure out what to do here. We can probably get the global object
735             // from the top-most Wasm Instance. https://bugs.webkit.org/show_bug.cgi?id=165721
736             if (visitor->callee()->isObject())
737                 m_globalObject = jsCast<JSObject*>(visitor->callee())->globalObject();
738         }
739         return StackVisitor::Done;
740     }
741
742     JSGlobalObject* globalObject() const { return m_globalObject; }
743
744 private:
745     mutable bool m_hasSkippedFirstFrame { false };
746     mutable JSGlobalObject* m_globalObject { nullptr };
747 };
748
749 DOMWindow& callerDOMWindow(ExecState* exec)
750 {
751     GetCallerGlobalObjectFunctor iter;
752     exec->iterate(iter);
753     return iter.globalObject() ? asJSDOMWindow(iter.globalObject())->wrapped() : firstDOMWindow(exec);
754 }
755
756 DOMWindow& activeDOMWindow(ExecState* exec)
757 {
758     return asJSDOMWindow(exec->lexicalGlobalObject())->wrapped();
759 }
760
761 DOMWindow& firstDOMWindow(ExecState* exec)
762 {
763     return asJSDOMWindow(exec->vmEntryGlobalObject())->wrapped();
764 }
765
766 static inline bool canAccessDocument(JSC::ExecState* state, Document* targetDocument, SecurityReportingOption reportingOption)
767 {
768     VM& vm = state->vm();
769     auto scope = DECLARE_THROW_SCOPE(vm);
770
771     if (!targetDocument)
772         return false;
773
774     DOMWindow& active = activeDOMWindow(state);
775
776     if (active.document()->securityOrigin().canAccess(targetDocument->securityOrigin()))
777         return true;
778
779     switch (reportingOption) {
780     case ThrowSecurityError:
781         throwSecurityError(*state, scope, targetDocument->domWindow()->crossDomainAccessErrorMessage(active));
782         break;
783     case LogSecurityError:
784         printErrorMessageForFrame(targetDocument->frame(), targetDocument->domWindow()->crossDomainAccessErrorMessage(active));
785         break;
786     case DoNotReportSecurityError:
787         break;
788     }
789
790     return false;
791 }
792
793 bool BindingSecurity::shouldAllowAccessToDOMWindow(JSC::ExecState* state, DOMWindow& target, SecurityReportingOption reportingOption)
794 {
795     return canAccessDocument(state, target.document(), reportingOption);
796 }
797
798 bool BindingSecurity::shouldAllowAccessToFrame(JSC::ExecState* state, Frame* target, SecurityReportingOption reportingOption)
799 {
800     return target && canAccessDocument(state, target->document(), reportingOption);
801 }
802
803 bool BindingSecurity::shouldAllowAccessToNode(JSC::ExecState& state, Node* target)
804 {
805     return !target || canAccessDocument(&state, &target->document(), LogSecurityError);
806 }
807     
808 static EncodedJSValue throwTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const String& errorMessage)
809 {
810     return throwVMTypeError(&state, scope, errorMessage);
811 }
812
813 static void appendArgumentMustBe(StringBuilder& builder, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName)
814 {
815     builder.appendLiteral("Argument ");
816     builder.appendNumber(argumentIndex + 1);
817     builder.appendLiteral(" ('");
818     builder.append(argumentName);
819     builder.appendLiteral("') to ");
820     if (!functionName) {
821         builder.appendLiteral("the ");
822         builder.append(interfaceName);
823         builder.appendLiteral(" constructor");
824     } else {
825         builder.append(interfaceName);
826         builder.append('.');
827         builder.append(functionName);
828     }
829     builder.appendLiteral(" must be ");
830 }
831
832 JSC::EncodedJSValue reportDeprecatedGetterError(JSC::ExecState& state, const char* interfaceName, const char* attributeName)
833 {
834     auto& context = *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())->scriptExecutionContext();
835     context.addConsoleMessage(MessageSource::JS, MessageLevel::Error, makeString("Deprecated attempt to access property '", attributeName, "' on a non-", interfaceName, " object."));
836     return JSValue::encode(jsUndefined());
837 }
838     
839 void reportDeprecatedSetterError(JSC::ExecState& state, const char* interfaceName, const char* attributeName)
840 {
841     auto& context = *jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())->scriptExecutionContext();
842     context.addConsoleMessage(MessageSource::JS, MessageLevel::Error, makeString("Deprecated attempt to set property '", attributeName, "' on a non-", interfaceName, " object."));
843 }
844
845 void throwNotSupportedError(JSC::ExecState& state, JSC::ThrowScope& scope)
846 {
847     ASSERT(!scope.exception());
848     throwException(&state, scope, createDOMException(&state, NOT_SUPPORTED_ERR));
849 }
850
851 void throwNotSupportedError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* message)
852 {
853     ASSERT(!scope.exception());
854     String messageString(message);
855     throwException(&state, scope, createDOMException(&state, NOT_SUPPORTED_ERR, &messageString));
856 }
857
858 void throwInvalidStateError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* message)
859 {
860     ASSERT(!scope.exception());
861     String messageString(message);
862     throwException(&state, scope, createDOMException(&state, INVALID_STATE_ERR, &messageString));
863 }
864
865 void throwSecurityError(JSC::ExecState& state, JSC::ThrowScope& scope, const String& message)
866 {
867     ASSERT(!scope.exception());
868     throwException(&state, scope, createDOMException(&state, SECURITY_ERR, message));
869 }
870
871 JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState& state, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues)
872 {
873     StringBuilder builder;
874     appendArgumentMustBe(builder, argumentIndex, argumentName, functionInterfaceName, functionName);
875     builder.appendLiteral("one of: ");
876     builder.append(expectedValues);
877     return throwVMTypeError(&state, scope, builder.toString());
878 }
879
880 JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState& state, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* interfaceName, const char* functionName)
881 {
882     StringBuilder builder;
883     appendArgumentMustBe(builder, argumentIndex, argumentName, interfaceName, functionName);
884     builder.appendLiteral("a function");
885     return throwVMTypeError(&state, scope, builder.toString());
886 }
887
888 JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType)
889 {
890     StringBuilder builder;
891     appendArgumentMustBe(builder, argumentIndex, argumentName, functionInterfaceName, functionName);
892     builder.appendLiteral("an instance of ");
893     builder.append(expectedType);
894     return throwVMTypeError(&state, scope, builder.toString());
895 }
896
897 void throwArrayElementTypeError(JSC::ExecState& state, JSC::ThrowScope& scope)
898 {
899     throwTypeError(state, scope, ASCIILiteral("Invalid Array element type"));
900 }
901
902 void throwAttributeTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName, const char* attributeName, const char* expectedType)
903 {
904     throwTypeError(state, scope, makeString("The ", interfaceName, '.', attributeName, " attribute must be an instance of ", expectedType));
905 }
906
907 JSC::EncodedJSValue throwRequiredMemberTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* memberName, const char* dictionaryName, const char* expectedType)
908 {
909     StringBuilder builder;
910     builder.appendLiteral("Member ");
911     builder.append(dictionaryName);
912     builder.append('.');
913     builder.append(memberName);
914     builder.appendLiteral(" is required and must be an instance of ");
915     builder.append(expectedType);
916     return throwVMTypeError(&state, scope, builder.toString());
917 }
918
919 JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName)
920 {
921     return throwVMError(&state, scope, createReferenceError(&state, makeString(interfaceName, " constructor associated execution context is unavailable")));
922 }
923
924 void throwSequenceTypeError(JSC::ExecState& state, JSC::ThrowScope& scope)
925 {
926     throwTypeError(state, scope, ASCIILiteral("Value is not a sequence"));
927 }
928
929 void throwNonFiniteTypeError(ExecState& state, JSC::ThrowScope& scope)
930 {
931     throwTypeError(&state, scope, ASCIILiteral("The provided value is non-finite"));
932 }
933
934 String makeGetterTypeErrorMessage(const char* interfaceName, const char* attributeName)
935 {
936     return makeString("The ", interfaceName, '.', attributeName, " getter can only be used on instances of ", interfaceName);
937 }
938
939 JSC::EncodedJSValue throwGetterTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName, const char* attributeName)
940 {
941     return throwVMTypeError(&state, scope, makeGetterTypeErrorMessage(interfaceName, attributeName));
942 }
943
944 JSC::EncodedJSValue rejectPromiseWithGetterTypeError(JSC::ExecState& state, const char* interfaceName, const char* attributeName)
945 {
946     return createRejectedPromiseWithTypeError(state, makeGetterTypeErrorMessage(interfaceName, attributeName));
947 }
948
949 bool throwSetterTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName, const char* attributeName)
950 {
951     throwTypeError(state, scope, makeString("The ", interfaceName, '.', attributeName, " setter can only be used on instances of ", interfaceName));
952     return false;
953 }
954
955 String makeThisTypeErrorMessage(const char* interfaceName, const char* functionName)
956 {
957     return makeString("Can only call ", interfaceName, '.', functionName, " on instances of ", interfaceName);
958 }
959
960 EncodedJSValue throwThisTypeError(JSC::ExecState& state, JSC::ThrowScope& scope, const char* interfaceName, const char* functionName)
961 {
962     return throwTypeError(state, scope, makeThisTypeErrorMessage(interfaceName, functionName));
963 }
964
965 JSC::EncodedJSValue rejectPromiseWithThisTypeError(DeferredPromise& promise, const char* interfaceName, const char* methodName)
966 {
967     promise.reject(TypeError, makeThisTypeErrorMessage(interfaceName, methodName));
968     return JSValue::encode(jsUndefined());
969 }
970
971 JSC::EncodedJSValue rejectPromiseWithThisTypeError(JSC::ExecState& state, const char* interfaceName, const char* methodName)
972 {
973     return createRejectedPromiseWithTypeError(state, makeThisTypeErrorMessage(interfaceName, methodName));
974 }
975
976 void callFunctionWithCurrentArguments(JSC::ExecState& state, JSC::JSObject& thisObject, JSC::JSFunction& function)
977 {
978     JSC::CallData callData;
979     JSC::CallType callType = JSC::getCallData(&function, callData);
980     ASSERT(callType != CallType::None);
981
982     JSC::MarkedArgumentBuffer arguments;
983     for (unsigned i = 0; i < state.argumentCount(); ++i)
984         arguments.append(state.uncheckedArgument(i));
985     JSC::call(&state, &function, callType, callData, &thisObject, arguments);
986 }
987
988 void DOMConstructorJSBuiltinObject::visitChildren(JSC::JSCell* cell, JSC::SlotVisitor& visitor)
989 {
990     auto* thisObject = jsCast<DOMConstructorJSBuiltinObject*>(cell);
991     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
992     Base::visitChildren(thisObject, visitor);
993     visitor.append(thisObject->m_initializeFunction);
994 }
995
996 static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec)
997 {
998     VM& vm = exec->vm();
999     auto scope = DECLARE_THROW_SCOPE(vm);
1000     throwTypeError(exec, scope, ASCIILiteral("Constructor requires 'new' operator"));
1001     return JSValue::encode(jsNull());
1002 }
1003
1004 CallType DOMConstructorObject::getCallData(JSCell*, CallData& callData)
1005 {
1006     callData.native.function = callThrowTypeError;
1007     return CallType::Host;
1008 }
1009
1010 void throwDOMSyntaxError(JSC::ExecState& state, JSC::ThrowScope& scope)
1011 {
1012     ASSERT(!scope.exception());
1013     throwException(&state, scope, createDOMException(&state, SYNTAX_ERR));
1014 }
1015
1016 void throwDataCloneError(JSC::ExecState& state, JSC::ThrowScope& scope)
1017 {
1018     ASSERT(!scope.exception());
1019     throwException(&state, scope, createDOMException(&state, DATA_CLONE_ERR));
1020 }
1021
1022 void throwIndexSizeError(JSC::ExecState& state, JSC::ThrowScope& scope)
1023 {
1024     ASSERT(!scope.exception());
1025     throwException(&state, scope, createDOMException(&state, INDEX_SIZE_ERR));
1026 }
1027
1028 void throwTypeMismatchError(JSC::ExecState& state, JSC::ThrowScope& scope)
1029 {
1030     ASSERT(!scope.exception());
1031     throwException(&state, scope, createDOMException(&state, TYPE_MISMATCH_ERR));
1032 }
1033
1034 } // namespace WebCore