/* * Copyright (c) 2010 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 "sky/engine/config.h" #include "sky/engine/core/inspector/ScriptArguments.h" #include "sky/engine/bindings/core/v8/ScriptValue.h" #include "sky/engine/bindings/core/v8/V8Binding.h" #include "sky/engine/wtf/text/StringBuilder.h" #include "v8/include/v8.h" namespace blink { namespace { static const unsigned maxArrayItemsLimit = 10000; static const unsigned maxStackDepthLimit = 32; class V8ValueStringBuilder { public: static String toString(v8::Handle value, v8::Isolate* isolate) { V8ValueStringBuilder builder(isolate); if (!builder.append(value)) return String(); return builder.toString(); } private: enum { IgnoreNull = 1 << 0, IgnoreUndefined = 1 << 1, }; V8ValueStringBuilder(v8::Isolate* isolate) : m_arrayLimit(maxArrayItemsLimit) , m_isolate(isolate) { } bool append(v8::Handle value, unsigned ignoreOptions = 0) { if (value.IsEmpty()) return true; if ((ignoreOptions & IgnoreNull) && value->IsNull()) return true; if ((ignoreOptions & IgnoreUndefined) && value->IsUndefined()) return true; if (value->IsString()) return append(v8::Handle::Cast(value)); if (value->IsStringObject()) return append(v8::Handle::Cast(value)->ValueOf()); if (value->IsSymbol()) return append(v8::Handle::Cast(value)); if (value->IsSymbolObject()) return append(v8::Handle::Cast(value)->ValueOf()); if (value->IsNumberObject()) { m_builder.appendNumber(v8::Handle::Cast(value)->ValueOf()); return true; } if (value->IsBooleanObject()) { m_builder.append(v8::Handle::Cast(value)->ValueOf() ? "true" : "false"); return true; } if (value->IsArray()) return append(v8::Handle::Cast(value)); if (toDOMWindow(value, m_isolate)) { m_builder.append("[object Window]"); return true; } if (value->IsObject() && !value->IsDate() && !value->IsFunction() && !value->IsNativeError() && !value->IsRegExp()) return append(v8::Handle::Cast(value)->ObjectProtoToString()); return append(value->ToString()); } bool append(v8::Handle array) { if (m_visitedArrays.contains(array)) return true; uint32_t length = array->Length(); if (length > m_arrayLimit) return false; if (m_visitedArrays.size() > maxStackDepthLimit) return false; bool result = true; m_arrayLimit -= length; m_visitedArrays.append(array); for (uint32_t i = 0; i < length; ++i) { if (i) m_builder.append(','); if (!append(array->Get(i), IgnoreNull | IgnoreUndefined)) { result = false; break; } } m_visitedArrays.removeLast(); return result; } bool append(v8::Handle symbol) { m_builder.appendLiteral("Symbol("); bool result = append(symbol->Name(), IgnoreUndefined); m_builder.append(')'); return result; } bool append(v8::Handle string) { if (m_tryCatch.HasCaught()) return false; if (!string.IsEmpty()) m_builder.append(toCoreString(string)); return true; } String toString() { if (m_tryCatch.HasCaught()) return String(); return m_builder.toString(); } uint32_t m_arrayLimit; v8::Isolate* m_isolate; StringBuilder m_builder; Vector > m_visitedArrays; v8::TryCatch m_tryCatch; }; } // namespace DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(ScriptArguments) PassRefPtr ScriptArguments::create(ScriptState* scriptState, Vector& arguments) { return adoptRef(new ScriptArguments(scriptState, arguments)); } ScriptArguments::ScriptArguments(ScriptState* scriptState, Vector& arguments) : m_scriptState(scriptState) { m_arguments.swap(arguments); } const ScriptValue &ScriptArguments::argumentAt(size_t index) const { ASSERT(m_arguments.size() > index); return m_arguments[index]; } bool ScriptArguments::getFirstArgumentAsString(String& result, bool checkForNullOrUndefined) { if (!argumentCount()) return false; const ScriptValue& value = argumentAt(0); ScriptState::Scope scope(m_scriptState.get()); if (checkForNullOrUndefined && (value.isNull() || value.isUndefined())) return false; result = V8ValueStringBuilder::toString(value.v8Value(), value.isolate()); return true; } } // namespace blink