JSC should infer when indexed storage contains only integers or doubles
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMBinding.cpp
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "config.h"
22 #include "JSDOMBinding.h"
23
24 #include "BindingSecurity.h"
25 #include "DOMObjectHashTableMap.h"
26 #include "DOMStringList.h"
27 #include "ExceptionCode.h"
28 #include "ExceptionHeaders.h"
29 #include "ExceptionInterfaces.h"
30 #include "Frame.h"
31 #include "JSDOMWindowCustom.h"
32 #include "JSExceptionBase.h"
33 #include "ScriptCallStack.h"
34 #include <interpreter/Interpreter.h>
35 #include <runtime/DateInstance.h>
36 #include <runtime/Error.h>
37 #include <runtime/ExceptionHelpers.h>
38 #include <runtime/JSFunction.h>
39
40 using namespace JSC;
41
42 namespace WebCore {
43
44 ASSERT_HAS_TRIVIAL_DESTRUCTOR(DOMConstructorObject);
45 ASSERT_HAS_TRIVIAL_DESTRUCTOR(DOMConstructorWithDocument);
46
47 const JSC::HashTable* getHashTableForGlobalData(JSGlobalData& globalData, const JSC::HashTable* staticTable)
48 {
49     return DOMObjectHashTableMap::mapFor(globalData).get(staticTable);
50 }
51
52 JSValue jsStringWithCacheSlowCase(ExecState* exec, JSStringCache& stringCache, StringImpl* stringImpl)
53 {
54     JSString* wrapper = JSC::jsString(exec, String(stringImpl));
55     weakAdd(stringCache, stringImpl, PassWeak<JSString>(wrapper, currentWorld(exec)->stringWrapperOwner(), stringImpl));
56     return wrapper;
57 }
58
59 JSValue jsStringOrNull(ExecState* exec, const String& s)
60 {
61     if (s.isNull())
62         return jsNull();
63     return jsStringWithCache(exec, s);
64 }
65
66 JSValue jsOwnedStringOrNull(ExecState* exec, const String& s)
67 {
68     if (s.isNull())
69         return jsNull();
70     return jsOwnedString(exec, s);
71 }
72
73 JSValue jsStringOrUndefined(ExecState* exec, const String& s)
74 {
75     if (s.isNull())
76         return jsUndefined();
77     return jsStringWithCache(exec, s);
78 }
79
80 JSValue jsString(ExecState* exec, const KURL& url)
81 {
82     return jsStringWithCache(exec, url.string());
83 }
84
85 JSValue jsStringOrNull(ExecState* exec, const KURL& url)
86 {
87     if (url.isNull())
88         return jsNull();
89     return jsStringWithCache(exec, url.string());
90 }
91
92 JSValue jsStringOrUndefined(ExecState* exec, const KURL& url)
93 {
94     if (url.isNull())
95         return jsUndefined();
96     return jsStringWithCache(exec, url.string());
97 }
98
99 AtomicStringImpl* findAtomicString(PropertyName propertyName)
100 {
101     StringImpl* impl = propertyName.publicName();
102     if (!impl)
103         return 0;
104     ASSERT(impl->existingHash());
105     return AtomicString::find(impl);
106 }
107
108 String valueToStringWithNullCheck(ExecState* exec, JSValue value)
109 {
110     if (value.isNull())
111         return String();
112     return value.toString(exec)->value(exec);
113 }
114
115 String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value)
116 {
117     if (value.isUndefinedOrNull())
118         return String();
119     return value.toString(exec)->value(exec);
120 }
121
122 JSValue jsDateOrNull(ExecState* exec, double value)
123 {
124     if (!isfinite(value))
125         return jsNull();
126     return DateInstance::create(exec, exec->lexicalGlobalObject()->dateStructure(), value);
127 }
128
129 double valueToDate(ExecState* exec, JSValue value)
130 {
131     if (value.isNumber())
132         return value.asNumber();
133     if (!value.inherits(&DateInstance::s_info))
134         return std::numeric_limits<double>::quiet_NaN();
135     return static_cast<DateInstance*>(value.toObject(exec))->internalNumber();
136 }
137
138 JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<DOMStringList> stringList)
139 {
140     JSC::MarkedArgumentBuffer list;
141     if (stringList) {
142         for (unsigned i = 0; i < stringList->length(); ++i)
143             list.append(jsStringWithCache(exec, stringList->item(i)));
144     }
145     return JSC::constructArray(exec, 0, globalObject, list);
146 }
147
148 void reportException(ExecState* exec, JSValue exception)
149 {
150     if (isTerminatedExecutionException(exception))
151         return;
152
153     Interpreter::ErrorHandlingMode mode(exec);
154     String errorMessage = exception.toString(exec)->value(exec);
155     JSObject* exceptionObject = exception.toObject(exec);
156     int lineNumber = exceptionObject->get(exec, Identifier(exec, "line")).toInt32(exec);
157     String exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL")).toString(exec)->value(exec);
158     exec->clearException();
159
160     if (ExceptionBase* exceptionBase = toExceptionBase(exception))
161         errorMessage = exceptionBase->message() + ": "  + exceptionBase->description();
162
163     JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
164     if (JSDOMWindow* window = jsDynamicCast<JSDOMWindow*>(globalObject)) {
165         if (!window->impl()->isCurrentlyDisplayedInFrame())
166             return;
167     }
168     ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext();
169     scriptExecutionContext->reportException(errorMessage, lineNumber, exceptionSourceURL, 0);
170 }
171
172 void reportCurrentException(ExecState* exec)
173 {
174     JSValue exception = exec->exception();
175     exec->clearException();
176     reportException(exec, exception);
177 }
178
179 #define TRY_TO_CREATE_EXCEPTION(interfaceName) \
180     case interfaceName##Type: \
181         errorObject = toJS(exec, globalObject, interfaceName::create(description)); \
182         break;
183
184 void setDOMException(ExecState* exec, ExceptionCode ec)
185 {
186     if (!ec || exec->hadException())
187         return;
188
189     if (ec == NATIVE_TYPE_ERR) {
190         throwTypeError(exec);
191         return;
192     }
193
194     // FIXME: All callers to setDOMException need to pass in the right global object
195     // for now, we're going to assume the lexicalGlobalObject.  Which is wrong in cases like this:
196     // frames[0].document.createElement(null, null); // throws an exception which should have the subframes prototypes.
197     JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec);
198
199     ExceptionCodeDescription description(ec);
200
201     JSValue errorObject;
202     switch (description.type) {
203         DOM_EXCEPTION_INTERFACES_FOR_EACH(TRY_TO_CREATE_EXCEPTION)
204     }
205
206     ASSERT(errorObject);
207     throwError(exec, errorObject);
208 }
209
210 #undef TRY_TO_CREATE_EXCEPTION
211
212 bool shouldAllowAccessToNode(ExecState* exec, Node* node)
213 {
214     return BindingSecurity::shouldAllowAccessToNode(exec, node);
215 }
216
217 bool shouldAllowAccessToFrame(ExecState* exec, Frame* target)
218 {
219     return BindingSecurity::shouldAllowAccessToFrame(exec, target);
220 }
221
222 bool shouldAllowAccessToFrame(ExecState* exec, Frame* frame, String& message)
223 {
224     if (!frame)
225         return false;
226     if (BindingSecurity::shouldAllowAccessToFrame(exec, frame, DoNotReportSecurityError))
227         return true;
228     message = frame->document()->domWindow()->crossDomainAccessErrorMessage(activeDOMWindow(exec));
229     return false;
230 }
231
232 bool shouldAllowAccessToDOMWindow(ExecState* exec, DOMWindow* target, String& message)
233 {
234     if (!target)
235         return false;
236     if (BindingSecurity::shouldAllowAccessToDOMWindow(exec, target, DoNotReportSecurityError))
237         return true;
238     message = target->crossDomainAccessErrorMessage(activeDOMWindow(exec));
239     return false;
240 }
241
242 void printErrorMessageForFrame(Frame* frame, const String& message)
243 {
244     if (!frame)
245         return;
246     frame->document()->domWindow()->printErrorMessage(message);
247 }
248
249 JSValue objectToStringFunctionGetter(ExecState* exec, JSValue, PropertyName propertyName)
250 {
251     return JSFunction::create(exec, exec->lexicalGlobalObject(), 0, propertyName.publicName(), objectProtoFuncToString);
252 }
253
254 Structure* getCachedDOMStructure(JSDOMGlobalObject* globalObject, const ClassInfo* classInfo)
255 {
256     JSDOMStructureMap& structures = globalObject->structures();
257     return structures.get(classInfo).get();
258 }
259
260 Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, Structure* structure, const ClassInfo* classInfo)
261 {
262     JSDOMStructureMap& structures = globalObject->structures();
263     ASSERT(!structures.contains(classInfo));
264     return structures.set(classInfo, WriteBarrier<Structure>(globalObject->globalData(), globalObject, structure)).iterator->value.get();
265 }
266
267 } // namespace WebCore