OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright | |
11 * notice, this list of conditions and the following disclaimer in the | |
12 * documentation and/or other materials provided with the distribution. | |
13 * | |
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 */ | |
25 | |
26 #include "config.h" | |
27 #include "bindings/v8/IDBBindingUtilities.h" | |
28 | |
29 #include "bindings/core/v8/V8DOMStringList.h" | |
30 #include "bindings/core/v8/custom/V8ArrayBufferViewCustom.h" | |
31 #include "bindings/core/v8/custom/V8Uint8ArrayCustom.h" | |
32 #include "bindings/modules/v8/V8IDBCursor.h" | |
33 #include "bindings/modules/v8/V8IDBCursorWithValue.h" | |
34 #include "bindings/modules/v8/V8IDBDatabase.h" | |
35 #include "bindings/modules/v8/V8IDBIndex.h" | |
36 #include "bindings/modules/v8/V8IDBKeyRange.h" | |
37 #include "bindings/modules/v8/V8IDBObjectStore.h" | |
38 #include "bindings/modules/v8/V8IDBRequest.h" | |
39 #include "bindings/modules/v8/V8IDBTransaction.h" | |
40 #include "bindings/v8/SerializedScriptValue.h" | |
41 #include "bindings/v8/V8Binding.h" | |
42 #include "bindings/v8/V8HiddenValue.h" | |
43 #include "modules/indexeddb/IDBKey.h" | |
44 #include "modules/indexeddb/IDBKeyPath.h" | |
45 #include "modules/indexeddb/IDBKeyRange.h" | |
46 #include "modules/indexeddb/IDBTracing.h" | |
47 #include "platform/RuntimeEnabledFeatures.h" | |
48 #include "platform/SharedBuffer.h" | |
49 #include "wtf/ArrayBufferView.h" | |
50 #include "wtf/MathExtras.h" | |
51 #include "wtf/Uint8Array.h" | |
52 #include "wtf/Vector.h" | |
53 | |
54 namespace WebCore { | |
55 | |
56 static v8::Handle<v8::Value> deserializeIDBValueBuffer(v8::Isolate*, SharedBuffe
r*, const Vector<blink::WebBlobInfo>*); | |
57 | |
58 static v8::Handle<v8::Value> toV8(const IDBKeyPath& value, v8::Handle<v8::Object
> creationContext, v8::Isolate* isolate) | |
59 { | |
60 switch (value.type()) { | |
61 case IDBKeyPath::NullType: | |
62 return v8::Null(isolate); | |
63 case IDBKeyPath::StringType: | |
64 return v8String(isolate, value.string()); | |
65 case IDBKeyPath::ArrayType: | |
66 RefPtrWillBeRawPtr<DOMStringList> keyPaths = DOMStringList::create(); | |
67 for (Vector<String>::const_iterator it = value.array().begin(); it != va
lue.array().end(); ++it) | |
68 keyPaths->append(*it); | |
69 return toV8(keyPaths.release(), creationContext, isolate); | |
70 } | |
71 ASSERT_NOT_REACHED(); | |
72 return v8::Undefined(isolate); | |
73 } | |
74 | |
75 static v8::Handle<v8::Value> toV8(const IDBKey* key, v8::Handle<v8::Object> crea
tionContext, v8::Isolate* isolate) | |
76 { | |
77 if (!key) { | |
78 // This should be undefined, not null. | |
79 // Spec: http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-
def-IDBKeyRange | |
80 return v8Undefined(); | |
81 } | |
82 | |
83 switch (key->type()) { | |
84 case IDBKey::InvalidType: | |
85 case IDBKey::MinType: | |
86 ASSERT_NOT_REACHED(); | |
87 return v8Undefined(); | |
88 case IDBKey::NumberType: | |
89 return v8::Number::New(isolate, key->number()); | |
90 case IDBKey::StringType: | |
91 return v8String(isolate, key->string()); | |
92 case IDBKey::BinaryType: | |
93 return toV8(Uint8Array::create(reinterpret_cast<const unsigned char*>(ke
y->binary()->data()), key->binary()->size()), creationContext, isolate); | |
94 case IDBKey::DateType: | |
95 return v8::Date::New(isolate, key->date()); | |
96 case IDBKey::ArrayType: | |
97 { | |
98 v8::Local<v8::Array> array = v8::Array::New(isolate, key->array().si
ze()); | |
99 for (size_t i = 0; i < key->array().size(); ++i) | |
100 array->Set(i, toV8(key->array()[i].get(), creationContext, isola
te)); | |
101 return array; | |
102 } | |
103 } | |
104 | |
105 ASSERT_NOT_REACHED(); | |
106 return v8Undefined(); | |
107 } | |
108 | |
109 static v8::Handle<v8::Value> toV8(const IDBAny* impl, v8::Handle<v8::Object> cre
ationContext, v8::Isolate* isolate) | |
110 { | |
111 if (!impl) | |
112 return v8::Null(isolate); | |
113 | |
114 switch (impl->type()) { | |
115 case IDBAny::UndefinedType: | |
116 return v8::Undefined(isolate); | |
117 case IDBAny::NullType: | |
118 return v8::Null(isolate); | |
119 case IDBAny::DOMStringListType: | |
120 return toV8(impl->domStringList(), creationContext, isolate); | |
121 case IDBAny::IDBCursorType: { | |
122 // Ensure request wrapper is kept alive at least as long as the cursor w
rapper, | |
123 // so that event listeners are retained. | |
124 v8::Handle<v8::Value> cursor = toV8(impl->idbCursor(), creationContext,
isolate); | |
125 v8::Handle<v8::Value> request = toV8(impl->idbCursor()->request(), creat
ionContext, isolate); | |
126 V8HiddenValue::setHiddenValue(isolate, cursor->ToObject(), V8HiddenValue
::idbCursorRequest(isolate), request); | |
127 return cursor; | |
128 } | |
129 case IDBAny::IDBCursorWithValueType: { | |
130 // Ensure request wrapper is kept alive at least as long as the cursor w
rapper, | |
131 // so that event listeners are retained. | |
132 v8::Handle<v8::Value> cursor = toV8(impl->idbCursorWithValue(), creation
Context, isolate); | |
133 v8::Handle<v8::Value> request = toV8(impl->idbCursorWithValue()->request
(), creationContext, isolate); | |
134 V8HiddenValue::setHiddenValue(isolate, cursor->ToObject(), V8HiddenValue
::idbCursorRequest(isolate), request); | |
135 return cursor; | |
136 } | |
137 case IDBAny::IDBDatabaseType: | |
138 return toV8(impl->idbDatabase(), creationContext, isolate); | |
139 case IDBAny::IDBIndexType: | |
140 return toV8(impl->idbIndex(), creationContext, isolate); | |
141 case IDBAny::IDBObjectStoreType: | |
142 return toV8(impl->idbObjectStore(), creationContext, isolate); | |
143 case IDBAny::IDBTransactionType: | |
144 return toV8(impl->idbTransaction(), creationContext, isolate); | |
145 case IDBAny::BufferType: | |
146 return deserializeIDBValueBuffer(isolate, impl->buffer(), impl->blobInfo
()); | |
147 case IDBAny::StringType: | |
148 return v8String(isolate, impl->string()); | |
149 case IDBAny::IntegerType: | |
150 return v8::Number::New(isolate, impl->integer()); | |
151 case IDBAny::KeyType: | |
152 return toV8(impl->key(), creationContext, isolate); | |
153 case IDBAny::KeyPathType: | |
154 return toV8(impl->keyPath(), creationContext, isolate); | |
155 case IDBAny::BufferKeyAndKeyPathType: { | |
156 v8::Handle<v8::Value> value = deserializeIDBValueBuffer(isolate, impl->b
uffer(), impl->blobInfo()); | |
157 v8::Handle<v8::Value> key = toV8(impl->key(), creationContext, isolate); | |
158 bool injected = injectV8KeyIntoV8Value(isolate, key, value, impl->keyPat
h()); | |
159 ASSERT_UNUSED(injected, injected); | |
160 return value; | |
161 } | |
162 } | |
163 | |
164 ASSERT_NOT_REACHED(); | |
165 return v8::Undefined(isolate); | |
166 } | |
167 | |
168 static const size_t maximumDepth = 2000; | |
169 | |
170 static IDBKey* createIDBKeyFromValue(v8::Isolate* isolate, v8::Handle<v8::Value>
value, Vector<v8::Handle<v8::Array> >& stack, bool allowExperimentalTypes = fal
se) | |
171 { | |
172 if (value->IsNumber() && !std::isnan(value->NumberValue())) | |
173 return IDBKey::createNumber(value->NumberValue()); | |
174 if (value->IsString()) | |
175 return IDBKey::createString(toCoreString(value.As<v8::String>())); | |
176 if (value->IsDate() && !std::isnan(value->NumberValue())) | |
177 return IDBKey::createDate(value->NumberValue()); | |
178 if (value->IsUint8Array() && (allowExperimentalTypes || RuntimeEnabledFeatur
es::indexedDBExperimentalEnabled())) { | |
179 // Per discussion in https://www.w3.org/Bugs/Public/show_bug.cgi?id=2333
2 the | |
180 // input type is constrained to Uint8Array to match the output type. | |
181 ArrayBufferView* view = WebCore::V8ArrayBufferView::toNative(value->ToOb
ject()); | |
182 const char* start = static_cast<const char*>(view->baseAddress()); | |
183 size_t length = view->byteLength(); | |
184 return IDBKey::createBinary(SharedBuffer::create(start, length)); | |
185 } | |
186 if (value->IsArray()) { | |
187 v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value); | |
188 | |
189 if (stack.contains(array)) | |
190 return 0; | |
191 if (stack.size() >= maximumDepth) | |
192 return 0; | |
193 stack.append(array); | |
194 | |
195 IDBKey::KeyArray subkeys; | |
196 uint32_t length = array->Length(); | |
197 for (uint32_t i = 0; i < length; ++i) { | |
198 v8::Local<v8::Value> item = array->Get(v8::Int32::New(isolate, i)); | |
199 IDBKey* subkey = createIDBKeyFromValue(isolate, item, stack, allowEx
perimentalTypes); | |
200 if (!subkey) | |
201 subkeys.append(IDBKey::createInvalid()); | |
202 else | |
203 subkeys.append(subkey); | |
204 } | |
205 | |
206 stack.removeLast(); | |
207 return IDBKey::createArray(subkeys); | |
208 } | |
209 return 0; | |
210 } | |
211 | |
212 static IDBKey* createIDBKeyFromValue(v8::Isolate* isolate, v8::Handle<v8::Value>
value, bool allowExperimentalTypes = false) | |
213 { | |
214 Vector<v8::Handle<v8::Array> > stack; | |
215 if (IDBKey* key = createIDBKeyFromValue(isolate, value, stack, allowExperime
ntalTypes)) | |
216 return key; | |
217 return IDBKey::createInvalid(); | |
218 } | |
219 | |
220 template<typename T> | |
221 static bool getValueFrom(T indexOrName, v8::Handle<v8::Value>& v8Value) | |
222 { | |
223 v8::Local<v8::Object> object = v8Value->ToObject(); | |
224 if (!object->Has(indexOrName)) | |
225 return false; | |
226 v8Value = object->Get(indexOrName); | |
227 return true; | |
228 } | |
229 | |
230 template<typename T> | |
231 static bool setValue(v8::Handle<v8::Value>& v8Object, T indexOrName, const v8::H
andle<v8::Value>& v8Value) | |
232 { | |
233 v8::Local<v8::Object> object = v8Object->ToObject(); | |
234 return object->Set(indexOrName, v8Value); | |
235 } | |
236 | |
237 static bool get(v8::Isolate* isolate, v8::Handle<v8::Value>& object, const Strin
g& keyPathElement, v8::Handle<v8::Value>& result) | |
238 { | |
239 if (object->IsString() && keyPathElement == "length") { | |
240 int32_t length = v8::Handle<v8::String>::Cast(object)->Length(); | |
241 result = v8::Number::New(isolate, length); | |
242 return true; | |
243 } | |
244 return object->IsObject() && getValueFrom(v8String(isolate, keyPathElement),
result); | |
245 } | |
246 | |
247 static bool canSet(v8::Handle<v8::Value>& object, const String& keyPathElement) | |
248 { | |
249 return object->IsObject(); | |
250 } | |
251 | |
252 static bool set(v8::Isolate* isolate, v8::Handle<v8::Value>& object, const Strin
g& keyPathElement, const v8::Handle<v8::Value>& v8Value) | |
253 { | |
254 return canSet(object, keyPathElement) && setValue(object, v8String(isolate,
keyPathElement), v8Value); | |
255 } | |
256 | |
257 static v8::Handle<v8::Value> getNthValueOnKeyPath(v8::Isolate* isolate, v8::Hand
le<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index) | |
258 { | |
259 v8::Handle<v8::Value> currentValue(rootValue); | |
260 ASSERT(index <= keyPathElements.size()); | |
261 for (size_t i = 0; i < index; ++i) { | |
262 v8::Handle<v8::Value> parentValue(currentValue); | |
263 if (!get(isolate, parentValue, keyPathElements[i], currentValue)) | |
264 return v8Undefined(); | |
265 } | |
266 | |
267 return currentValue; | |
268 } | |
269 | |
270 static bool canInjectNthValueOnKeyPath(v8::Isolate* isolate, v8::Handle<v8::Valu
e>& rootValue, const Vector<String>& keyPathElements, size_t index) | |
271 { | |
272 if (!rootValue->IsObject()) | |
273 return false; | |
274 | |
275 v8::Handle<v8::Value> currentValue(rootValue); | |
276 | |
277 ASSERT(index <= keyPathElements.size()); | |
278 for (size_t i = 0; i < index; ++i) { | |
279 v8::Handle<v8::Value> parentValue(currentValue); | |
280 const String& keyPathElement = keyPathElements[i]; | |
281 if (!get(isolate, parentValue, keyPathElement, currentValue)) | |
282 return canSet(parentValue, keyPathElement); | |
283 } | |
284 return true; | |
285 } | |
286 | |
287 | |
288 static v8::Handle<v8::Value> ensureNthValueOnKeyPath(v8::Isolate* isolate, v8::H
andle<v8::Value>& rootValue, const Vector<String>& keyPathElements, size_t index
) | |
289 { | |
290 v8::Handle<v8::Value> currentValue(rootValue); | |
291 | |
292 ASSERT(index <= keyPathElements.size()); | |
293 for (size_t i = 0; i < index; ++i) { | |
294 v8::Handle<v8::Value> parentValue(currentValue); | |
295 const String& keyPathElement = keyPathElements[i]; | |
296 if (!get(isolate, parentValue, keyPathElement, currentValue)) { | |
297 v8::Handle<v8::Object> object = v8::Object::New(isolate); | |
298 if (!set(isolate, parentValue, keyPathElement, object)) | |
299 return v8Undefined(); | |
300 currentValue = object; | |
301 } | |
302 } | |
303 | |
304 return currentValue; | |
305 } | |
306 | |
307 static IDBKey* createIDBKeyFromScriptValueAndKeyPathInternal(v8::Isolate* isolat
e, const ScriptValue& value, const String& keyPath, bool allowExperimentalTypes) | |
308 { | |
309 Vector<String> keyPathElements; | |
310 IDBKeyPathParseError error; | |
311 IDBParseKeyPath(keyPath, keyPathElements, error); | |
312 ASSERT(error == IDBKeyPathParseErrorNone); | |
313 ASSERT(isolate->InContext()); | |
314 | |
315 v8::HandleScope handleScope(isolate); | |
316 v8::Handle<v8::Value> v8Value(value.v8Value()); | |
317 v8::Handle<v8::Value> v8Key(getNthValueOnKeyPath(isolate, v8Value, keyPathEl
ements, keyPathElements.size())); | |
318 if (v8Key.IsEmpty()) | |
319 return 0; | |
320 return createIDBKeyFromValue(isolate, v8Key, allowExperimentalTypes); | |
321 } | |
322 | |
323 static IDBKey* createIDBKeyFromScriptValueAndKeyPathInternal(v8::Isolate* isolat
e, const ScriptValue& value, const IDBKeyPath& keyPath, bool allowExperimentalTy
pes = false) | |
324 { | |
325 ASSERT(!keyPath.isNull()); | |
326 v8::HandleScope handleScope(isolate); | |
327 if (keyPath.type() == IDBKeyPath::ArrayType) { | |
328 IDBKey::KeyArray result; | |
329 const Vector<String>& array = keyPath.array(); | |
330 for (size_t i = 0; i < array.size(); ++i) { | |
331 IDBKey* key = createIDBKeyFromScriptValueAndKeyPathInternal(isolate,
value, array[i], allowExperimentalTypes); | |
332 if (!key) | |
333 return 0; | |
334 result.append(key); | |
335 } | |
336 return IDBKey::createArray(result); | |
337 } | |
338 | |
339 ASSERT(keyPath.type() == IDBKeyPath::StringType); | |
340 return createIDBKeyFromScriptValueAndKeyPathInternal(isolate, value, keyPath
.string(), allowExperimentalTypes); | |
341 } | |
342 | |
343 IDBKey* createIDBKeyFromScriptValueAndKeyPath(v8::Isolate* isolate, const Script
Value& value, const IDBKeyPath& keyPath) | |
344 { | |
345 IDB_TRACE("createIDBKeyFromScriptValueAndKeyPath"); | |
346 return createIDBKeyFromScriptValueAndKeyPathInternal(isolate, value, keyPath
); | |
347 } | |
348 | |
349 static v8::Handle<v8::Value> deserializeIDBValueBuffer(v8::Isolate* isolate, Sha
redBuffer* buffer, const Vector<blink::WebBlobInfo>* blobInfo) | |
350 { | |
351 ASSERT(isolate->InContext()); | |
352 if (!buffer) | |
353 return v8::Null(isolate); | |
354 | |
355 // FIXME: The extra copy here can be eliminated by allowing SerializedScript
Value to take a raw const char* or const uint8_t*. | |
356 Vector<uint8_t> value; | |
357 value.append(buffer->data(), buffer->size()); | |
358 RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::creat
eFromWireBytes(value); | |
359 return serializedValue->deserialize(isolate, 0, blobInfo); | |
360 } | |
361 | |
362 bool injectV8KeyIntoV8Value(v8::Isolate* isolate, v8::Handle<v8::Value> key, v8:
:Handle<v8::Value> value, const IDBKeyPath& keyPath) | |
363 { | |
364 IDB_TRACE("injectIDBV8KeyIntoV8Value"); | |
365 ASSERT(isolate->InContext()); | |
366 | |
367 ASSERT(keyPath.type() == IDBKeyPath::StringType); | |
368 Vector<String> keyPathElements; | |
369 IDBKeyPathParseError error; | |
370 IDBParseKeyPath(keyPath.string(), keyPathElements, error); | |
371 ASSERT(error == IDBKeyPathParseErrorNone); | |
372 | |
373 if (!keyPathElements.size()) | |
374 return false; | |
375 | |
376 v8::HandleScope handleScope(isolate); | |
377 v8::Handle<v8::Value> parent(ensureNthValueOnKeyPath(isolate, value, keyPath
Elements, keyPathElements.size() - 1)); | |
378 if (parent.IsEmpty()) | |
379 return false; | |
380 | |
381 if (!set(isolate, parent, keyPathElements.last(), key)) | |
382 return false; | |
383 | |
384 return true; | |
385 } | |
386 | |
387 bool canInjectIDBKeyIntoScriptValue(v8::Isolate* isolate, const ScriptValue& scr
iptValue, const IDBKeyPath& keyPath) | |
388 { | |
389 IDB_TRACE("canInjectIDBKeyIntoScriptValue"); | |
390 ASSERT(keyPath.type() == IDBKeyPath::StringType); | |
391 Vector<String> keyPathElements; | |
392 IDBKeyPathParseError error; | |
393 IDBParseKeyPath(keyPath.string(), keyPathElements, error); | |
394 ASSERT(error == IDBKeyPathParseErrorNone); | |
395 | |
396 if (!keyPathElements.size()) | |
397 return false; | |
398 | |
399 v8::Handle<v8::Value> v8Value(scriptValue.v8Value()); | |
400 return canInjectNthValueOnKeyPath(isolate, v8Value, keyPathElements, keyPath
Elements.size() - 1); | |
401 } | |
402 | |
403 ScriptValue idbAnyToScriptValue(ScriptState* scriptState, IDBAny* any) | |
404 { | |
405 v8::Isolate* isolate = scriptState->isolate(); | |
406 v8::HandleScope handleScope(isolate); | |
407 v8::Handle<v8::Value> v8Value(toV8(any, scriptState->context()->Global(), is
olate)); | |
408 return ScriptValue(scriptState, v8Value); | |
409 } | |
410 | |
411 ScriptValue idbKeyToScriptValue(ScriptState* scriptState, IDBKey* key) | |
412 { | |
413 v8::Isolate* isolate = scriptState->isolate(); | |
414 v8::HandleScope handleScope(isolate); | |
415 v8::Handle<v8::Value> v8Value(toV8(key, scriptState->context()->Global(), is
olate)); | |
416 return ScriptValue(scriptState, v8Value); | |
417 } | |
418 | |
419 IDBKey* scriptValueToIDBKey(v8::Isolate* isolate, const ScriptValue& scriptValue
) | |
420 { | |
421 ASSERT(isolate->InContext()); | |
422 v8::HandleScope handleScope(isolate); | |
423 v8::Handle<v8::Value> v8Value(scriptValue.v8Value()); | |
424 return createIDBKeyFromValue(isolate, v8Value); | |
425 } | |
426 | |
427 IDBKeyRange* scriptValueToIDBKeyRange(v8::Isolate* isolate, const ScriptValue& s
criptValue) | |
428 { | |
429 v8::HandleScope handleScope(isolate); | |
430 v8::Handle<v8::Value> value(scriptValue.v8Value()); | |
431 return V8IDBKeyRange::toNativeWithTypeCheck(isolate, value); | |
432 } | |
433 | |
434 #ifndef NDEBUG | |
435 void assertPrimaryKeyValidOrInjectable(ScriptState* scriptState, PassRefPtr<Shar
edBuffer> buffer, const Vector<blink::WebBlobInfo>* blobInfo, IDBKey* key, const
IDBKeyPath& keyPath) | |
436 { | |
437 ScriptState::Scope scope(scriptState); | |
438 v8::Isolate* isolate = scriptState->isolate(); | |
439 ScriptValue keyValue = idbKeyToScriptValue(scriptState, key); | |
440 ScriptValue scriptValue(scriptState, deserializeIDBValueBuffer(isolate, buff
er.get(), blobInfo)); | |
441 | |
442 // This assertion is about already persisted data, so allow experimental typ
es. | |
443 const bool allowExperimentalTypes = true; | |
444 IDBKey* expectedKey = createIDBKeyFromScriptValueAndKeyPathInternal(isolate,
scriptValue, keyPath, allowExperimentalTypes); | |
445 ASSERT(!expectedKey || expectedKey->isEqual(key)); | |
446 | |
447 bool injected = injectV8KeyIntoV8Value(isolate, keyValue.v8Value(), scriptVa
lue.v8Value(), keyPath); | |
448 ASSERT_UNUSED(injected, injected); | |
449 } | |
450 #endif | |
451 | |
452 } // namespace WebCore | |
OLD | NEW |