| // Copyright 2011, Google Inc. |
| // All rights reserved. |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| #include "config.h" |
| #include "bindings/core/dart/DartUtilities.h" |
| |
| #if OS(ANDROID) |
| #include <sys/system_properties.h> |
| #endif |
| |
| #include "bindings/core/dart/DartController.h" |
| #include "bindings/core/dart/DartDOMData.h" |
| #include "bindings/core/dart/DartJsInterop.h" |
| #include "bindings/core/dart/DartScriptDebugServer.h" |
| #include "bindings/core/dart/DartScriptState.h" |
| #include "bindings/core/dart/V8Converter.h" |
| #include "bindings/core/v8/ExceptionState.h" |
| #include "bindings/core/v8/ScriptController.h" |
| #include "bindings/core/v8/SerializedScriptValueFactory.h" |
| #include "bindings/core/v8/V8Binding.h" |
| #include "bindings/core/v8/V8Node.h" |
| #include "bindings/core/v8/V8PerIsolateData.h" |
| #include "core/dom/DOMArrayBuffer.h" |
| #include "core/dom/DOMDataView.h" |
| #include "core/dom/Document.h" |
| #include "core/events/ErrorEvent.h" |
| #include "core/fetch/FetchInitiatorTypeNames.h" |
| #include "core/fetch/ResourceFetcher.h" |
| #include "core/frame/LocalDOMWindow.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/inspector/ScriptArguments.h" |
| #include "core/inspector/ScriptCallStack.h" |
| #include "core/loader/FrameLoader.h" |
| #include "modules/webdatabase/sqlite/SQLValue.h" |
| #include "platform/SharedBuffer.h" |
| #include "platform/network/ResourceRequest.h" |
| |
| #include "wtf/ArrayBufferView.h" |
| #include "wtf/Float32Array.h" |
| #include "wtf/Float64Array.h" |
| #include "wtf/Int16Array.h" |
| #include "wtf/Int32Array.h" |
| #include "wtf/Int8Array.h" |
| #include "wtf/RefCounted.h" |
| #include "wtf/Uint16Array.h" |
| #include "wtf/Uint32Array.h" |
| #include "wtf/Uint8Array.h" |
| #include "wtf/Uint8ClampedArray.h" |
| #include "wtf/text/AtomicString.h" |
| #include "wtf/text/CString.h" |
| #include "wtf/text/WTFString.h" |
| |
| namespace blink { |
| |
| V8Scope::V8Scope(DartDOMData* dartDOMData, v8::Handle<v8::Context> context) |
| : m_v8Isolate(v8::Isolate::GetCurrent()) |
| , m_dartDOMData(dartDOMData) |
| , m_handleScope(m_v8Isolate) |
| , m_contextScope(context) |
| , m_recursionScope(m_v8Isolate) |
| { |
| if (m_dartDOMData) |
| (*m_dartDOMData->recursion())++; |
| } |
| |
| V8Scope::V8Scope(DartDOMData* dartDOMData) |
| : m_v8Isolate(v8::Isolate::GetCurrent()) |
| , m_dartDOMData(dartDOMData) |
| , m_handleScope(m_v8Isolate) |
| , m_contextScope(DartUtilities::currentV8Context()) |
| , m_recursionScope(m_v8Isolate) |
| { |
| if (m_dartDOMData) |
| (*m_dartDOMData->recursion())++; |
| } |
| |
| V8Scope::~V8Scope() |
| { |
| if (m_dartDOMData) |
| (*m_dartDOMData->recursion())--; |
| } |
| |
| DartStringPeer* DartStringPeer::nullString() |
| { |
| DEFINE_STATIC_LOCAL(DartStringPeer, empty, ()); |
| return ∅ |
| } |
| |
| DartStringPeer* DartStringPeer::emptyString() |
| { |
| DEFINE_STATIC_LOCAL(DartStringPeer, empty, (StringImpl::empty())); |
| return ∅ |
| } |
| |
| |
| static void stringFinalizer(void* peer) |
| { |
| ASSERT(reinterpret_cast<DartStringPeer*>(peer) != DartStringPeer::nullString()); |
| delete reinterpret_cast<DartStringPeer*>(peer); |
| } |
| |
| template <typename T> DartStringPeer* convertAndExternalize(Dart_Handle string, intptr_t length) |
| { |
| if (!length) |
| return new DartStringPeer(StringImpl::empty()); |
| #ifndef NDEBUG |
| { |
| intptr_t storageSize = 0; |
| Dart_StringStorageSize(string, &storageSize); |
| ASSERT(length * intptr_t(sizeof(T)) == storageSize); |
| } |
| #endif |
| T* buffer = 0; |
| DartStringPeer* peer = new DartStringPeer(StringImpl::createUninitialized(length, buffer)); |
| Dart_Handle r = Dart_MakeExternalString(string, buffer, length * sizeof(T), peer, stringFinalizer); |
| ALLOW_UNUSED_LOCAL(r); |
| ASSERT(!Dart_IsError(r)); |
| return peer; |
| } |
| |
| DartStringPeer* DartUtilities::toStringImpl(Dart_Handle object, intptr_t charsize, intptr_t strlength) |
| { |
| ASSERT(Dart_IsString(object) && !Dart_IsExternalString(object)); |
| return (charsize == 1) ? convertAndExternalize<LChar>(object, strlength) : convertAndExternalize<UChar>(object, strlength); |
| } |
| |
| |
| Dart_Handle DartUtilities::stringImplToDartString(StringImpl* stringImpl) |
| { |
| if (!stringImpl) { |
| DartDOMData* domData = DartDOMData::current(); |
| return domData->emptyString(); |
| } |
| |
| DartStringPeer* peer = new DartStringPeer(stringImpl); |
| if (stringImpl->is8Bit()) { |
| // FIXME: maybe it makes sense only externalize strings longer than certain threshold, such as 5 symbols. |
| return Dart_NewExternalLatin1String(reinterpret_cast<const uint8_t*>(stringImpl->characters8()), |
| stringImpl->length(), peer, stringFinalizer); |
| } else { |
| // FIXME: maybe it makes sense only externalize strings longer than certain threshold, such as 5 symbols. |
| return Dart_NewExternalUTF16String(reinterpret_cast<const uint16_t*>(stringImpl->characters16()), |
| stringImpl->length(), peer, stringFinalizer); |
| } |
| } |
| |
| Dart_Handle DartUtilities::stringToDartString(const String& str) |
| { |
| return stringImplToDartString(str.impl()); |
| } |
| |
| Dart_Handle DartUtilities::stringToDartString(const AtomicString& str) |
| { |
| return stringImplToDartString(str.impl()); |
| } |
| |
| |
| Dart_Handle DartUtilities::safeStringImplToDartString(StringImpl* stringImpl) |
| { |
| if (!stringImpl) { |
| DartDOMData* domData = DartDOMData::current(); |
| return domData->emptyString(); |
| } |
| |
| if (stringImpl->is8Bit()) { |
| return Dart_NewStringFromUTF8( |
| reinterpret_cast<const uint8_t*>(stringImpl->characters8()), |
| stringImpl->length()); |
| } else { |
| return Dart_NewStringFromUTF16( |
| reinterpret_cast<const uint16_t*>(stringImpl->characters16()), |
| stringImpl->length()); |
| } |
| } |
| |
| Dart_Handle DartUtilities::safeStringToDartString(const String& str) |
| { |
| return safeStringImplToDartString(str.impl()); |
| } |
| |
| Dart_Handle DartUtilities::safeStringToDartString(const AtomicString& str) |
| { |
| return safeStringImplToDartString(str.impl()); |
| } |
| |
| template <typename Trait> |
| typename Trait::nativeType convert(Dart_Handle object, Dart_Handle& exception) |
| { |
| typename Trait::nativeType value; |
| Dart_Handle result = Trait::convert(object, &value); |
| if (Dart_IsError(result)) { |
| exception = Dart_NewStringFromCString(Dart_GetError(result)); |
| return typename Trait::nativeType(); |
| } |
| return value; |
| } |
| |
| struct IntegerTrait { |
| typedef int64_t nativeType; |
| static Dart_Handle convert(Dart_Handle object, int64_t* value) |
| { |
| return Dart_IntegerToInt64(object, value); |
| // FIXME: support bigints. |
| } |
| }; |
| |
| int64_t DartUtilities::toInteger(Dart_Handle object, Dart_Handle& exception) |
| { |
| return convert<IntegerTrait>(object, exception); |
| } |
| |
| String DartUtilities::toString(Dart_Handle object) |
| { |
| Dart_Handle exception = 0; |
| String string = dartToString(object, exception); |
| ASSERT(!exception); |
| return string; |
| } |
| |
| struct DoubleTrait { |
| typedef double nativeType; |
| static Dart_Handle convert(Dart_Handle object, double* value) |
| { |
| if (Dart_IsDouble(object)) |
| return Dart_DoubleValue(object, value); |
| |
| if (Dart_IsInteger(object)) { |
| int64_t v = 0; |
| Dart_Handle result = Dart_IntegerToInt64(object, &v); |
| if (!Dart_IsError(result)) { |
| *value = static_cast<double>(v); |
| return result; |
| } |
| } |
| |
| if (Dart_IsNumber(object)) { |
| object = Dart_Invoke(object, Dart_NewStringFromCString("toDouble"), 0, 0); |
| if (Dart_IsError(object)) |
| return object; |
| } |
| |
| // For non-Number objects, use the error message returned by Dart_DoubleValue. |
| return Dart_DoubleValue(object, value); |
| } |
| }; |
| |
| double DartUtilities::dartToDouble(Dart_Handle object, Dart_Handle& exception) |
| { |
| return convert<DoubleTrait>(object, exception); |
| } |
| |
| struct BoolTrait { |
| typedef bool nativeType; |
| static Dart_Handle convert(Dart_Handle object, bool* value) |
| { |
| if (Dart_IsNull(object)) { |
| *value = false; |
| return Dart_Null(); |
| } |
| return Dart_BooleanValue(object, value); |
| } |
| }; |
| |
| bool DartUtilities::dartToBool(Dart_Handle object, Dart_Handle& exception) |
| { |
| return convert<BoolTrait>(object, exception); |
| } |
| |
| DartStringAdapter DartUtilities::dartToStringImpl(Dart_Handle object, Dart_Handle& exception, bool autoDartScope) |
| { |
| if (!Dart_IsError(object) && !Dart_IsNull(object)) { |
| ASSERT(Dart_IsString(object) && !Dart_IsExternalString(object)); |
| intptr_t charsize = Dart_IsStringLatin1(object) ? 1 : 2; |
| intptr_t strlength; |
| Dart_StringLength(object, &strlength); |
| if (autoDartScope) |
| return DartStringAdapter(toStringImpl(object, charsize, strlength)); |
| DartApiScope apiScope; |
| return DartStringAdapter(toStringImpl(object, charsize, strlength)); |
| } |
| if (!autoDartScope) { |
| DartApiScope apiScope; |
| DartDOMData* domData = DartDOMData::current(); |
| Dart_Handle excp = Dart_NewStringFromCString("String expected"); |
| Dart_SetPersistentHandle(domData->currentException(), excp); |
| exception = domData->currentException(); |
| } else { |
| exception = Dart_NewStringFromCString("String expected"); |
| } |
| return DartStringAdapter(DartStringPeer::nullString()); |
| } |
| |
| void DartUtilities::extractMapElements(Dart_Handle map, Dart_Handle& exception, HashMap<String, Dart_Handle>& elements) |
| { |
| ASSERT(elements.isEmpty()); |
| Dart_Handle list = DartUtilities::invokeUtilsMethod("convertMapToList", 1, &map); |
| if (!DartUtilities::checkResult(list, exception)) |
| return; |
| ASSERT(Dart_IsList(list)); |
| |
| intptr_t length = 0; |
| Dart_ListLength(list, &length); |
| ASSERT(length % 2 == 0); |
| |
| for (intptr_t i = 0; i < length; i += 2) { |
| Dart_Handle key = Dart_ListGetAt(list, i); |
| ASSERT(!Dart_IsError(key) && Dart_IsString(key)); |
| Dart_Handle value = Dart_ListGetAt(list, i+1); |
| ASSERT(!Dart_IsError(value)); |
| String keyString = DartUtilities::dartToString(key, exception); |
| if (exception) |
| return; |
| elements.add(keyString, value); |
| } |
| } |
| |
| Dart_Handle DartUtilities::toList(const Vector<Dart_Handle>& elements, Dart_Handle& exception) |
| { |
| Dart_Handle ret = Dart_NewList(elements.size()); |
| if (Dart_IsError(ret)) { |
| exception = ret; |
| return Dart_Null(); |
| } |
| for (size_t i = 0; i < elements.size(); i++) { |
| Dart_ListSetAt(ret, i, elements[i]); |
| } |
| return ret; |
| } |
| |
| void DartUtilities::extractListElements(Dart_Handle list, Dart_Handle& exception, Vector<Dart_Handle>& elements) |
| { |
| ASSERT(elements.isEmpty()); |
| list = DartUtilities::invokeUtilsMethod("convertToList", 1, &list); |
| if (!DartUtilities::checkResult(list, exception)) |
| return; |
| ASSERT(Dart_IsList(list)); |
| |
| intptr_t length = 0; |
| Dart_ListLength(list, &length); |
| elements.reserveCapacity(length); |
| for (intptr_t i = 0; i < length; i++) { |
| Dart_Handle element = Dart_ListGetAt(list, i); |
| ASSERT(!Dart_IsError(element)); |
| elements.append(element); |
| } |
| } |
| |
| v8::Local<v8::Context> DartUtilities::currentV8Context() |
| { |
| LocalFrame* frame = DartUtilities::domWindowForCurrentIsolate()->frame(); |
| v8::Local<v8::Context> context = toV8Context(frame, DOMWrapperWorld::mainWorld()); |
| ASSERT(!context.IsEmpty()); |
| return context; |
| } |
| |
| int DartUtilities::dartToInt(Dart_Handle object, Dart_Handle& exception) |
| { |
| int64_t value = toInteger(object, exception); |
| if (exception) |
| return 0; |
| if (value < INT_MIN || value > INT_MAX) { |
| exception = Dart_NewStringFromCString("value out of range"); |
| return 0; |
| } |
| return value; |
| } |
| |
| unsigned DartUtilities::dartToUnsigned(Dart_Handle object, Dart_Handle& exception) |
| { |
| int64_t value = toInteger(object, exception); |
| if (exception) |
| return 0; |
| if (value < 0 || value > UINT_MAX) { |
| exception = Dart_NewStringFromCString("value out of range"); |
| return 0; |
| } |
| return value; |
| } |
| |
| long long DartUtilities::dartToLongLong(Dart_Handle object, Dart_Handle& exception) |
| { |
| // FIXME: proper processing of longer integer values. |
| return toInteger(object, exception); |
| } |
| |
| unsigned long long DartUtilities::dartToUnsignedLongLong(Dart_Handle object, Dart_Handle& exception) |
| { |
| // FIXME: proper processing of longer integer values. |
| int64_t value = toInteger(object, exception); |
| if (exception) |
| return 0; |
| if (value < 0) { |
| exception = Dart_NewStringFromCString("value out of range"); |
| return 0; |
| } |
| return value; |
| } |
| |
| // TODO(terry): Copied from V8Binding.cpp (private member in V8). |
| const int64_t kJSMaxInteger = 0x20000000000000LL - 1; // 2^53 - 1, maximum uniquely representable integer in ECMAScript. |
| const int64_t maxJSInteger = kJSMaxInteger; |
| const int64_t minJSInteger = -kJSMaxInteger; |
| |
| Dart_Handle DartUtilities::numberToDart(double value) |
| { |
| // JS can store integer values that are no greater than 2^53 - 1. |
| // TODO(terry): Need to call V8Binding's toInt64 however, we need an isolate |
| if (minJSInteger <= value && value <= maxJSInteger) { |
| int64_t intValue = static_cast<int64_t>(value); |
| if (value == intValue) |
| return intToDart(intValue); |
| } |
| return doubleToDart(value); |
| } |
| |
| ScriptValue DartUtilities::dartToScriptValue(Dart_Handle object) |
| { |
| // TODO(terry): Added bug per JacobR - he thinks it would be better to use |
| // DartHandleProxy probably pressing pause crashes Dartium 45. |
| // See issue: https://github.com/dart-lang/sdk/issues/25589 |
| Dart_Handle exception = 0; |
| ScriptState* v8ScriptState = currentDartScriptState()->v8ScriptState(); |
| v8::Handle<v8::Value> value = V8Converter::toV8(object, exception); |
| if (exception) |
| return ScriptValue(v8ScriptState, v8::Undefined(v8ScriptState->isolate())); |
| ASSERT(!value.IsEmpty()); |
| |
| return ScriptValue(v8ScriptState, value); |
| } |
| |
| Dart_Handle DartUtilities::dateToDart(double date) |
| { |
| Dart_Handle asDouble = DartUtilities::doubleToDart(date); |
| ASSERT(!Dart_IsError(asDouble)); |
| return DartUtilities::invokeUtilsMethod("doubleToDateTime", 1, &asDouble); |
| } |
| |
| double DartUtilities::dartToDate(Dart_Handle date, Dart_Handle& exception) |
| { |
| Dart_Handle asDouble = DartUtilities::invokeUtilsMethod("dateTimeToDouble", 1, &date); |
| if (!DartUtilities::checkResult(asDouble, exception)) |
| return 0.0; |
| |
| return DartUtilities::dartToDouble(asDouble, exception); |
| } |
| |
| double DartUtilities::dartToDate(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToDate(object, exception); |
| } |
| |
| bool DartUtilities::isDateTime(DartDOMData* domData, Dart_Handle handle) |
| { |
| return objectIsType(handle, domData->dateTimeType()); |
| } |
| |
| bool DartUtilities::objectIsType(Dart_Handle handle, Dart_Handle type) |
| { |
| bool isType = false; |
| Dart_Handle result = Dart_ObjectIsType(handle, type, &isType); |
| if (Dart_IsError(result)) |
| return false; |
| return isType; |
| } |
| |
| bool DartUtilities::isTypeSubclassOf(Dart_Handle type, Dart_Handle library, const char* typeName) |
| { |
| Dart_Handle other = Dart_GetType(library, Dart_NewStringFromCString(typeName), 0, 0); |
| ASSERT(!Dart_IsError(other)); |
| |
| Dart_Handle args[2] = { type, other }; |
| Dart_Handle result = DartUtilities::invokeUtilsMethod("isTypeSubclassOf", 2, args); |
| if (Dart_IsError(result)) { |
| ASSERT_NOT_REACHED(); |
| return false; |
| } |
| |
| Dart_Handle exception = 0; |
| bool boolResult = dartToBool(result, exception); |
| if (exception) |
| return false; |
| return boolResult; |
| } |
| |
| Dart_Handle DartUtilities::getAndValidateNativeType(Dart_Handle type, const String& tagName) |
| { |
| Dart_Handle args[2] = { type, stringToDartString(tagName) }; |
| Dart_Handle result = DartUtilities::invokeUtilsMethod("getAndValidateNativeType", 2, args); |
| ASSERT(!Dart_IsError(result)); |
| if (Dart_IsError(result)) { |
| ASSERT_NOT_REACHED(); |
| return Dart_Null(); |
| } |
| return result; |
| } |
| |
| bool DartUtilities::isFunction(DartDOMData* domData, Dart_Handle handle) |
| { |
| return DartUtilities::objectIsType(handle, domData->functionType()); |
| } |
| |
| Dart_Handle DartUtilities::getDartType(const char* libraryName, const char* typeName) |
| { |
| Dart_Handle library = Dart_LookupLibrary(Dart_NewStringFromCString(libraryName)); |
| ASSERT(!Dart_IsError(library)); |
| |
| Dart_Handle dartType = Dart_GetType(library, Dart_NewStringFromCString(typeName), 0, 0); |
| ASSERT(!Dart_IsError(dartType)); |
| |
| return dartType; |
| } |
| |
| Dart_Handle DartUtilities::getDartHtmlType(const char* typeName) |
| { |
| Dart_Handle dartType = Dart_GetType(DartDOMData::current()->htmlLibrary(), |
| Dart_NewStringFromCString(typeName), 0, 0); |
| ASSERT(!Dart_IsError(dartType)); |
| |
| return dartType; |
| } |
| |
| bool DartUtilities::isNode(Dart_Handle handle) |
| { |
| Dart_Handle dartType = DartUtilities::getDartHtmlType("Node"); |
| if (!objectIsType(handle, dartType)) { |
| return false; |
| } |
| // Some dart:html Node instances may not really be Node objects. |
| Dart_Handle exception = 0; |
| v8::Handle<v8::Value> v8Node = JsInterop::fromDart(DartDOMData::current(), handle, exception); |
| if (exception) { |
| return false; |
| } |
| return V8Node::hasInstance(v8Node, v8::Isolate::GetCurrent()); |
| } |
| |
| Node* DartUtilities::dartNodeToNativeNode(Dart_Handle handle) |
| { |
| Dart_Handle exception = 0; |
| v8::Handle<v8::Value> v8Node = JsInterop::fromDart(DartDOMData::current(), handle, exception); |
| ASSERT(!exception); |
| ASSERT(V8Node::hasInstance(v8Node, v8::Isolate::GetCurrent())); |
| Node* node = V8Node::toImpl(v8Node.As<v8::Object>()); |
| return node; |
| } |
| |
| bool DartUtilities::isMessagePort(Dart_Handle handle) |
| { |
| Dart_Handle dartType = DartUtilities::getDartHtmlType("MessagePort"); |
| return objectIsType(handle, dartType); |
| } |
| |
| MessagePort* DartUtilities::dartMessagePortToNativeMessagePort(void* value) |
| { |
| return static_cast<MessagePort*>(value); |
| } |
| |
| static Dart_TypedData_Type typedDataTypeFromViewType(ArrayBufferView::ViewType type) |
| { |
| switch (type) { |
| case ArrayBufferView::TypeInt8: |
| return Dart_TypedData_kInt8; |
| case ArrayBufferView::TypeUint8: |
| return Dart_TypedData_kUint8; |
| case ArrayBufferView::TypeUint8Clamped: |
| return Dart_TypedData_kUint8Clamped; |
| case ArrayBufferView::TypeInt16: |
| return Dart_TypedData_kInt16; |
| case ArrayBufferView::TypeUint16: |
| return Dart_TypedData_kUint16; |
| case ArrayBufferView::TypeInt32: |
| return Dart_TypedData_kInt32; |
| case ArrayBufferView::TypeUint32: |
| return Dart_TypedData_kUint32; |
| case ArrayBufferView::TypeFloat32: |
| return Dart_TypedData_kFloat32; |
| case ArrayBufferView::TypeFloat64: |
| return Dart_TypedData_kFloat64; |
| case ArrayBufferView::TypeDataView: |
| return Dart_TypedData_kByteData; |
| } |
| ASSERT_NOT_REACHED(); |
| return Dart_TypedData_kInvalid; |
| } |
| |
| static unsigned elementSizeFromViewType(Dart_TypedData_Type type) |
| { |
| switch (type) { |
| case Dart_TypedData_kByteData: |
| return sizeof(uint8_t); |
| case Dart_TypedData_kInt8: |
| return sizeof(int8_t); |
| case Dart_TypedData_kUint8: |
| return sizeof(uint8_t); |
| case Dart_TypedData_kUint8Clamped: |
| return sizeof(uint8_t); |
| case Dart_TypedData_kInt16: |
| return sizeof(int16_t); |
| case Dart_TypedData_kUint16: |
| return sizeof(uint16_t); |
| case Dart_TypedData_kInt32: |
| return sizeof(int32_t); |
| case Dart_TypedData_kUint32: |
| return sizeof(uint32_t); |
| case Dart_TypedData_kFloat32: |
| return sizeof(float); |
| case Dart_TypedData_kFloat64: |
| return sizeof(double); |
| case Dart_TypedData_kFloat32x4: |
| return 4 * sizeof(float); |
| default: |
| break; |
| } |
| ASSERT_NOT_REACHED(); |
| return 0; |
| } |
| |
| static unsigned elementSizeFromViewType(ArrayBufferView::ViewType type) |
| { |
| return elementSizeFromViewType(typedDataTypeFromViewType(type)); |
| } |
| |
| class TypedDataPeer { |
| public: |
| virtual ~TypedDataPeer() { }; |
| virtual bool isViewPeer() = 0; |
| }; |
| |
| class TypedBufferPeer : public TypedDataPeer { |
| public: |
| TypedBufferPeer(PassRefPtr<ArrayBuffer> buffer) : m_buffer(buffer) { } |
| virtual ~TypedBufferPeer() { } |
| |
| PassRefPtr<ArrayBuffer> buffer() |
| { |
| return m_buffer; |
| } |
| |
| virtual bool isViewPeer() |
| { |
| return false; |
| } |
| |
| private: |
| RefPtr<ArrayBuffer> m_buffer; |
| }; |
| |
| class TypedViewPeer : public TypedDataPeer { |
| public: |
| TypedViewPeer(PassRefPtr<ArrayBufferView> view) : m_view(view) { } |
| virtual ~TypedViewPeer() { } |
| |
| PassRefPtr<ArrayBufferView> view() |
| { |
| return m_view; |
| } |
| |
| virtual bool isViewPeer() |
| { |
| return true; |
| } |
| |
| private: |
| RefPtr<ArrayBufferView> m_view; |
| }; |
| |
| static void externalArrayBufferCallback(void* isolateCallbackData, Dart_WeakPersistentHandle handle, void* peer) |
| { |
| delete reinterpret_cast<TypedDataPeer*>(peer); |
| } |
| |
| static Dart_Handle createExternalTypedData(Dart_TypedData_Type type, void* data, intptr_t numberOfElements, TypedDataPeer* peer, intptr_t peerSize, Dart_WeakPersistentHandleFinalizer callback) |
| { |
| Dart_Handle newInstance = Dart_NewExternalTypedData(type, data, numberOfElements); |
| Dart_Handle result = Dart_SetPeer(newInstance, peer); |
| if (Dart_IsError(result)) |
| return result; |
| Dart_NewWeakPersistentHandle(newInstance, peer, peerSize, callback); |
| return newInstance; |
| } |
| |
| Dart_Handle DartUtilities::arrayBufferToDart(WTF::ArrayBuffer* buffer) |
| { |
| void* data = buffer->data(); |
| unsigned byteLength = buffer->byteLength(); |
| TypedBufferPeer* peer = new TypedBufferPeer(buffer); |
| Dart_Handle typedData = createExternalTypedData(Dart_TypedData_kUint8, data, byteLength, peer, byteLength, externalArrayBufferCallback); |
| ASSERT(!Dart_IsError(typedData)); |
| return Dart_NewByteBuffer(typedData); |
| } |
| |
| static bool externalTypedDataGetPeer(Dart_Handle handle, void** peer) |
| { |
| *peer = 0; |
| Dart_Handle getPeerResult = Dart_GetPeer(handle, peer); |
| if (!Dart_IsError(getPeerResult) && *peer) { |
| return true; |
| } |
| return false; |
| } |
| |
| static PassRefPtr<WTF::ArrayBuffer> dartToArrayBufferHelper(Dart_Handle array, Dart_Handle& exception, bool externalize) |
| { |
| void* data = 0; |
| |
| // If a ByteBuffer is passed in extract the typed data first. |
| if (Dart_IsByteBuffer(array)) { |
| array = Dart_GetDataFromByteBuffer(array); |
| } |
| |
| // Check if the Dart array buffer object is external and has an |
| // ArrayBuffer peer. |
| if (externalTypedDataGetPeer(array, &data) && !reinterpret_cast<TypedDataPeer*>(data)->isViewPeer()) { |
| return reinterpret_cast<TypedBufferPeer*>(data)->buffer(); |
| } |
| |
| Dart_TypedData_Type type; |
| intptr_t elementLength = 0; |
| intptr_t byteLength = 0; |
| |
| // Check if the Dart object is a typed data object by acquiring its data. |
| // If it is, create a thin ArrayBuffer wrapper around the data in the dart |
| // heap. |
| Dart_Handle result = Dart_TypedDataAcquireData(array, &type, &data, &elementLength); |
| if (Dart_IsError(result)) { |
| exception = Dart_NewStringFromCString("Typed data object expected"); |
| return nullptr; |
| } |
| // FIXME: we really shouldn't release the data until we are done with it. |
| Dart_TypedDataReleaseData(array); |
| byteLength = elementLength * elementSizeFromViewType(type); |
| return externalize ? ArrayBuffer::create(data, byteLength) : ArrayBuffer::createNoCopy(data, byteLength); |
| } |
| |
| PassRefPtr<WTF::ArrayBuffer> DartUtilities::dartToArrayBuffer(Dart_Handle array, Dart_Handle& exception) |
| { |
| return dartToArrayBufferHelper(array, exception, false); |
| } |
| |
| PassRefPtr<WTF::ArrayBuffer> DartUtilities::dartToExternalizedArrayBuffer(Dart_Handle array, Dart_Handle& exception) |
| { |
| return dartToArrayBufferHelper(array, exception, true); |
| } |
| |
| // FIXME: This mapping to dart objects loses object identity for |
| // the buffer part of views. If we have two views on the same buffer |
| // in C++ and we create dart wrappers we will get two different dart |
| // buffer objects. Additionally, this means that neutering will not work. |
| Dart_Handle DartUtilities::arrayBufferViewToDart(WTF::ArrayBufferView* view) |
| { |
| ArrayBufferView::ViewType type = view->type(); |
| void* address = view->baseAddress(); |
| unsigned byteLength = view->byteLength(); |
| unsigned length = byteLength / elementSizeFromViewType(type); |
| TypedViewPeer* peer = new TypedViewPeer(view); |
| return createExternalTypedData(typedDataTypeFromViewType(type), address, length, peer, byteLength, externalArrayBufferCallback); |
| } |
| |
| |
| // FIXME: Again, this breaks the view-buffer relationship. |
| static PassRefPtr<WTF::ArrayBufferView> dartToArrayBufferViewHelper(Dart_Handle array, Dart_Handle& exception, bool externalize) |
| { |
| void* data = 0; |
| |
| // Check if the array is external and has an ArrayBufferView peer. |
| if (externalTypedDataGetPeer(array, &data)) { |
| if (!reinterpret_cast<TypedDataPeer*>(data)->isViewPeer()) { |
| exception = Dart_NewStringFromCString("Typed data view expected"); |
| return nullptr; |
| } |
| return reinterpret_cast<TypedViewPeer*>(data)->view(); |
| } |
| |
| // Check if the dart object is an internal typed data object and get |
| // the data from it. |
| Dart_TypedData_Type type; |
| intptr_t elementLength = 0; |
| Dart_Handle result = Dart_TypedDataAcquireData(array, &type, &data, &elementLength); |
| if (Dart_IsError(result)) { |
| exception = Dart_NewStringFromCString("Typed data object expected"); |
| return nullptr; |
| } |
| intptr_t byteLength = elementLength * elementSizeFromViewType(type); |
| // FIXME: we really shouldn't release the data until we are done with it. |
| Dart_TypedDataReleaseData(array); |
| RefPtr<DOMArrayBuffer> buffer = externalize ? DOMArrayBuffer::create(data, byteLength) : DOMArrayBuffer::createNoCopy(data, byteLength); |
| |
| switch (type) { |
| case Dart_TypedData_kByteData: |
| return DOMDataView::create(buffer, 0, elementLength)->view(); |
| case Dart_TypedData_kInt8: |
| return Int8Array::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kUint8: |
| return Uint8Array::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kUint8Clamped: |
| return Uint8ClampedArray::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kInt16: |
| return Uint16Array::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kUint16: |
| return Uint16Array::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kInt32: |
| return Int32Array::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kUint32: |
| return Uint32Array::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kFloat32: |
| return Float32Array::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kFloat64: |
| return Float64Array::create(buffer->buffer(), 0, elementLength); |
| case Dart_TypedData_kFloat32x4: |
| return Float32Array::create(buffer->buffer(), 0, elementLength * sizeof(float)); |
| default: |
| break; |
| } |
| ASSERT_NOT_REACHED(); |
| return nullptr; |
| } |
| |
| PassRefPtr<WTF::ArrayBufferView> DartUtilities::dartToArrayBufferView(Dart_Handle array, Dart_Handle& exception) |
| { |
| return dartToArrayBufferViewHelper(array, exception, false); |
| } |
| |
| PassRefPtr<WTF::ArrayBufferView> DartUtilities::dartToExternalizedArrayBufferView(Dart_Handle array, Dart_Handle& exception) |
| { |
| return dartToArrayBufferViewHelper(array, exception, true); |
| } |
| |
| PassRefPtr<WTF::Int8Array> DartUtilities::dartToInt8ArrayWithNullCheck(Dart_Handle handle, Dart_Handle& exception) |
| { |
| return Dart_IsNull(handle) ? nullptr : dartToInt8Array(handle, exception); |
| } |
| |
| PassRefPtr<WTF::Int8Array> DartUtilities::dartToInt8Array(Dart_Handle handle, Dart_Handle& exception) |
| { |
| RefPtr<ArrayBufferView> view = DartUtilities::dartToArrayBufferView(handle, exception); |
| if (exception) |
| return nullptr; |
| if (view->type() == ArrayBufferView::TypeInt8) |
| return reinterpret_cast<Int8Array*>(view.get()); |
| exception = Dart_NewStringFromCString("Int8List expected"); |
| return nullptr; |
| } |
| |
| PassRefPtr<WTF::Int8Array> DartUtilities::dartToInt8ArrayWithNullCheck(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToInt8ArrayWithNullCheck(object, exception); |
| } |
| |
| PassRefPtr<WTF::Int8Array> DartUtilities::dartToInt8Array(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToInt8Array(object, exception); |
| } |
| |
| PassRefPtr<WTF::Int32Array> DartUtilities::dartToInt32ArrayWithNullCheck(Dart_Handle handle, Dart_Handle& exception) |
| { |
| return Dart_IsNull(handle) ? nullptr : dartToInt32Array(handle, exception); |
| } |
| |
| PassRefPtr<WTF::Int32Array> DartUtilities::dartToInt32Array(Dart_Handle handle, Dart_Handle& exception) |
| { |
| RefPtr<ArrayBufferView> view = DartUtilities::dartToArrayBufferView(handle, exception); |
| if (exception) |
| return nullptr; |
| if (view->type() == ArrayBufferView::TypeInt32) |
| return reinterpret_cast<Int32Array*>(view.get()); |
| exception = Dart_NewStringFromCString("Int32List expected"); |
| return nullptr; |
| } |
| |
| PassRefPtr<WTF::Int32Array> DartUtilities::dartToInt32ArrayWithNullCheck(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToInt32ArrayWithNullCheck(object, exception); |
| } |
| |
| PassRefPtr<WTF::Int32Array> DartUtilities::dartToInt32Array(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToInt32Array(object, exception); |
| } |
| |
| PassRefPtr<WTF::Uint8ClampedArray> DartUtilities::dartToUint8ClampedArrayWithNullCheck(Dart_Handle handle, Dart_Handle& exception) |
| { |
| return Dart_IsNull(handle) ? nullptr : dartToUint8ClampedArray(handle, exception); |
| } |
| |
| PassRefPtr<WTF::Uint8ClampedArray> DartUtilities::dartToUint8ClampedArray(Dart_Handle handle, Dart_Handle& exception) |
| { |
| RefPtr<ArrayBufferView> view = DartUtilities::dartToArrayBufferView(handle, exception); |
| if (exception) |
| return nullptr; |
| if (view->type() == ArrayBufferView::TypeUint8Clamped) |
| return reinterpret_cast<Uint8ClampedArray*>(view.get()); |
| exception = Dart_NewStringFromCString("Uint8ClampedList expected"); |
| return nullptr; |
| } |
| |
| PassRefPtr<WTF::Uint8ClampedArray> DartUtilities::dartToUint8ClampedArrayWithNullCheck(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToUint8ClampedArrayWithNullCheck(object, exception); |
| } |
| |
| PassRefPtr<WTF::Uint8ClampedArray> DartUtilities::dartToUint8ClampedArray(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToUint8ClampedArray(object, exception); |
| } |
| |
| PassRefPtr<WTF::Uint8Array> DartUtilities::dartToUint8ArrayWithNullCheck(Dart_Handle handle, Dart_Handle& exception) |
| { |
| return Dart_IsNull(handle) ? nullptr : dartToUint8Array(handle, exception); |
| } |
| |
| PassRefPtr<WTF::Uint8Array> DartUtilities::dartToUint8Array(Dart_Handle handle, Dart_Handle& exception) |
| { |
| RefPtr<ArrayBufferView> view = DartUtilities::dartToArrayBufferView(handle, exception); |
| if (exception) |
| return nullptr; |
| if (view->type() == ArrayBufferView::TypeUint8) |
| return reinterpret_cast<Uint8Array*>(view.get()); |
| exception = Dart_NewStringFromCString("Uint8List expected"); |
| return nullptr; |
| } |
| |
| PassRefPtr<WTF::Uint8Array> DartUtilities::dartToUint8ArrayWithNullCheck(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToUint8ArrayWithNullCheck(object, exception); |
| } |
| |
| PassRefPtr<WTF::Uint8Array> DartUtilities::dartToUint8Array(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToUint8Array(object, exception); |
| } |
| |
| PassRefPtr<WTF::Float32Array> DartUtilities::dartToFloat32ArrayWithNullCheck(Dart_Handle handle, Dart_Handle& exception) |
| { |
| return Dart_IsNull(handle) ? nullptr : dartToFloat32Array(handle, exception); |
| } |
| |
| PassRefPtr<WTF::Float32Array> DartUtilities::dartToFloat32Array(Dart_Handle handle, Dart_Handle& exception) |
| { |
| RefPtr<ArrayBufferView> view = DartUtilities::dartToArrayBufferView(handle, exception); |
| if (exception) |
| return nullptr; |
| if (view->type() == ArrayBufferView::TypeFloat32) |
| return reinterpret_cast<Float32Array*>(view.get()); |
| exception = Dart_NewStringFromCString("Float32List expected"); |
| return nullptr; |
| } |
| |
| PassRefPtr<WTF::Float32Array> DartUtilities::dartToFloat32ArrayWithNullCheck(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToFloat32ArrayWithNullCheck(object, exception); |
| } |
| |
| PassRefPtr<WTF::Float32Array> DartUtilities::dartToFloat32Array(Dart_NativeArguments args, int idx, Dart_Handle& exception) |
| { |
| Dart_Handle object = Dart_GetNativeArgument(args, idx); |
| return dartToFloat32Array(object, exception); |
| } |
| |
| bool DartUtilities::isUint8Array(Dart_Handle object) |
| { |
| return Dart_GetTypeOfTypedData(object) == Dart_TypedData_kUint8; |
| } |
| |
| bool DartUtilities::isUint8ClampedArray(Dart_Handle object) |
| { |
| return Dart_GetTypeOfTypedData(object) == Dart_TypedData_kUint8Clamped; |
| } |
| |
| // FIXME: this function requires better testing. Currently blocking as new MessageChannel hasn't been implemented yet. |
| void DartUtilities::toMessagePortArray(Dart_Handle value, MessagePortArray& ports, ArrayBufferArray& arrayBuffers, Dart_Handle& exception) |
| { |
| Vector<Dart_Handle> elements; |
| DartUtilities::extractListElements(value, exception, elements); |
| if (exception) |
| return; |
| |
| for (size_t i = 0; i < elements.size(); i++) { |
| Dart_Handle element = elements[i]; |
| if (DartUtilities::isMessagePort(element)) { |
| MessagePort* messagePort = DartUtilities::dartMessagePortToNativeMessagePort(element); |
| ASSERT(messagePort); |
| ports.append(messagePort); |
| continue; |
| } |
| |
| if (Dart_IsByteBuffer(element)) { |
| element = Dart_GetDataFromByteBuffer(element); |
| RefPtr<ArrayBuffer> arrayBuffer = DartUtilities::dartToExternalizedArrayBuffer(element, exception); |
| ASSERT(!exception); |
| ASSERT(arrayBuffer); |
| arrayBuffers.append(DOMArrayBuffer::create(arrayBuffer)); |
| continue; |
| } |
| |
| exception = Dart_NewStringFromCString("TransferArray argument must contain only Transferables"); |
| return; |
| } |
| } |
| |
| LocalDOMWindow* DartUtilities::domWindowForCurrentIsolate() |
| { |
| DartDOMData* domData = DartDOMData::current(); |
| ASSERT(domData->scriptExecutionContext()->isDocument()); |
| Document* document = static_cast<Document*>(domData->scriptExecutionContext()); |
| return document->domWindow(); |
| } |
| |
| ScriptState* DartUtilities::v8ScriptStateForCurrentIsolate() |
| { |
| return ScriptState::forMainWorld(domWindowForCurrentIsolate()->frame()); |
| } |
| |
| ExecutionContext* DartUtilities::scriptExecutionContext() |
| { |
| if (Dart_CurrentIsolate()) |
| return DartDOMData::current()->scriptExecutionContext(); |
| return 0; |
| } |
| |
| bool DartUtilities::processingUserGesture() |
| { |
| // FIXME: implement this. |
| return false; |
| } |
| |
| intptr_t DartUtilities::libraryHandleToLibraryId(Dart_Handle library) |
| { |
| intptr_t libraryId = -1; |
| Dart_Handle result = Dart_LibraryId(library, &libraryId); |
| ALLOW_UNUSED_LOCAL(result); |
| ASSERT(!Dart_IsError(result)); |
| return libraryId; |
| } |
| |
| DartScriptState* DartUtilities::currentDartScriptState() |
| { |
| DartDOMData* dartDOMData = DartDOMData::current(); |
| if (!dartDOMData->rootScriptState()) { |
| DartController* controller = DartController::retrieve(dartDOMData->scriptExecutionContext()); |
| intptr_t libraryId = DartUtilities::libraryHandleToLibraryId(Dart_RootLibrary()); |
| DartScriptState* scriptState = controller->lookupScriptState(Dart_CurrentIsolate(), currentV8Context(), libraryId); |
| dartDOMData->setRootScriptState(scriptState); |
| return scriptState; |
| } |
| return dartDOMData->rootScriptState(); |
| } |
| |
| static PassRefPtr<ScriptCallStack> createScriptCallStackFromStackTrace(Dart_StackTrace stackTrace) |
| { |
| uintptr_t frameCount = 0; |
| Dart_Handle result = Dart_StackTraceLength(stackTrace, reinterpret_cast<intptr_t*>(&frameCount)); |
| if (Dart_IsError(result)) |
| return nullptr; |
| |
| if (frameCount > ScriptCallStack::maxCallStackSizeToCapture) |
| frameCount = ScriptCallStack::maxCallStackSizeToCapture; |
| |
| Dart_Isolate isolate = Dart_CurrentIsolate(); |
| Vector<ScriptCallFrame> scriptCallStackFrames; |
| for (uintptr_t frameIndex = 0; frameIndex < frameCount; frameIndex++) { |
| Dart_ActivationFrame frame = 0; |
| result = Dart_GetActivationFrame(stackTrace, frameIndex, &frame); |
| if (Dart_IsError(result)) { |
| return nullptr; |
| } |
| ASSERT(frame); |
| |
| Dart_Handle dartFunctionName; |
| Dart_Handle dartScriptUrl; |
| intptr_t lineNumber = 0; |
| intptr_t columnNumber = 0; |
| result = Dart_ActivationFrameInfo(frame, &dartFunctionName, &dartScriptUrl, &lineNumber, &columnNumber); |
| if (Dart_IsError(result)) { |
| return nullptr; |
| } |
| |
| // This skips frames where source is unavailable. WebKit code for the |
| // console assumes that console.log et al. are implemented directly |
| // as natives, i.e. that the top-of-stack will be the caller of |
| // console.log. The Dart implementation involves intermediate Dart |
| // calls, which are skipped by this clause. |
| if (columnNumber == -1) |
| continue; |
| |
| String functionName = DartUtilities::toString(dartFunctionName); |
| String scriptUrl = DartUtilities::toString(dartScriptUrl); |
| |
| scriptCallStackFrames.append(ScriptCallFrame(functionName, DartScriptDebugServer::shared().getScriptId(scriptUrl, isolate), scriptUrl, lineNumber, columnNumber)); |
| } |
| if (scriptCallStackFrames.isEmpty()) |
| scriptCallStackFrames.append(ScriptCallFrame("undefined", "undefined", "undefined", 0, 0)); |
| |
| return ScriptCallStack::create(scriptCallStackFrames); |
| } |
| |
| ScriptCallFrame DartUtilities::getTopFrame(Dart_StackTrace stackTrace, Dart_Handle& exception) |
| { |
| { |
| uintptr_t frameCount = 0; |
| Dart_Handle result = Dart_StackTraceLength(stackTrace, reinterpret_cast<intptr_t*>(&frameCount)); |
| if (Dart_IsError(result)) { |
| exception = result; |
| goto fail; |
| } |
| if (!frameCount) { |
| exception = Dart_NewStringFromCString("Empty stack trace"); |
| goto fail; |
| } |
| Dart_ActivationFrame frame = 0; |
| result = Dart_GetActivationFrame(stackTrace, 0, &frame); |
| if (Dart_IsError(result)) { |
| exception = result; |
| goto fail; |
| } |
| ASSERT(frame); |
| return toScriptCallFrame(frame, exception); |
| } |
| fail: |
| return ScriptCallFrame("undefined", "undefined", "undefined", 0, 0); |
| } |
| |
| ScriptCallFrame DartUtilities::toScriptCallFrame(Dart_ActivationFrame frame, Dart_Handle& exception) |
| { |
| ASSERT(frame); |
| Dart_Handle functionName; |
| Dart_Handle scriptUrl; |
| intptr_t lineNumber = 0; |
| intptr_t columnNumber = 0; |
| Dart_Handle result = Dart_ActivationFrameInfo(frame, &functionName, &scriptUrl, &lineNumber, &columnNumber); |
| if (Dart_IsError(result)) { |
| exception = result; |
| return ScriptCallFrame("undefined", "undefined", "undefined", 0, 0); |
| } |
| return ScriptCallFrame(DartUtilities::toString(functionName), "undefined", DartUtilities::toString(scriptUrl), lineNumber, columnNumber); |
| } |
| |
| PassRefPtr<ScriptCallStack> DartUtilities::createScriptCallStack() |
| { |
| Dart_StackTrace trace = 0; |
| Dart_Handle result = Dart_GetStackTrace(&trace); |
| ALLOW_UNUSED_LOCAL(result); |
| ASSERT(!Dart_IsError(result)); |
| ASSERT(!Dart_IsNull(result)); |
| ASSERT(trace); |
| return createScriptCallStackFromStackTrace(trace); |
| } |
| |
| static const uint8_t* snapshotBuffer(int index) |
| { |
| // DartSnapshot.bytes is generated by build system. |
| #include "bindings/dart/DartSnapshot.bytes" |
| ASSERT(index == DartUtilities::VmIsolateSnapshotId || index == DartUtilities::IsolateSnapshotId); |
| if (index == DartUtilities::VmIsolateSnapshotId) { |
| return vmIsolateSnapshotBuffer; |
| } |
| return isolateSnapshotBuffer; |
| } |
| |
| const uint8_t* DartUtilities::vmIsolateSnapshot() |
| { |
| return snapshotBuffer(VmIsolateSnapshotId); |
| } |
| |
| const uint8_t* DartUtilities::isolateSnapshot() |
| { |
| return snapshotBuffer(IsolateSnapshotId); |
| } |
| |
| Dart_Handle DartUtilities::canonicalizeUrl(Dart_Handle library, Dart_Handle urlHandle, String url) |
| { |
| DEFINE_STATIC_LOCAL(String, dartPrefix, ("dart:")); |
| DEFINE_STATIC_LOCAL(String, packagePrefix, ("package:")); |
| |
| if (url.startsWith(dartPrefix) || url.startsWith(packagePrefix)) |
| // Not a relative URL. |
| return urlHandle; |
| |
| Dart_Handle libraryURLHandle = Dart_LibraryUrl(library); |
| ASSERT(!Dart_IsError(libraryURLHandle)); |
| String libraryURL = DartUtilities::toString(libraryURLHandle); |
| |
| String result; |
| if (libraryURL.startsWith(packagePrefix) && !libraryURL.startsWith("package://")) { |
| // KURL expects a URL with an authority. If the library URL is |
| // "package:<path>", we convert to "package://_/<path>" for resolution |
| // and convert back. |
| DEFINE_STATIC_LOCAL(String, resolvePrefix, ("package://_/")); |
| |
| libraryURL = resolvePrefix + libraryURL.substring(packagePrefix.length()); |
| result = KURL(KURL(KURL(), libraryURL), url).string(); |
| if (result.startsWith(resolvePrefix)) |
| result = packagePrefix + result.substring(resolvePrefix.length()); |
| } else { |
| result = KURL(KURL(KURL(), libraryURL), url).string(); |
| } |
| |
| return DartUtilities::stringToDartString(result); |
| } |
| |
| void DartUtilities::reportProblem(ExecutionContext* context, const String& error, int line, int col) |
| { |
| String sourceURL = context->url().string(); |
| |
| // FIXME: Pass in stack trace. |
| if (context && context->isDocument()) { |
| int scriptId = 0; |
| static_cast<Document*>(context)->reportException(ErrorEvent::create(error, sourceURL, line, col, 0), scriptId, nullptr, NotSharableCrossOrigin); |
| } |
| } |
| |
| void DartUtilities::reportProblem(ExecutionContext* context, Dart_Handle result) |
| { |
| // FIXME: provide sourceURL. |
| String sourceURL = "FIXME"; |
| reportProblem(context, result, sourceURL); |
| } |
| |
| void DartUtilities::reportProblem(ExecutionContext* context, Dart_Handle result, const String& sourceURL) |
| { |
| ASSERT(Dart_IsError(result)); |
| ASSERT(!sourceURL.isEmpty()); |
| |
| const String internalErrorPrefix("Internal error: "); |
| |
| String errorMessage; |
| // FIXME: line number info. |
| int lineNumber = 0; |
| // FIXME: call stack info. |
| RefPtr<ScriptCallStack> callStack; |
| |
| if (!Dart_ErrorHasException(result)) { |
| errorMessage = internalErrorPrefix + Dart_GetError(result); |
| } else { |
| // Print the exception. |
| Dart_Handle exception = Dart_ErrorGetException(result); |
| ASSERT(!Dart_IsError(exception)); |
| |
| exception = Dart_ToString(exception); |
| if (Dart_IsError(exception)) |
| errorMessage = String("Error: ") + Dart_GetError(exception); |
| else |
| errorMessage = String("Exception: ") + DartUtilities::toString(exception); |
| |
| // Print the stack trace. |
| Dart_StackTrace stacktrace; |
| Dart_Handle traceResult = Dart_GetStackTraceFromError(result, &stacktrace); |
| ALLOW_UNUSED_LOCAL(traceResult); |
| ASSERT(!Dart_IsError(traceResult)); |
| callStack = createScriptCallStackFromStackTrace(stacktrace); |
| } |
| |
| if (context && context->isDocument()) { |
| int scriptId = 0; |
| static_cast<Document*>(context)->reportException(ErrorEvent::create(errorMessage, sourceURL, lineNumber, 0, 0), scriptId, callStack, NotSharableCrossOrigin); |
| } |
| } |
| |
| Dart_Handle DartUtilities::toDartCoreException(const String& className, const String& message) |
| { |
| DartApiScope apiScope; |
| DartDOMData* domData = DartDOMData::current(); |
| Dart_Handle coreLib = Dart_LookupLibrary(Dart_NewStringFromCString("dart:core")); |
| Dart_Handle errorClass = Dart_GetType(coreLib, stringToDart(className), 0, 0); |
| Dart_Handle dartMessage = stringToDart(message); |
| Dart_Handle error = Dart_New(errorClass, Dart_NewStringFromCString(""), 1, &dartMessage); |
| Dart_SetPersistentHandle(domData->currentException(), error); |
| return domData->currentException(); |
| } |
| |
| Dart_Handle DartUtilities::coreArgumentErrorException(const String& message) |
| { |
| return DartUtilities::toDartCoreException("ArgumentError", message); |
| } |
| |
| Dart_Handle DartUtilities::notImplementedException(const char* fileName, int lineNumber) |
| { |
| Dart_Handle args[2] = { Dart_NewStringFromCString(fileName), Dart_NewInteger(lineNumber) }; |
| Dart_Handle result = DartUtilities::invokeUtilsMethod("makeUnimplementedError", 2, args); |
| ASSERT(!Dart_IsError(result)); |
| return result; |
| } |
| |
| Dart_Handle DartUtilities::newResolvedPromise(Dart_Handle value) |
| { |
| Dart_Handle asyncLib = Dart_LookupLibrary(Dart_NewStringFromCString("dart:async")); |
| Dart_Handle futureClass = Dart_GetType(asyncLib, Dart_NewStringFromCString("Future"), 0, 0); |
| return Dart_New(futureClass, Dart_NewStringFromCString("value"), 1, &value); |
| } |
| |
| Dart_Handle DartUtilities::newSmashedPromise(Dart_Handle error) |
| { |
| Dart_Handle asyncLib = Dart_LookupLibrary(Dart_NewStringFromCString("dart:async")); |
| Dart_Handle futureClass = Dart_GetType(asyncLib, Dart_NewStringFromCString("Future"), 0, 0); |
| return Dart_New(futureClass, Dart_NewStringFromCString("error"), 1, &error); |
| } |
| |
| Dart_Handle DartUtilities::newResolver() |
| { |
| Dart_Handle asyncLib = Dart_LookupLibrary(Dart_NewStringFromCString("dart:async")); |
| Dart_Handle futureClass = Dart_GetType(asyncLib, Dart_NewStringFromCString("Completer"), 0, 0); |
| return Dart_New(futureClass, Dart_EmptyString(), 0, 0); |
| } |
| |
| Dart_Handle DartUtilities::newArgumentError(const String& message) |
| { |
| Dart_Handle asyncLib = Dart_LookupLibrary(Dart_NewStringFromCString("dart:core")); |
| Dart_Handle futureClass = Dart_GetType(asyncLib, Dart_NewStringFromCString("ArgumentError"), 0, 0); |
| Dart_Handle dartMessage = stringToDart(message); |
| return Dart_New(futureClass, Dart_EmptyString(), 1, &dartMessage); |
| } |
| |
| Dart_Handle DartUtilities::invokeUtilsMethod(const char* methodName, int argCount, Dart_Handle* args) |
| { |
| DartDOMData* domData = DartDOMData::current(); |
| ASSERT(domData); |
| Dart_PersistentHandle library = domData->htmlLibrary(); |
| ASSERT(!Dart_IsError(library)); |
| |
| Dart_Handle utilsClass = Dart_GetType(library, Dart_NewStringFromCString("_Utils"), 0, 0); |
| ASSERT(!Dart_IsError(utilsClass)); |
| |
| return Dart_Invoke(utilsClass, Dart_NewStringFromCString(methodName), argCount, args); |
| } |
| |
| |
| int DartUtilities::getProp(const char* name, char* value, int valueLen) |
| { |
| #if OS(ANDROID) |
| return __system_property_get(name, value); |
| #else |
| char* v = getenv(name); |
| if (!v) { |
| return 0; |
| } |
| ASSERT(valueLen > 0 && static_cast<size_t>(valueLen) > strlen(v)); |
| strncpy(value, v, valueLen); |
| value[valueLen - 1] = '\0'; |
| return strlen(value); |
| #endif |
| } |
| } |