+2014-07-22 Mark Lam <mark.lam@apple.com>
+
+ Array.concat() should work on runtime arrays too.
+ <https://webkit.org/b/135179>
+
+ Reviewed by Geoffrey Garen.
+
+ * jsc.cpp:
+ (WTF::RuntimeArray::create):
+ (WTF::RuntimeArray::~RuntimeArray):
+ (WTF::RuntimeArray::destroy):
+ (WTF::RuntimeArray::getOwnPropertySlot):
+ (WTF::RuntimeArray::getOwnPropertySlotByIndex):
+ (WTF::RuntimeArray::put):
+ (WTF::RuntimeArray::deleteProperty):
+ (WTF::RuntimeArray::getLength):
+ (WTF::RuntimeArray::createPrototype):
+ (WTF::RuntimeArray::createStructure):
+ (WTF::RuntimeArray::finishCreation):
+ (WTF::RuntimeArray::RuntimeArray):
+ (WTF::RuntimeArray::lengthGetter):
+ (GlobalObject::finishCreation):
+ (functionCreateRuntimeArray):
+ - Added support to create a runtime array for testing purpose.
+ * runtime/ArrayPrototype.cpp:
+ (JSC::getLength):
+ - Added fast case for when the array object is a JSArray.
+ (JSC::arrayProtoFuncJoin):
+ - Added a needed but missing exception check.
+ (JSC::arrayProtoFuncConcat):
+ - Use getLength() to compute the array length instead of assuming that
+ the array is a JSArray instance.
+ * tests/stress/regexp-matches-array.js: Added.
+ (testArrayConcat):
+ * tests/stress/runtime-array.js: Added.
+ (testArrayConcat):
+
2014-07-22 Brent Fulgham <bfulgham@apple.com>
Fix Windows (return a value!)
#include "config.h"
+#include "ArrayPrototype.h"
#include "ButterflyInlines.h"
#include "BytecodeGenerator.h"
#include "Completion.h"
class ElementHandleOwner;
class Masuqerader;
class Root;
+class RuntimeArray;
class Element : public JSNonFinalObject {
public:
WriteBarrier<JSObject> m_delegate;
};
+class RuntimeArray : public JSArray {
+public:
+ typedef JSArray Base;
+
+ static RuntimeArray* create(ExecState* exec)
+ {
+ VM& vm = exec->vm();
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ Structure* structure = createStructure(vm, globalObject, createPrototype(vm, globalObject));
+ RuntimeArray* runtimeArray = new (NotNull, allocateCell<RuntimeArray>(*exec->heap())) RuntimeArray(exec, structure);
+ runtimeArray->finishCreation(exec);
+ vm.heap.addFinalizer(runtimeArray, destroy);
+ return runtimeArray;
+ }
+
+ ~RuntimeArray() { }
+
+ static void destroy(JSCell* cell)
+ {
+ static_cast<RuntimeArray*>(cell)->RuntimeArray::~RuntimeArray();
+ }
+
+ static const bool needsDestruction = false;
+
+ static bool getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+ {
+ RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
+ if (propertyName == exec->propertyNames().length) {
+ slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter);
+ return true;
+ }
+
+ unsigned index = propertyName.asIndex();
+ if (index < thisObject->getLength()) {
+ ASSERT(index != PropertyName::NotAnIndex);
+ slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
+ return true;
+ }
+
+ return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ }
+
+ static bool getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned index, PropertySlot& slot)
+ {
+ RuntimeArray* thisObject = jsCast<RuntimeArray*>(object);
+ if (index < thisObject->getLength()) {
+ slot.setValue(thisObject, DontDelete | DontEnum, jsNumber(thisObject->m_vector[index]));
+ return true;
+ }
+
+ return JSObject::getOwnPropertySlotByIndex(thisObject, exec, index, slot);
+ }
+
+ static NO_RETURN_DUE_TO_CRASH void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&)
+ {
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
+ static NO_RETURN_DUE_TO_CRASH bool deleteProperty(JSCell*, ExecState*, PropertyName)
+ {
+ RELEASE_ASSERT_NOT_REACHED();
+ }
+
+ unsigned getLength() const { return m_vector.size(); }
+
+ DECLARE_INFO;
+
+ static ArrayPrototype* createPrototype(VM&, JSGlobalObject* globalObject)
+ {
+ return globalObject->arrayPrototype();
+ }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info(), ArrayClass);
+ }
+
+protected:
+ void finishCreation(ExecState* exec)
+ {
+ Base::finishCreation(exec->vm());
+ ASSERT(inherits(info()));
+
+ for (size_t i = 0; i < exec->argumentCount(); i++)
+ m_vector.append(exec->argument(i).toInt32(exec));
+ }
+
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames | JSArray::StructureFlags;
+
+private:
+ RuntimeArray(ExecState* exec, Structure* structure)
+ : JSArray(exec->vm(), structure, 0)
+ {
+ }
+
+ static EncodedJSValue lengthGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName)
+ {
+ RuntimeArray* thisObject = jsDynamicCast<RuntimeArray*>(JSValue::decode(thisValue));
+ if (!thisObject)
+ return throwVMTypeError(exec);
+ return JSValue::encode(jsNumber(thisObject->getLength()));
+ }
+
+ Vector<int> m_vector;
+};
+
const ClassInfo Element::s_info = { "Element", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Element) };
const ClassInfo Masquerader::s_info = { "Masquerader", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Masquerader) };
const ClassInfo Root::s_info = { "Root", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(Root) };
const ClassInfo ImpureGetter::s_info = { "ImpureGetter", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ImpureGetter) };
+const ClassInfo RuntimeArray::s_info = { "RuntimeArray", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(RuntimeArray) };
ElementHandleOwner* Element::handleOwner()
{
static bool fillBufferWithContentsOfFile(const String& fileName, Vector<char>& buffer);
static EncodedJSValue JSC_HOST_CALL functionCreateProxy(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionSetImpureGetterDelegate(ExecState*);
addFunction(vm, "makeMasquerader", functionMakeMasquerader, 0);
addFunction(vm, "createProxy", functionCreateProxy, 1);
+ addFunction(vm, "createRuntimeArray", functionCreateRuntimeArray, 0);
addFunction(vm, "createImpureGetter", functionCreateImpureGetter, 1);
addFunction(vm, "setImpureGetterDelegate", functionSetImpureGetterDelegate, 2);
return JSValue::encode(proxy);
}
+EncodedJSValue JSC_HOST_CALL functionCreateRuntimeArray(ExecState* exec)
+{
+ JSLockHolder lock(exec);
+ RuntimeArray* array = RuntimeArray::create(exec);
+ return JSValue::encode(array);
+}
+
EncodedJSValue JSC_HOST_CALL functionCreateImpureGetter(ExecState* exec)
{
JSLockHolder lock(exec);
static ALWAYS_INLINE unsigned getLength(ExecState* exec, JSObject* obj)
{
+ if (isJSArray(obj))
+ return jsCast<JSArray*>(obj)->length();
return obj->get(exec, exec->propertyNames().length).toUInt32(exec);
}
for (; k < length; k++) {
JSValue element = thisObj->get(exec, k);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
if (!element.isUndefinedOrNull())
stringJoiner.append(element.toWTFStringInline(exec));
else
Checked<unsigned, RecordOverflow> finalArraySize = 0;
for (size_t i = 0;;) {
- if (JSArray* currentArray = jsDynamicCast<JSArray*>(curArg))
- finalArraySize += currentArray->length();
- else
+ if (JSArray* currentArray = jsDynamicCast<JSArray*>(curArg)) {
+ finalArraySize += getLength(exec, currentArray);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ } else
finalArraySize++;
if (i == argCount)
break;
unsigned n = 0;
for (size_t i = 0;;) {
if (JSArray* currentArray = jsDynamicCast<JSArray*>(curArg)) {
- unsigned length = currentArray->length();
+ unsigned length = getLength(exec, currentArray);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
for (unsigned k = 0; k < length; ++k) {
JSValue v = getProperty(exec, currentArray, k);
if (exec->hadException())