📄 arrayprototype.cpp
字号:
/* * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2003 Peter Kelly (pmk@post.com) * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * */#include "config.h"#include "ArrayPrototype.h"#include "CodeBlock.h"#include "Interpreter.h"#include "JIT.h"#include "ObjectPrototype.h"#include "Lookup.h"#include "Operations.h"#include <algorithm>#include <wtf/Assertions.h>#include <wtf/HashSet.h>namespace JSC {ASSERT_CLASS_FITS_IN_CELL(ArrayPrototype);static JSValuePtr arrayProtoFuncToString(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncToLocaleString(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncConcat(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncJoin(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncPop(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncPush(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncReverse(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncShift(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncSlice(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncSort(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncSplice(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncUnShift(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncEvery(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncForEach(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncSome(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncIndexOf(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncFilter(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncMap(ExecState*, JSObject*, JSValuePtr, const ArgList&);static JSValuePtr arrayProtoFuncLastIndexOf(ExecState*, JSObject*, JSValuePtr, const ArgList&);}#include "ArrayPrototype.lut.h"namespace JSC {static inline bool isNumericCompareFunction(CallType callType, const CallData& callData){ if (callType != CallTypeJS) return false; CodeBlock& codeBlock = callData.js.functionBody->bytecode(callData.js.scopeChain);#if ENABLE(JIT) // If the JIT is enabled then we need to preserve the invariant that every // function with a CodeBlock also has JIT code. if (!codeBlock.jitCode()) JIT::compile(callData.js.scopeChain->globalData, &codeBlock);#endif return codeBlock.isNumericCompareFunction();}// ------------------------------ ArrayPrototype ----------------------------const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::arrayTable};/* Source for ArrayPrototype.lut.h@begin arrayTable 16 toString arrayProtoFuncToString DontEnum|Function 0 toLocaleString arrayProtoFuncToLocaleString DontEnum|Function 0 concat arrayProtoFuncConcat DontEnum|Function 1 join arrayProtoFuncJoin DontEnum|Function 1 pop arrayProtoFuncPop DontEnum|Function 0 push arrayProtoFuncPush DontEnum|Function 1 reverse arrayProtoFuncReverse DontEnum|Function 0 shift arrayProtoFuncShift DontEnum|Function 0 slice arrayProtoFuncSlice DontEnum|Function 2 sort arrayProtoFuncSort DontEnum|Function 1 splice arrayProtoFuncSplice DontEnum|Function 2 unshift arrayProtoFuncUnShift DontEnum|Function 1 every arrayProtoFuncEvery DontEnum|Function 1 forEach arrayProtoFuncForEach DontEnum|Function 1 some arrayProtoFuncSome DontEnum|Function 1 indexOf arrayProtoFuncIndexOf DontEnum|Function 1 lastIndexOf arrayProtoFuncLastIndexOf DontEnum|Function 1 filter arrayProtoFuncFilter DontEnum|Function 1 map arrayProtoFuncMap DontEnum|Function 1@end*/// ECMA 15.4.4ArrayPrototype::ArrayPrototype(PassRefPtr<Structure> structure) : JSArray(structure){}bool ArrayPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot){ return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayTable(exec), this, propertyName, slot);}// ------------------------------ Array Functions ----------------------------// Helper functionstatic JSValuePtr getProperty(ExecState* exec, JSObject* obj, unsigned index){ PropertySlot slot(obj); if (!obj->getPropertySlot(exec, index, slot)) return noValue(); return slot.getValue(exec, index);}static void putProperty(ExecState* exec, JSObject* obj, const Identifier& propertyName, JSValuePtr value){ PutPropertySlot slot; obj->put(exec, propertyName, value, slot);}JSValuePtr arrayProtoFuncToString(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList&){ if (!thisValue.isObject(&JSArray::info)) return throwError(exec, TypeError); JSObject* thisObj = asArray(thisValue); HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; if (arrayVisitedElements.size() > MaxReentryDepth) return throwError(exec, RangeError, "Maximum call stack size exceeded."); bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; if (alreadyVisited) return jsEmptyString(exec); // return an empty string, avoiding infinite recursion. Vector<UChar, 256> strBuffer; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned k = 0; k < length; k++) { if (k >= 1) strBuffer.append(','); if (!strBuffer.data()) { JSObject* error = Error::create(exec, GeneralError, "Out of memory"); exec->setException(error); break; } JSValuePtr element = thisObj->get(exec, k); if (element.isUndefinedOrNull()) continue; UString str = element.toString(exec); strBuffer.append(str.data(), str.size()); if (!strBuffer.data()) { JSObject* error = Error::create(exec, GeneralError, "Out of memory"); exec->setException(error); } if (exec->hadException()) break; } arrayVisitedElements.remove(thisObj); return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0));}JSValuePtr arrayProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList&){ if (!thisValue.isObject(&JSArray::info)) return throwError(exec, TypeError); JSObject* thisObj = asArray(thisValue); HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; if (arrayVisitedElements.size() > MaxReentryDepth) return throwError(exec, RangeError, "Maximum call stack size exceeded."); bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; if (alreadyVisited) return jsEmptyString(exec); // return an empty string, avoding infinite recursion. Vector<UChar, 256> strBuffer; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned k = 0; k < length; k++) { if (k >= 1) strBuffer.append(','); if (!strBuffer.data()) { JSObject* error = Error::create(exec, GeneralError, "Out of memory"); exec->setException(error); break; } JSValuePtr element = thisObj->get(exec, k); if (element.isUndefinedOrNull()) continue; JSObject* o = element.toObject(exec); JSValuePtr conversionFunction = o->get(exec, exec->propertyNames().toLocaleString); UString str; CallData callData; CallType callType = conversionFunction.getCallData(callData); if (callType != CallTypeNone) str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec); else str = element.toString(exec); strBuffer.append(str.data(), str.size()); if (!strBuffer.data()) { JSObject* error = Error::create(exec, GeneralError, "Out of memory"); exec->setException(error); } if (exec->hadException()) break; } arrayVisitedElements.remove(thisObj); return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0));}JSValuePtr arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args){ JSObject* thisObj = thisValue.toThisObject(exec); HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; if (arrayVisitedElements.size() > MaxReentryDepth) return throwError(exec, RangeError, "Maximum call stack size exceeded."); bool alreadyVisited = !arrayVisitedElements.add(thisObj).second; if (alreadyVisited) return jsEmptyString(exec); // return an empty string, avoding infinite recursion. Vector<UChar, 256> strBuffer; UChar comma = ','; UString separator = args.at(exec, 0).isUndefined() ? UString(&comma, 1) : args.at(exec, 0).toString(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned k = 0; k < length; k++) { if (k >= 1) strBuffer.append(separator.data(), separator.size()); if (!strBuffer.data()) { JSObject* error = Error::create(exec, GeneralError, "Out of memory"); exec->setException(error); break; } JSValuePtr element = thisObj->get(exec, k); if (element.isUndefinedOrNull()) continue; UString str = element.toString(exec); strBuffer.append(str.data(), str.size()); if (!strBuffer.data()) { JSObject* error = Error::create(exec, GeneralError, "Out of memory"); exec->setException(error); } if (exec->hadException()) break; } arrayVisitedElements.remove(thisObj); return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0));}JSValuePtr arrayProtoFuncConcat(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args){ JSArray* arr = constructEmptyArray(exec); int n = 0; JSValuePtr curArg = thisValue.toThisObject(exec); ArgList::const_iterator it = args.begin(); ArgList::const_iterator end = args.end(); while (1) { if (curArg.isObject(&JSArray::info)) { unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec); JSObject* curObject = curArg.toObject(exec); for (unsigned k = 0; k < length; ++k) { if (JSValuePtr v = getProperty(exec, curObject, k)) arr->put(exec, n, v); n++; } } else { arr->put(exec, n, curArg); n++; } if (it == end) break; curArg = (*it).jsValue(exec); ++it; } arr->setLength(n); return arr;}JSValuePtr arrayProtoFuncPop(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList&){ if (isJSArray(&exec->globalData(), thisValue)) return asArray(thisValue)->pop(); JSObject* thisObj = thisValue.toThisObject(exec); JSValuePtr result; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (length == 0) { putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length)); result = jsUndefined(); } else { result = thisObj->get(exec, length - 1); thisObj->deleteProperty(exec, length - 1); putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - 1)); } return result;}JSValuePtr arrayProtoFuncPush(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args){ if (isJSArray(&exec->globalData(), thisValue) && args.size() == 1) { JSArray* array = asArray(thisValue); array->push(exec, args.begin()->jsValue(exec)); return jsNumber(exec, array->length()); } JSObject* thisObj = thisValue.toThisObject(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned n = 0; n < args.size(); n++) thisObj->put(exec, length + n, args.at(exec, n)); length += args.size(); putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length)); return jsNumber(exec, length);}JSValuePtr arrayProtoFuncReverse(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList&){ JSObject* thisObj = thisValue.toThisObject(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); unsigned middle = length / 2; for (unsigned k = 0; k < middle; k++) { unsigned lk1 = length - k - 1; JSValuePtr obj2 = getProperty(exec, thisObj, lk1); JSValuePtr obj = getProperty(exec, thisObj, k); if (obj2) thisObj->put(exec, k, obj2); else thisObj->deleteProperty(exec, k); if (obj) thisObj->put(exec, lk1, obj); else thisObj->deleteProperty(exec, lk1); } return thisObj;}JSValuePtr arrayProtoFuncShift(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList&){ JSObject* thisObj = thisValue.toThisObject(exec); JSValuePtr result; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (length == 0) { putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length)); result = jsUndefined(); } else { result = thisObj->get(exec, 0); for (unsigned k = 1; k < length; k++) { if (JSValuePtr obj = getProperty(exec, thisObj, k)) thisObj->put(exec, k - 1, obj); else thisObj->deleteProperty(exec, k - 1); } thisObj->deleteProperty(exec, length - 1); putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(exec, length - 1)); } return result;}JSValuePtr arrayProtoFuncSlice(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args){ // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10 JSObject* thisObj = thisValue.toThisObject(exec); // We return a new array JSArray* resObj = constructEmptyArray(exec); JSValuePtr result = resObj; double begin = args.at(exec, 0).toInteger(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); if (begin >= 0) { if (begin > length) begin = length; } else { begin += length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -