]> git.saurik.com Git - apple/javascriptcore.git/commitdiff
JavaScriptCore-7600.1.4.15.12.tar.gz ios-83 v7600.1.4.15.12
authorApple <opensource@apple.com>
Fri, 6 Mar 2015 22:29:10 +0000 (22:29 +0000)
committerApple <opensource@apple.com>
Fri, 6 Mar 2015 22:29:10 +0000 (22:29 +0000)
51 files changed:
API/JSObjectRef.cpp
API/JSWeakObjectMapRefPrivate.cpp
API/JSWrapperMap.mm
API/tests/CustomGlobalObjectClassTest.c
API/tests/CustomGlobalObjectClassTest.h
API/tests/Regress141809.h [new file with mode: 0644]
API/tests/Regress141809.mm [new file with mode: 0644]
API/tests/testapi.c
API/tests/testapi.mm
ChangeLog
Configurations/LLVMForJSC.xcconfig
Configurations/Version.xcconfig
JavaScriptCore.xcodeproj/project.pbxproj
assembler/ARMv7Assembler.h
bytecompiler/NodesCodegen.cpp
dfg/DFGArrayMode.h
dfg/DFGGraph.h
dfg/DFGPlan.cpp
dfg/DFGStackLayoutPhase.cpp
disassembler/ARMv7/ARMv7DOpcode.cpp
disassembler/ARMv7/ARMv7DOpcode.h
ftl/FTLLowerDFGToLLVM.cpp
ftl/FTLLowerDFGToLLVM.h
heap/Heap.cpp
heap/Heap.h
heap/MachineStackMarker.cpp
heap/MachineStackMarker.h
inspector/InjectedScript.cpp
inspector/InjectedScript.h
inspector/InjectedScriptSource.js
inspector/JSGlobalObjectInspectorController.cpp
inspector/JSGlobalObjectInspectorController.h
inspector/agents/InspectorRuntimeAgent.cpp
inspector/agents/InspectorRuntimeAgent.h
inspector/protocol/Runtime.json
interpreter/Interpreter.cpp
jit/JITOpcodes.cpp
jit/RegisterSet.cpp
llint/LowLevelInterpreter.asm
llint/LowLevelInterpreter64.asm
llvm/LLVMAPIFunctions.h
llvm/library/LLVMExports.cpp
parser/ParserArena.h
runtime/MapData.cpp
runtime/VM.cpp
runtime/VM.h
tests/stress/get-my-argument-by-val-inlined-no-formal-parameters.js [new file with mode: 0644]
tests/stress/regress-141489.js [new file with mode: 0644]
tests/stress/throw-from-ftl-call-ic-slow-path-cells.js [new file with mode: 0644]
tests/stress/throw-from-ftl-call-ic-slow-path-undefined.js [new file with mode: 0644]
tests/stress/throw-from-ftl-call-ic-slow-path.js [new file with mode: 0644]

index b67c40b5081a914dee732fdcf5e1bc1cde0b31d3..dfad3bd7b476135f47890b6e5be63562624e552f 100644 (file)
@@ -302,6 +302,14 @@ void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value
     JSObject* jsObject = toJS(object);
     JSValue jsValue = toJS(exec, value);
 
+    if (JSProxy* proxy = jsDynamicCast<JSProxy*>(jsObject)) {
+        if (JSGlobalObject* globalObject = jsDynamicCast<JSGlobalObject*>(proxy->target())) {
+            globalObject->resetPrototype(exec->vm(), jsValue.isObject() ? jsValue : jsNull());
+            return;
+        }
+        // Someday we might use proxies for something other than JSGlobalObjects, but today is not that day.
+        RELEASE_ASSERT_NOT_REACHED();
+    }
     jsObject->setPrototypeWithCycleCheck(exec, jsValue.isObject() ? jsValue : jsNull());
 }
 
@@ -501,6 +509,11 @@ JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSSt
     JSObject* jsObject = toJS(object);
     JSValue result;
     Identifier name(propertyName->identifier(&exec->vm()));
+
+    // Get wrapped object if proxied
+    if (jsObject->inherits(JSProxy::info()))
+        jsObject = jsCast<JSProxy*>(jsObject)->target();
+
     if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info()))
         result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
     else if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info()))
@@ -519,6 +532,11 @@ bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRe
     JSObject* jsObject = toJS(object);
     JSValue jsValue = value ? toJS(exec, value) : JSValue();
     Identifier name(propertyName->identifier(&exec->vm()));
+
+    // Get wrapped object if proxied
+    if (jsObject->inherits(JSProxy::info()))
+        jsObject = jsCast<JSProxy*>(jsObject)->target();
+
     if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) {
         jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue);
         return true;
@@ -542,6 +560,11 @@ bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStrin
     JSLockHolder locker(exec);
     JSObject* jsObject = toJS(object);
     Identifier name(propertyName->identifier(&exec->vm()));
+
+    // Get wrapped object if proxied
+    if (jsObject->inherits(JSProxy::info()))
+        jsObject = jsCast<JSProxy*>(jsObject)->target();
+
     if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) {
         jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->deletePrivateProperty(name);
         return true;
index 5f38de2f79bccbf5749ff3400e44ab4d1121459c..446cf90135161ec24eb8eb5db12f934132fac754 100644 (file)
@@ -62,7 +62,9 @@ void JSWeakObjectMapSet(JSContextRef ctx, JSWeakObjectMapRef map, void* key, JSO
     JSObject* obj = toJS(object);
     if (!obj)
         return;
-    ASSERT(obj->inherits(JSCallbackObject<JSGlobalObject>::info()) || obj->inherits(JSCallbackObject<JSDestructibleObject>::info()));
+    ASSERT(obj->inherits(JSProxy::info())
+        || obj->inherits(JSCallbackObject<JSGlobalObject>::info()) 
+        || obj->inherits(JSCallbackObject<JSDestructibleObject>::info()));
     map->map().set(key, obj);
 }
 
index f6717b9e227b19e91f07f004da7f4c794aff8b8d..069de826729ab1c100ce3fc2d59be308bd1b5dbe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -363,15 +363,16 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
     JSC::Weak<JSC::JSObject> m_constructor;
 }
 
-- (id)initWithContext:(JSContext *)context forClass:(Class)cls superClassInfo:(JSObjCClassInfo*)superClassInfo;
+- (id)initWithContext:(JSContext *)context forClass:(Class)cls;
 - (JSValue *)wrapperForObject:(id)object;
 - (JSValue *)constructor;
+- (JSC::JSObject *)prototype;
 
 @end
 
 @implementation JSObjCClassInfo
 
-- (id)initWithContext:(JSContext *)context forClass:(Class)cls superClassInfo:(JSObjCClassInfo*)superClassInfo
+- (id)initWithContext:(JSContext *)context forClass:(Class)cls
 {
     self = [super init];
     if (!self)
@@ -386,8 +387,6 @@ static void copyPrototypeProperties(JSContext *context, Class objcClass, Protoco
     definition.className = className;
     m_classRef = JSClassCreate(&definition);
 
-    [self allocateConstructorAndPrototypeWithSuperClassInfo:superClassInfo];
-
     return self;
 }
 
@@ -449,8 +448,12 @@ static JSValue *allocateConstructorForCustomClass(JSContext *context, const char
     return constructorWithCustomBrand(context, [NSString stringWithFormat:@"%sConstructor", className], cls);
 }
 
-- (void)allocateConstructorAndPrototypeWithSuperClassInfo:(JSObjCClassInfo*)superClassInfo
+typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair;
+
+- (ConstructorPrototypePair)allocateConstructorAndPrototype
 {
+    JSObjCClassInfo* superClassInfo = [m_context.wrapperMap classInfoForClass:class_getSuperclass(m_class)];
+
     ASSERT(!m_constructor || !m_prototype);
     ASSERT((m_class == [NSObject class]) == !superClassInfo);
     if (!superClassInfo) {
@@ -464,11 +467,6 @@ static JSValue *allocateConstructorForCustomClass(JSContext *context, const char
             m_prototype = toJS(JSValueToObject(cContext, valueInternalValue(prototype), 0));
         }
     } else {
-        // We need to hold a reference to the superclass prototype here on the stack
-        // to that it won't get GC'ed while we do allocations between now and when we
-        // set it in this class' prototype below.
-        JSC::JSObject* superClassPrototype = superClassInfo->m_prototype.get();
-
         const char* className = class_getName(m_class);
 
         // Create or grab the prototype/constructor pair.
@@ -498,15 +496,10 @@ static JSValue *allocateConstructorForCustomClass(JSContext *context, const char
         });
 
         // Set [Prototype].
+        JSC::JSObject* superClassPrototype = [superClassInfo prototype];
         JSObjectSetPrototype([m_context JSGlobalContextRef], toRef(m_prototype.get()), toRef(superClassPrototype));
     }
-}
-
-- (void)reallocateConstructorAndOrPrototype
-{
-    [self allocateConstructorAndPrototypeWithSuperClassInfo:[m_context.wrapperMap classInfoForClass:class_getSuperclass(m_class)]];
-    // We should not add any code here that can trigger a GC or the prototype and
-    // constructor that we just created may be collected before they can be used.
+    return ConstructorPrototypePair(m_constructor.get(), m_prototype.get());
 }
 
 - (JSValue *)wrapperForObject:(id)object
@@ -523,12 +516,7 @@ static JSValue *allocateConstructorForCustomClass(JSContext *context, const char
         }
     }
 
-    if (!m_prototype)
-        [self reallocateConstructorAndOrPrototype];
-    ASSERT(!!m_prototype);
-    // We need to hold a reference to the prototype here on the stack to that it won't
-    // get GC'ed while we create the wrapper below.
-    JSC::JSObject* prototype = m_prototype.get();
+    JSC::JSObject* prototype = [self prototype];
 
     JSObjectRef wrapper = makeWrapper([m_context JSGlobalContextRef], m_classRef, object);
     JSObjectSetPrototype([m_context JSGlobalContextRef], wrapper, toRef(prototype));
@@ -537,13 +525,20 @@ static JSValue *allocateConstructorForCustomClass(JSContext *context, const char
 
 - (JSValue *)constructor
 {
-    if (!m_constructor)
-        [self reallocateConstructorAndOrPrototype];
-    ASSERT(!!m_constructor);
-    // If we need to add any code here in the future that can trigger a GC, we should
-    // cache the constructor pointer in a stack local var first so that it is protected
-    // from the GC until it gets used below.
-    return [JSValue valueWithJSValueRef:toRef(m_constructor.get()) inContext:m_context];
+    JSC::JSObject* constructor = m_constructor.get();
+    if (!constructor)
+        constructor = [self allocateConstructorAndPrototype].first;
+    ASSERT(!!constructor);
+    return [JSValue valueWithJSValueRef:toRef(constructor) inContext:m_context];
+}
+
+- (JSC::JSObject*)prototype
+{
+    JSC::JSObject* prototype = m_prototype.get();
+    if (!prototype)
+        prototype = [self allocateConstructorAndPrototype].second;
+    ASSERT(!!prototype);
+    return prototype;
 }
 
 @end
@@ -590,7 +585,7 @@ static JSValue *allocateConstructorForCustomClass(JSContext *context, const char
     if ('_' == *class_getName(cls))
         return m_classMap[cls] = [self classInfoForClass:class_getSuperclass(cls)];
 
-    return m_classMap[cls] = [[[JSObjCClassInfo alloc] initWithContext:m_context forClass:cls superClassInfo:[self classInfoForClass:class_getSuperclass(cls)]] autorelease];
+    return m_classMap[cls] = [[[JSObjCClassInfo alloc] initWithContext:m_context forClass:cls] autorelease];
 }
 
 - (JSValue *)jsWrapperForObject:(id)object
index ade3a0dc52cfab9435b2822b743192e4e31ab34e..62e63978ede6f7015b3633c77e4a16fc5f6f72e4 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "CustomGlobalObjectClassTest.h"
 
+#include <JavaScriptCore/JSObjectRefPrivate.h>
 #include <JavaScriptCore/JavaScriptCore.h>
 #include <stdio.h>
 
@@ -98,3 +99,47 @@ void customGlobalObjectClassTest()
 
     assertTrue(executedCallback, "Executed custom global object callback");
 }
+
+void globalObjectSetPrototypeTest()
+{
+    JSClassDefinition definition = kJSClassDefinitionEmpty;
+    definition.className = "Global";
+    JSClassRef global = JSClassCreate(&definition);
+    JSGlobalContextRef context = JSGlobalContextCreate(global);
+    JSObjectRef object = JSContextGetGlobalObject(context);
+
+    JSObjectRef above = JSObjectMake(context, 0, 0);
+    JSStringRef test = JSStringCreateWithUTF8CString("test");
+    JSValueRef value = JSValueMakeString(context, test);
+    JSObjectSetProperty(context, above, test, value, kJSPropertyAttributeDontEnum, 0);
+
+    JSObjectSetPrototype(context, object, above);
+    JSStringRef script = JSStringCreateWithUTF8CString("test === \"test\"");
+    JSValueRef result = JSEvaluateScript(context, script, 0, 0, 0, 0);
+
+    assertTrue(JSValueToBoolean(context, result), "test === \"test\"");
+
+    JSStringRelease(test);
+    JSStringRelease(script);
+}
+
+void globalObjectPrivatePropertyTest()
+{
+    JSClassDefinition definition = kJSClassDefinitionEmpty;
+    definition.className = "Global";
+    JSClassRef global = JSClassCreate(&definition);
+    JSGlobalContextRef context = JSGlobalContextCreate(global);
+    JSObjectRef globalObject = JSContextGetGlobalObject(context);
+
+    JSStringRef privateName = JSStringCreateWithUTF8CString("private");
+    JSValueRef privateValue = JSValueMakeString(context, privateName);
+    assertTrue(JSObjectSetPrivateProperty(context, globalObject, privateName, privateValue), "JSObjectSetPrivateProperty succeeded");
+    JSValueRef result = JSObjectGetPrivateProperty(context, globalObject, privateName);
+    assertTrue(JSValueIsStrictEqual(context, privateValue, result), "privateValue === \"private\"");
+
+    assertTrue(JSObjectDeletePrivateProperty(context, globalObject, privateName), "JSObjectDeletePrivateProperty succeeded");
+    result = JSObjectGetPrivateProperty(context, globalObject, privateName);
+    assertTrue(JSValueIsNull(context, result), "Deleted private property is indeed no longer present");
+
+    JSStringRelease(privateName);
+}
index 9f8630fcedec917095a44b2c99399d26c9adcae3..86914ca6f57d90b1010a11ac8136571d74e875dd 100644 (file)
@@ -27,5 +27,7 @@
 #define CustomGlobalObjectClassTest_h
 
 void customGlobalObjectClassTest(void);
+void globalObjectSetPrototypeTest(void);
+void globalObjectPrivatePropertyTest(void);
 
 #endif // CustomGlobalObjectClassTest_h
diff --git a/API/tests/Regress141809.h b/API/tests/Regress141809.h
new file mode 100644 (file)
index 0000000..43b099c
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#import <Foundation/Foundation.h>
+#import <JavaScriptCore/JavaScriptCore.h>
+
+#if JSC_OBJC_API_ENABLED
+
+void runRegress141809();
+
+#endif // JSC_OBJC_API_ENABLED
+
diff --git a/API/tests/Regress141809.mm b/API/tests/Regress141809.mm
new file mode 100644 (file)
index 0000000..16fd373
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#import "config.h"
+#import "Regress141809.h"
+
+#import <objc/objc.h>
+#import <objc/runtime.h>
+
+#if JSC_OBJC_API_ENABLED
+
+extern "C" void checkResult(NSString *description, bool passed);
+extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef);
+
+@protocol TestClassAExports <JSExport>
+@end
+
+@interface TestClassA : NSObject<TestClassAExports>
+@end
+
+@implementation TestClassA
+@end
+
+@protocol TestClassBExports <JSExport>
+- (NSString *)name;
+@end
+
+@interface TestClassB : TestClassA <TestClassBExports>
+@end
+
+@implementation TestClassB
+- (NSString *)name
+{
+    return @"B";
+}
+@end
+
+@protocol TestClassCExports <JSExport>
+- (NSString *)name;
+@end
+
+@interface TestClassC : TestClassB <TestClassCExports>
+@end
+
+@implementation TestClassC
+- (NSString *)name
+{
+    return @"C";
+}
+@end
+
+void runRegress141809()
+{
+    // Test that the ObjC API can correctly re-construct the synthesized
+    // prototype and constructor of JS exported ObjC classes.
+    // See <https://webkit.org/b/141809>
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        context[@"print"] = ^(NSString* str) {
+            NSLog(@"%@", str);
+        };
+        
+        [context evaluateScript:@"function dumpPrototypes(obj) { \
+            var objDepth = 0; \
+            var currObj = obj; \
+            var objChain = ''; \
+            do { \
+                var propIndex = 0; \
+                var props = ''; \
+                Object.getOwnPropertyNames(currObj).forEach(function(val, idx, array) { \
+                    props += ((propIndex > 0 ? ', ' : '') + val); \
+                    propIndex++; \
+                }); \
+                var str = ''; \
+                if (!objDepth) \
+                    str += 'obj '; \
+                else { \
+                    for (i = 0; i < objDepth; i++) \
+                        str += ' '; \
+                    str += '--> proto '; \
+                } \
+                str += currObj; \
+                if (props) \
+                    str += (' with ' + propIndex + ' props: ' + props); \
+                print(str); \
+                objChain += (str + '\\n'); \
+                objDepth++; \
+                currObj = Object.getPrototypeOf(currObj); \
+            } while (currObj); \
+            return { objDepth: objDepth, objChain: objChain }; \
+        }"];
+        JSValue* dumpPrototypes = context[@"dumpPrototypes"];
+        
+        JSValue* resultBeforeGC = nil;
+        @autoreleasepool {
+            TestClassC* obj = [[TestClassC alloc] init];
+            resultBeforeGC = [dumpPrototypes callWithArguments:@[obj]];
+        }
+        
+        JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
+        
+        @autoreleasepool {
+            TestClassC* obj = [[TestClassC alloc] init];
+            JSValue* resultAfterGC = [dumpPrototypes callWithArguments:@[obj]];
+            checkResult(@"object and prototype chain depth is 5 deep", [resultAfterGC[@"objDepth"] toInt32] == 5);
+            checkResult(@"object and prototype chain depth before and after GC matches", [resultAfterGC[@"objDepth"] toInt32] == [resultBeforeGC[@"objDepth"] toInt32]);
+            checkResult(@"object and prototype chain before and after GC matches", [[resultAfterGC[@"objChain"] toString] isEqualToString:[resultBeforeGC[@"objChain"] toString]]);
+        }
+    }
+}
+
+#endif // JSC_OBJC_API_ENABLED
index 9b29949f672f305d58f1db2845a22012b923b7fb..60d7dc0b593f00d6c7d8652917e6627df3789eb7 100644 (file)
@@ -2079,6 +2079,8 @@ int main(int argc, char* argv[])
         printf("PASS: global context name behaves as expected.\n");
 
     customGlobalObjectClassTest();
+    globalObjectSetPrototypeTest();
+    globalObjectPrivatePropertyTest();
 
     if (failed) {
         printf("FAIL: Some tests failed.\n");
index c528e691ee326b8a269eec79d6905da49afd5122..724867c6400e5876fd479234dd80c7d7e0e701c0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,9 @@
 #import "CurrentThisInsideBlockGetterTest.h"
 #import "DateTests.h"
 #import "JSExportTests.h"
+#import "Regress141809.h"
+
+#import <pthread.h>
 
 extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef);
 extern "C" void JSSynchronousEdenCollectForDebugging(JSContextRef);
@@ -470,6 +473,16 @@ static bool blockSignatureContainsClass()
     return containsClass;
 }
 
+static void* threadMain(void* contextPtr)
+{
+    JSContext *context = (__bridge JSContext*)contextPtr;
+
+    // Do something to enter the VM.
+    TestObject *testObject = [TestObject testObject];
+    context[@"testObject"] = testObject;
+    pthread_exit(nullptr);
+}
+
 void testObjectiveCAPI()
 {
     NSLog(@"Testing Objective-C API");
@@ -1359,9 +1372,21 @@ void testObjectiveCAPI()
         checkResult(@"EdenCollection doesn't reclaim new managed values", [managedJSObject value] != nil);
     }
 
+    @autoreleasepool {
+        JSContext *context = [[JSContext alloc] init];
+        
+        pthread_t threadID;
+        pthread_create(&threadID, NULL, &threadMain, (__bridge void*)context);
+        pthread_join(threadID, nullptr);
+        JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
+
+        checkResult(@"Did not crash after entering the VM from another thread", true);
+    }
+    
     currentThisInsideBlockGetterTest();
     runDateTests();
     runJSExportTests();
+    runRegress141809();
 }
 
 #else
index bbda15d843f9a35db88edd902b9dfa890870bc70..097cfa1a8153ca9208c179093e95280244bf385f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,681 @@
+2015-03-06  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r180234
+
+    2015-02-17  Filip Pizlo  <fpizlo@apple.com>
+
+            Throwing from an FTL call IC slow path may result in tag registers being clobbered on 64-bit CPUs
+            https://bugs.webkit.org/show_bug.cgi?id=141717
+            rdar://problem/19863382
+
+            Reviewed by Geoffrey Garen.
+
+            The best solution is to ensure that the engine catching an exception restores tag registers.
+
+            Each of these new test cases reliably crashed prior to this patch and they don't crash at all now.
+
+            * jit/JITOpcodes.cpp:
+            (JSC::JIT::emit_op_catch):
+            * llint/LowLevelInterpreter.asm:
+            * llint/LowLevelInterpreter64.asm:
+            * tests/stress/throw-from-ftl-call-ic-slow-path-cells.js: Added.
+            * tests/stress/throw-from-ftl-call-ic-slow-path-undefined.js: Added.
+            * tests/stress/throw-from-ftl-call-ic-slow-path.js: Added.
+
+2015-03-06  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r181030
+
+    2015-03-04  Filip Pizlo  <fpizlo@apple.com>
+
+            [FTL] inlined GetMyArgumentByVal with no arguments passed causes instant crash
+            https://bugs.webkit.org/show_bug.cgi?id=141180
+            rdar://problem/19677552
+
+            Reviewed by Benjamin Poulain.
+
+            If we do a GetMyArgumentByVal on an inlined call frame that has no arguments, then the
+            bounds check already terminates execution. This means we can skip the part where we
+            previously did an out-of-bound array access on the inlined call frame arguments vector.
+
+            * ftl/FTLLowerDFGToLLVM.cpp:
+            (JSC::FTL::LowerDFGToLLVM::safelyInvalidateAfterTermination):
+            (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal):
+            (JSC::FTL::LowerDFGToLLVM::terminate):
+            (JSC::FTL::LowerDFGToLLVM::didAlreadyTerminate):
+            (JSC::FTL::LowerDFGToLLVM::crash):
+            * tests/stress/get-my-argument-by-val-inlined-no-formal-parameters.js: Added.
+            (foo):
+            (bar):
+
+2015-03-04  Matthew Hanson  <matthew_hanson@apple.com>
+
+        Merge r180101. rdar://problem/19913017
+
+    2015-02-13  Joseph Pecoraro  <pecoraro@apple.com>
+
+            JSContext Inspector: Do not stash console messages for non-debuggable JSContext
+            https://bugs.webkit.org/show_bug.cgi?id=141589
+
+            Reviewed by Timothy Hatcher.
+
+            Consider developer extras disabled for JSContext inspection if the
+            RemoteInspector server is not enabled (typically a non-debuggable
+            process rejected by webinspectord) or if remote debugging on the
+            JSContext was explicitly disabled via SPI.
+
+            When developer extras are disabled, console message will not be stashed.
+
+            * inspector/JSGlobalObjectInspectorController.cpp:
+            (Inspector::JSGlobalObjectInspectorController::developerExtrasEnabled):
+            * inspector/JSGlobalObjectInspectorController.h:
+
+2015-02-26  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r180452
+
+    2015-02-20  Mark Lam  <mark.lam@apple.com>
+
+            [JSObjCClassInfo reallocateConstructorAndOrPrototype] should also reallocate super class prototype chain.
+            <https://webkit.org/b/141809>
+
+            Reviewed by Geoffrey Garen.
+
+            A ObjC class that implement the JSExport protocol will have a JS prototype
+            chain and constructor automatically synthesized for its JS wrapper object.
+            However, if there are no more instances of that ObjC class reachable by a
+            JS GC root scan, then its synthesized prototype chain and constructors may
+            be released by the GC.  If a new instance of that ObjC class is subsequently
+            instantiated, then [JSObjCClassInfo reallocateConstructorAndOrPrototype]
+            should re-construct the prototype chain and constructor (if they were
+            previously released).  However, the current implementation only
+            re-constructs the immediate prototype, but not every other prototype
+            object upstream in the prototype chain.
+
+            To fix this, we do the following:
+            1. We no longer allocate the JSObjCClassInfo's prototype and constructor
+               eagerly.  Hence, -initWithContext:forClass: will no longer call
+               -allocateConstructorAndPrototypeWithSuperClassInfo:.
+            2. Instead, we'll always access the prototype and constructor thru
+               accessor methods.  The accessor methods will call
+               -allocateConstructorAndPrototype: if needed.
+            3. -allocateConstructorAndPrototype: will fetch the needed superClassInfo
+               from the JSWrapperMap itself.  This makes it so that we no longer
+               need to pass the superClassInfo all over.
+            4. -allocateConstructorAndPrototype: will get the super class prototype
+               by invoking -prototype: on the superClassInfo, thereby allowing the
+               super class to allocate its prototype and constructor if needed and
+               fixing the issue in this bug.
+
+            5. Also removed the GC warning comments, and ensured that needed JS
+               objects are kept alive by having a local var pointing to it from the
+               stack (which makes a GC root).
+
+            * API/JSWrapperMap.mm:
+            (-[JSObjCClassInfo initWithContext:forClass:]):
+            (-[JSObjCClassInfo allocateConstructorAndPrototype]):
+            (-[JSObjCClassInfo wrapperForObject:]):
+            (-[JSObjCClassInfo constructor]):
+            (-[JSObjCClassInfo prototype]):
+            (-[JSWrapperMap classInfoForClass:]):
+            (-[JSObjCClassInfo initWithContext:forClass:superClassInfo:]): Deleted.
+            (-[JSObjCClassInfo allocateConstructorAndPrototypeWithSuperClassInfo:]): Deleted.
+            (-[JSObjCClassInfo reallocateConstructorAndOrPrototype]): Deleted.
+            * API/tests/Regress141809.h: Added.
+            * API/tests/Regress141809.mm: Added.
+            (-[TestClassB name]):
+            (-[TestClassC name]):
+            (runRegress141809):
+            * API/tests/testapi.mm:
+            * JavaScriptCore.xcodeproj/project.pbxproj:
+
+2015-02-25  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge patch for r180247 and r180249.
+
+    2015-02-20  Michael Saboff  <msaboff@apple.com>
+
+            CrashTracer: DFG_CRASH beneath JSC::FTL::LowerDFGToLLVM::compileNode
+            https://bugs.webkit.org/show_bug.cgi?id=141730
+
+            Reviewed by Geoffrey Garen.
+
+            Added a new failure handler, loweringFailed(), to LowerDFGToLLVM that reports failures
+            while processing DFG lowering.  For debug builds, the failures are logged identical
+            to the way the DFG_CRASH() reports them.  For release builds, the failures are reported
+            and that FTL compilation is terminated, but the process is allowed to continue.
+            Wrapped calls to loweringFailed() in a macro LOWERING_FAILED so the function and
+            line number are reported at the point of the inconsistancy.
+
+            Converted instances of DFG_CRASH to LOWERING_FAILED.
+
+            * dfg/DFGPlan.cpp:
+            (JSC::DFG::Plan::compileInThreadImpl): Added lowerDFGToLLVM() failure check that
+            will fail the FTL compile.
+
+            * ftl/FTLLowerDFGToLLVM.cpp:
+            (JSC::FTL::LowerDFGToLLVM::LowerDFGToLLVM):
+            Added new member variable, m_loweringSucceeded, to stop compilation on the first
+            reported failure.
+
+            * ftl/FTLLowerDFGToLLVM.cpp:
+            (JSC::FTL::LowerDFGToLLVM::lower):
+            * ftl/FTLLowerDFGToLLVM.h:
+            Added check for compilation failures and now report those failures via a boolean
+            return value.
+
+            * ftl/FTLLowerDFGToLLVM.cpp:
+            (JSC::FTL::LowerDFGToLLVM::createPhiVariables):
+            (JSC::FTL::LowerDFGToLLVM::compileNode):
+            (JSC::FTL::LowerDFGToLLVM::compileUpsilon):
+            (JSC::FTL::LowerDFGToLLVM::compilePhi):
+            (JSC::FTL::LowerDFGToLLVM::compileDoubleRep):
+            (JSC::FTL::LowerDFGToLLVM::compileValueRep):
+            (JSC::FTL::LowerDFGToLLVM::compileValueToInt32):
+            (JSC::FTL::LowerDFGToLLVM::compilePutLocal):
+            (JSC::FTL::LowerDFGToLLVM::compileArithAddOrSub):
+            (JSC::FTL::LowerDFGToLLVM::compileArithMul):
+            (JSC::FTL::LowerDFGToLLVM::compileArithDiv):
+            (JSC::FTL::LowerDFGToLLVM::compileArithMod):
+            (JSC::FTL::LowerDFGToLLVM::compileArithMinOrMax):
+            (JSC::FTL::LowerDFGToLLVM::compileArithAbs):
+            (JSC::FTL::LowerDFGToLLVM::compileArithNegate):
+            (JSC::FTL::LowerDFGToLLVM::compileArrayifyToStructure):
+            (JSC::FTL::LowerDFGToLLVM::compileGetById):
+            (JSC::FTL::LowerDFGToLLVM::compileGetMyArgumentByVal):
+            (JSC::FTL::LowerDFGToLLVM::compileGetArrayLength):
+            (JSC::FTL::LowerDFGToLLVM::compileGetByVal):
+            (JSC::FTL::LowerDFGToLLVM::compilePutByVal):
+            (JSC::FTL::LowerDFGToLLVM::compileArrayPush):
+            (JSC::FTL::LowerDFGToLLVM::compileArrayPop):
+            (JSC::FTL::LowerDFGToLLVM::compileNewArray):
+            (JSC::FTL::LowerDFGToLLVM::compileToString):
+            (JSC::FTL::LowerDFGToLLVM::compileMakeRope):
+            (JSC::FTL::LowerDFGToLLVM::compileCompareEq):
+            (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
+            (JSC::FTL::LowerDFGToLLVM::compileSwitch):
+            (JSC::FTL::LowerDFGToLLVM::compare):
+            (JSC::FTL::LowerDFGToLLVM::boolify):
+            (JSC::FTL::LowerDFGToLLVM::opposite):
+            (JSC::FTL::LowerDFGToLLVM::lowJSValue):
+            (JSC::FTL::LowerDFGToLLVM::speculate):
+            (JSC::FTL::LowerDFGToLLVM::isArrayType):
+            (JSC::FTL::LowerDFGToLLVM::exitValueForAvailability):
+            (JSC::FTL::LowerDFGToLLVM::exitValueForNode):
+            (JSC::FTL::LowerDFGToLLVM::setInt52):
+            Changed DFG_CRASH() to LOWERING_FAILED().  Updated related control flow as appropriate.
+
+            (JSC::FTL::LowerDFGToLLVM::loweringFailed): New error reporting member function.
+
+2015-02-25  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge r180516.
+
+    2015-02-23  Matthew Mirman  <mmirman@apple.com>
+
+            r9 is volatile on ARMv7 for iOS 3 and up. 
+            https://bugs.webkit.org/show_bug.cgi?id=141489
+            rdar://problem/19432916
+
+            Reviewed by Michael Saboff.
+
+            * jit/RegisterSet.cpp: 
+            (JSC::RegisterSet::calleeSaveRegisters): removed r9 from the list of ARMv7 callee save registers.
+            * tests/stress/regress-141489.js: Added.
+            (foo):
+
+2015-02-20  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r180237
+
+    2015-02-17  Filip Pizlo  <fpizlo@apple.com>
+
+            StackLayoutPhase should use CodeBlock::usesArguments rather than FunctionExecutable::usesArguments
+            https://bugs.webkit.org/show_bug.cgi?id=141721
+            rdar://problem/17198633
+
+            Reviewed by Michael Saboff.
+
+            I've seen cases where the two are out of sync.  We know we can trust the CodeBlock::usesArguments because
+            we use it everywhere else.
+
+            No test because I could never reproduce the crash.
+
+            * dfg/DFGGraph.h:
+            (JSC::DFG::Graph::usesArguments):
+            * dfg/DFGStackLayoutPhase.cpp:
+            (JSC::DFG::StackLayoutPhase::run):
+
+2015-02-20  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge r178224.
+
+    2015-01-09  Joseph Pecoraro  <pecoraro@apple.com>
+
+            Web Inspector: Uncaught Exception in ProbeManager deleting breakpoint
+            https://bugs.webkit.org/show_bug.cgi?id=140279
+            rdar://problem/19422299
+
+            Reviewed by Oliver Hunt.
+
+            * runtime/MapData.cpp:
+            (JSC::MapData::replaceAndPackBackingStore):
+            The cell table also needs to have its values fixed.
+
+2015-02-20  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge patch for rdar://problem/19828630.
+
+    2015-02-13  Filip Pizlo  <fpizlo@apple.com>
+
+            Effectful calls to length should only happen once on the varargs path.
+            rdar://problem/19828518
+
+            Reviewed by Michael Saboff.
+
+            * interpreter/Interpreter.cpp:
+            (JSC::sizeFrameForVarargs):
+            (JSC::loadVarargs):
+            * runtime/VM.cpp:
+            (JSC::VM::VM):
+            * runtime/VM.h:
+
+2015-02-10  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge r179576, r179648.
+
+    2015-02-04  Mark Lam  <mark.lam@apple.com>
+
+            r179576 introduce a deadlock potential during GC thread suspension.
+            <https://webkit.org/b/141268>
+
+            Reviewed by Michael Saboff.
+
+            http://trac.webkit.org/r179576 introduced a potential for deadlocking.
+            In the GC thread suspension loop, we currently delete
+            MachineThreads::Thread that we detect to be invalid.  This is unsafe
+            because we may have already suspended some threads, and one of those
+            suspended threads may still be holding the C heap lock which we need
+            for deleting the invalid thread.
+
+            The fix is to put the invalid threads in a separate toBeDeleted list,
+            and delete them only after GC has resumed all threads.
+
+            * heap/MachineStackMarker.cpp:
+            (JSC::MachineThreads::removeCurrentThread):
+            - Undo refactoring removeThreadWithLockAlreadyAcquired() out of
+            removeCurrentThread() since it is no longer needed.
+
+            (JSC::MachineThreads::tryCopyOtherThreadStacks):
+            - Put invalid Threads on a threadsToBeDeleted list, and delete those
+            Threads only after all threads have been resumed.
+
+            (JSC::MachineThreads::removeThreadWithLockAlreadyAcquired): Deleted.
+            * heap/MachineStackMarker.h:
+
+    2015-02-03  Mark Lam  <mark.lam@apple.com>
+
+            Workaround a thread library bug where thread destructors may not get called.
+            <https://webkit.org/b/141209>
+
+            Reviewed by Michael Saboff.
+
+            There's a bug where thread destructors may not get called.  As far as
+            we know, this only manifests on darwin ports.  We will work around this
+            by checking at GC time if the platform thread is still valid.  If not,
+            we'll purge it from the VM's registeredThreads list before proceeding
+            with thread scanning activity.
+
+            Note: it is important that we do this invalid thread detection during
+            suspension, because the validity (and liveness) of the other thread is
+            only guaranteed while it is suspended.
+
+            * API/tests/testapi.mm:
+            (threadMain):
+            - Added a test to enter the VM from another thread before we GC on
+              the main thread.
+
+            * heap/MachineStackMarker.cpp:
+            (JSC::MachineThreads::removeThreadWithLockAlreadyAcquired):
+            (JSC::MachineThreads::removeCurrentThread):
+            - refactored removeThreadWithLockAlreadyAcquired() out from
+              removeCurrentThread() so that we can also call it for purging invalid
+              threads.
+            (JSC::suspendThread):
+            - Added a return status to tell if the suspension succeeded or not.
+            (JSC::MachineThreads::tryCopyOtherThreadStacks):
+            - Check if the suspension failed, and purge the thread if we can't
+              suspend it.  Failure to suspend implies that the thread has
+              terminated without calling its destructor.
+            * heap/MachineStackMarker.h:
+
+2015-02-10  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge r179187.
+
+    2015-01-27  Csaba Osztrogonác  <ossy@webkit.org>
+
+            [ARM] Typo fix after r176083
+            https://bugs.webkit.org/show_bug.cgi?id=140937
+
+            Reviewed by Anders Carlsson.
+
+            * assembler/ARMv7Assembler.h:
+            (JSC::ARMv7Assembler::ldrh):
+
+2015-02-10  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge r176083.
+
+    2014-11-13  Benjamin Poulain  <benjamin@webkit.org>
+
+            ARMv7(s) Assembler: LDRH with immediate offset is loading from the wrong offset
+            https://bugs.webkit.org/show_bug.cgi?id=136914
+
+            Reviewed by Michael Saboff.
+
+            TLDR: the immediate offset of half-word load was divided by 2.
+
+            Story time: So I started getting those weird reports of :nth-child() behaving bizarrely
+            on ARMv7 and ARMv7s. To make things worse, the behavior changes depending on style updates.
+
+            I started looking the disassembly on the tests cases...
+
+            The first thing I noticed was that the computation of An+B looked wrong. For example,
+            in the case of n+6, the instruction should have been:
+                subs r1, r1, #6
+            but was
+                subs r1, r1, #2
+
+            After spending a lot of time trying to find the error in the assembler, I discovered
+            the problem was not real, but just a bug in the disassembler.
+            This is the first fix: ARMv7DOpcodeAddSubtractImmediate3's immediate3() was truncating
+            the value to 2 bits instead of 3 bits.
+
+            The disassembler being fixed, I still have no lead on the weird bug. Some disassembly later,
+            I realize the LDRH instruction is not decoded at all. The reason is that both LDRH and STRH
+            were under the umbrella ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord but the pattern
+            only matched SRTH.
+
+            I fix that next, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord is split into
+            ARMv7DOpcodeStoreRegisterImmediateHalfWord and ARMv7DOpcodeLoadRegisterImmediateHalfWord,
+            each with their own pattern and their instruction group.
+
+            Now that I can see the LDRHs correctly, there is something fishy about them, their offset
+            is way too small for the data I load.
+
+            This time, looking at the binary, the generated code is indeed incorrect. It turns out that
+            the ARMv7 assembler shifted the offset of half-word load as if they were byte load: divided by 4.
+            As a result, all the load of half-words with more than zero offset were loading
+            values with a smaller offset than what they should have.
+
+            That being fixed, I dump the assembly: still wrong. I am ready to throw my keyboard through
+            my screen at that point.
+
+            Looking at the disassembler, there is yet again a bug. The computation of the scale() adjustment
+            of the offset was incorrect for anything but word loads.
+            I replaced it by a switch-case to make it explicit.
+
+            STRH is likely incorrect too. I'll fix that in a follow up, I want to survey all the 16 bits cases
+            that are not directly used by the CSS JIT.
+
+            * assembler/ARMv7Assembler.h:
+            (JSC::ARMv7Assembler::ldrh):
+            Fix the immediate scaling. Add an assertion to make sure the alignment of the input is correct.
+
+            * disassembler/ARMv7/ARMv7DOpcode.cpp:
+            (JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale):
+            Fix the scaling code. Just hardcode instruction-to-scale table.
+
+            * disassembler/ARMv7/ARMv7DOpcode.h:
+            (JSC::ARMv7Disassembler::ARMv7DOpcodeAddSubtractImmediate3::immediate3):
+            The mask for a 3 bits immediate is not 3 :)
+
+            (JSC::ARMv7Disassembler::ARMv7DOpcodeLoadStoreRegisterImmediate::scale): Deleted.
+
+2015-02-05  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r178953
+
+    2015-01-21  Joseph Pecoraro  <pecoraro@apple.com>
+
+            Web Inspector: ASSERT expanding objects in console PrimitiveBindingTraits<T>::assertValueHasExpectedType
+            https://bugs.webkit.org/show_bug.cgi?id=140746
+
+            Reviewed by Timothy Hatcher.
+
+            * inspector/InjectedScriptSource.js:
+            Do not add impure properties to the descriptor object that will
+            eventually be sent to the frontend.
+
+2015-02-05  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r178768
+
+    2015-01-20  Joseph Pecoraro  <pecoraro@apple.com>
+
+            Web Inspector: Expanding event objects in console shows undefined for most values, it should have real values
+            https://bugs.webkit.org/show_bug.cgi?id=137306
+
+            Reviewed by Timothy Hatcher.
+
+            Provide another optional parameter to getProperties, to gather a list
+            of all own and getter properties.
+
+            * inspector/InjectedScript.cpp:
+            (Inspector::InjectedScript::getProperties):
+            * inspector/InjectedScript.h:
+            * inspector/InjectedScriptSource.js:
+            * inspector/agents/InspectorRuntimeAgent.cpp:
+            (Inspector::InspectorRuntimeAgent::getProperties):
+            * inspector/agents/InspectorRuntimeAgent.h:
+            * inspector/protocol/Runtime.json:
+
+2015-02-04  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r179329
+
+    2015-01-13  Geoffrey Garen  <ggaren@apple.com>
+
+            Out of bounds access in BytecodeGenerator::emitGetById under DotAccessorNode::emitBytecode
+            https://bugs.webkit.org/show_bug.cgi?id=140397
+
+            Reviewed by Geoffrey Garen.
+
+            Patch by Alexey Proskuryakov.
+
+            Reviewed, performance tested, and ChangeLogged by Geoffrey Garen.
+
+            No performance change.
+
+            No test, since this is a small past-the-end read, which is very
+            difficult to turn into a reproducible failing test -- and existing tests
+            crash reliably using ASan.
+
+            * bytecompiler/NodesCodegen.cpp:
+            (JSC::BracketAccessorNode::emitBytecode):
+            (JSC::DotAccessorNode::emitBytecode):
+            (JSC::FunctionCallBracketNode::emitBytecode):
+            (JSC::PostfixNode::emitResolve):
+            (JSC::DeleteBracketNode::emitBytecode):
+            (JSC::DeleteDotNode::emitBytecode):
+            (JSC::PrefixNode::emitResolve):
+            (JSC::UnaryOpNode::emitBytecode):
+            (JSC::BitwiseNotNode::emitBytecode):
+            (JSC::BinaryOpNode::emitBytecode):
+            (JSC::EqualNode::emitBytecode):
+            (JSC::StrictEqualNode::emitBytecode):
+            (JSC::ThrowableBinaryOpNode::emitBytecode):
+            (JSC::AssignDotNode::emitBytecode):
+            (JSC::AssignBracketNode::emitBytecode): Use RefPtr in more places. Any
+            register used across a call to a function that might allocate a new
+            temporary register must be held in a RefPtr.
+
+2015-02-04  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r178311
+
+    2015-01-12  Geoffrey Garen  <ggaren@apple.com>
+
+            Out of bounds read in IdentifierArena::makeIdentifier
+            https://bugs.webkit.org/show_bug.cgi?id=140376
+
+            Patch by Alexey Proskuryakov.
+
+            Reviewed and ChangeLogged by Geoffrey Garen.
+
+            No test, since this is a small past-the-end read, which is very
+            difficult to turn into a reproducible failing test -- and existing tests
+            crash reliably using ASan.
+
+            * parser/ParserArena.h:
+            (JSC::IdentifierArena::makeIdentifier):
+            (JSC::IdentifierArena::makeIdentifierLCharFromUChar): Check for a
+            zero-length string input, like we do in the literal parser, since it is
+            not valid to dereference characters in a zero-length string.
+
+            A zero-length string is allowed in JavaScript -- for example, "".
+
+2015-01-28  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r178364
+
+    2015-01-12  Michael Saboff  <msaboff@apple.com>
+
+            Local JSArray* "keys" in objectConstructorKeys() is not marked during garbage collection
+            https://bugs.webkit.org/show_bug.cgi?id=140348
+
+            Reviewed by Mark Lam.
+
+            We used to read registers in MachineThreads::gatherFromCurrentThread(), but that is too late
+            because those registers may have been spilled on the stack and replaced with other values by
+            the time we call down to gatherFromCurrentThread().
+
+            Now we get the register contents at the same place that we demarcate the current top of
+            stack using the address of a local variable, in Heap::markRoots().  The register contents
+            buffer is passed along with the demarcation pointer.  These need to be done at this level 
+            in the call tree and no lower, as markRoots() calls various functions that visit object
+            pointers that may be latter proven dead.  Any of those pointers that are left on the
+            stack or in registers could be incorrectly marked as live if we scan the stack contents
+            from a called function or one of its callees.  The stack demarcation pointer and register
+            saving need to be done in the same function so that we have a consistent stack, active
+            and spilled registers.
+
+            Because we don't want to make unnecessary calls to get the register contents, we use
+            a macro to allocated, and possibly align, the register structure and get the actual
+            register contents.
+
+
+            * heap/Heap.cpp:
+            (JSC::Heap::markRoots):
+            (JSC::Heap::gatherStackRoots):
+            * heap/Heap.h:
+            * heap/MachineStackMarker.cpp:
+            (JSC::MachineThreads::gatherFromCurrentThread):
+            (JSC::MachineThreads::gatherConservativeRoots):
+            * heap/MachineStackMarker.h:
+
+2015-01-27  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r177455
+
+    2014-12-17  Chris Dumez  <cdumez@apple.com>
+
+            [iOS] Make it possible to toggle FeatureCounter support at runtime
+            https://bugs.webkit.org/show_bug.cgi?id=139688
+            <rdar://problem/19266254>
+
+            Reviewed by Andreas Kling.
+
+            Stop linking against AppSupport framework as the functionality is no
+            longer in WTF (it was moved to WebCore).
+
+            * Configurations/JavaScriptCore.xcconfig:
+
+2015-01-26  Lucas Forschler  <lforschler@apple.com>
+
+        Merge r177328
+
+    2014-12-15  Chris Dumez  <cdumez@apple.com>
+
+            [iOS] Add feature counting support
+            https://bugs.webkit.org/show_bug.cgi?id=139652
+            <rdar://problem/19255690>
+
+            Reviewed by Gavin Barraclough.
+
+            Link against AppSupport framework on iOS as we need it to implement
+            the new FeatureCounter API in WTF.
+
+            * Configurations/JavaScriptCore.xcconfig:
+
+2015-01-21  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge r176972.
+
+    2014-12-08  Mark Lam  <mark.lam@apple.com>
+
+            CFA wrongly assumes that a speculation for SlowPutArrayStorageShape disallows ArrayStorageShape arrays.
+            <https://webkit.org/b/139327>
+
+            Reviewed by Michael Saboff.
+
+            The code generator and runtime slow paths expects otherwise.  This patch fixes
+            CFA to match the code generator's expectation.
+
+            * dfg/DFGArrayMode.h:
+            (JSC::DFG::ArrayMode::arrayModesThatPassFiltering):
+            (JSC::DFG::ArrayMode::arrayModesWithIndexingShapes):
+
+2015-01-20  Babak Shafiei  <bshafiei@apple.com>
+
+        Merge r171691.
+
+    2014-07-28  Mark Hahnenberg  <mhahnenberg@apple.com>
+
+            REGRESSION: JSObjectSetPrototype() does not work on result of JSGetGlobalObject()
+            https://bugs.webkit.org/show_bug.cgi?id=135322
+
+            Reviewed by Oliver Hunt.
+
+            The prototype chain of the JSProxy object should match that of the JSGlobalObject. 
+
+            This is a separate but related issue with JSObjectSetPrototype which doesn't correctly 
+            account for JSProxies. I also audited the rest of the C API to check that we correctly 
+            handle JSProxies in all other situations where we expect a JSCallbackObject of some sort
+            and found some SPI calls (JSObject*PrivateProperty) that didn't behave correctly when 
+            passed a JSProxy.
+
+            I also added some new tests for these cases.
+
+            * API/JSObjectRef.cpp:
+            (JSObjectSetPrototype):
+            (JSObjectGetPrivateProperty):
+            (JSObjectSetPrivateProperty):
+            (JSObjectDeletePrivateProperty):
+            * API/JSWeakObjectMapRefPrivate.cpp:
+            * API/tests/CustomGlobalObjectClassTest.c:
+            (globalObjectSetPrototypeTest):
+            (globalObjectPrivatePropertyTest):
+            * API/tests/CustomGlobalObjectClassTest.h:
+            * API/tests/testapi.c:
+            (main):
+
+2015-01-11  Mark Lam  <mark.lam@apple.com>
+
+        Update WebKit branch to build with newer LLVM.
+        <https://webkit.org/b/140341>
+
+        Reviewed by Filip Pizlo.
+
+        * Configurations/LLVMForJSC.xcconfig:
+        - Add the ability to pick up LLVM_LIBS_iphoneos from AspenLLVM.xcconfig.
+        * llvm/LLVMAPIFunctions.h:
+        - Removed some erroneous and unused APIs.
+        * llvm/library/LLVMExports.cpp:
+        (initializeAndGetJSCLLVMAPI):
+        - Removed an unneeded option that is also not supported by the new LLVM.
+
 2014-12-10  Babak Shafiei  <bshafiei@apple.com>
 
         Merge r176803.
index 9357b811817bf469558e9e3df6d41beb9e71835d..8a668425fa01da496a98dcd53a1477013f4126c8 100644 (file)
 // Only export our hook for initializing LLVM and returning the API struct.
 OTHER_LDFLAGS_HIDE_SYMBOLS = -Wl,-exported_symbol -Wl,_initializeAndGetJSCLLVMAPI -Wl,-all_load;
 
-LLVM_LIBS_iphoneos = -lLLVMLinker -lLLVMipo -lLLVMVectorize -lLLVMBitWriter -lLLVMTableGen -lLLVMInstrumentation -lLLVMIRReader -lLLVMBitReader -lLLVMAsmParser -lLLVMARM64Disassembler -lLLVMARM64CodeGen -lLLVMARM64AsmParser -lLLVMARM64Desc -lLLVMARM64Info -lLLVMARM64AsmPrinter -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMDebugInfo -lLLVMOption -lLLVMInterpreter -lLLVMJIT -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMMCDisassembler -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport -lprotobuf;
+LLVM_LIBS_ios = -lLLVMLinker -lLLVMipo -lLLVMVectorize -lLLVMBitWriter -lLLVMTableGen -lLLVMInstrumentation -lLLVMIRReader -lLLVMBitReader -lLLVMAsmParser -lLLVMARM64Disassembler -lLLVMARM64CodeGen -lLLVMARM64AsmParser -lLLVMARM64Desc -lLLVMARM64Info -lLLVMARM64AsmPrinter -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMDebugInfo -lLLVMOption -lLLVMInterpreter -lLLVMJIT -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMMCDisassembler -lLLVMMCJIT -lLLVMTarget -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport -lprotobuf
+
+#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/AspenLLVM.xcconfig"
+
+// In general, we prefer to not append libraries this way because it may interfere with the required
+// ordering of library linkage (as determined by their dependencies on other libraries).  In this
+// case, we'll make this a one time exception to work around the fact that there are pre-existing
+// versions of AspenLLVM.xcconfig that overrides LLVM_LIBS_ios but is missing -lLLVMMCDisassembler.
+LLVM_LIBS_iphoneos = $(LLVM_LIBS_ios) -lLLVMMCDisassembler
+
 LLVM_LIBS_macosx = -lLLVMTableGen -lLLVMDebugInfo -lLLVMOption -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMIRReader -lLLVMAsmParser -lLLVMMCDisassembler -lLLVMMCParser -lLLVMInstrumentation -lLLVMBitReader -lLLVMInterpreter -lLLVMipo -lLLVMVectorize -lLLVMLinker -lLLVMBitWriter -lLLVMMCJIT -lLLVMJIT -lLLVMCodeGen -lLLVMObjCARCOpts -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMRuntimeDyld -lLLVMExecutionEngine -lLLVMTarget -lLLVMMC -lLLVMObject -lLLVMCore -lLLVMSupport;
 
 LLVM_LIBRARY_PATHS = $(LLVM_LIBRARY_PATHS_$(PLATFORM_NAME))
index 84fb2bf34a486c8f5892b2c1b3269e0aec953d28..128aac25e7bd9c4492d16bca48c6683705a83af2 100644 (file)
@@ -24,8 +24,8 @@
 MAJOR_VERSION = 600;
 MINOR_VERSION = 1;
 TINY_VERSION = 4;
-MICRO_VERSION = 13;
-NANO_VERSION = 1;
+MICRO_VERSION = 15;
+NANO_VERSION = 12;
 FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(TINY_VERSION).$(MICRO_VERSION).$(NANO_VERSION);
 
 // The bundle version and short version string are set based on the current build configuration, see below.
index 8d02066a516e17c42cc51268b92b05e62bb39d85..308d9df9350a6aad3a35c3eb103fc2a689aa9171 100644 (file)
                FE5932A8183C5A2600A1ECCC /* VMEntryScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FEA08620182B7A0400F6D851 /* Breakpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861E182B7A0400F6D851 /* Breakpoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FEA08621182B7A0400F6D851 /* DebuggerPrimitives.h in Headers */ = {isa = PBXBuildFile; fileRef = FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */ = {isa = PBXBuildFile; fileRef = FEB51F6B1A97B688001F921C /* Regress141809.mm */; };
                FEB58C14187B8B160098EF0B /* ErrorHandlingScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEB58C12187B8B160098EF0B /* ErrorHandlingScope.cpp */; };
                FEB58C15187B8B160098EF0B /* ErrorHandlingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = FEB58C13187B8B160098EF0B /* ErrorHandlingScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FED287B215EC9A5700DA8161 /* LLIntOpcode.h in Headers */ = {isa = PBXBuildFile; fileRef = FED287B115EC9A5700DA8161 /* LLIntOpcode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMEntryScope.h; sourceTree = "<group>"; };
                FEA0861E182B7A0400F6D851 /* Breakpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpoint.h; sourceTree = "<group>"; };
                FEA0861F182B7A0400F6D851 /* DebuggerPrimitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerPrimitives.h; sourceTree = "<group>"; };
+               FEB51F6A1A97B688001F921C /* Regress141809.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Regress141809.h; path = API/tests/Regress141809.h; sourceTree = "<group>"; };
+               FEB51F6B1A97B688001F921C /* Regress141809.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = Regress141809.mm; path = API/tests/Regress141809.mm; sourceTree = "<group>"; };
                FEB58C12187B8B160098EF0B /* ErrorHandlingScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorHandlingScope.cpp; sourceTree = "<group>"; };
                FEB58C13187B8B160098EF0B /* ErrorHandlingScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ErrorHandlingScope.h; sourceTree = "<group>"; };
                FED287B115EC9A5700DA8161 /* LLIntOpcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LLIntOpcode.h; path = llint/LLIntOpcode.h; sourceTree = "<group>"; };
                                C288B2DD18A54D3E007BE40B /* DateTests.mm */,
                                C2181FC018A948FB0025A235 /* JSExportTests.h */,
                                C2181FC118A948FB0025A235 /* JSExportTests.mm */,
+                               FEB51F6A1A97B688001F921C /* Regress141809.h */,
+                               FEB51F6B1A97B688001F921C /* Regress141809.mm */,
                                144005170A531CB50005F061 /* minidom */,
                                14BD5A2D0A3E91F600BAF59C /* testapi.c */,
                                14D857740A4696C80032146C /* testapi.js */,
                        buildActionMask = 2147483647;
                        files = (
                                C29ECB031804D0ED00D2CBB4 /* CurrentThisInsideBlockGetterTest.mm in Sources */,
+                               FEB51F6C1A97B688001F921C /* Regress141809.mm in Sources */,
                                C20328201981979D0088B499 /* CustomGlobalObjectClassTest.c in Sources */,
                                C288B2DE18A54D3E007BE40B /* DateTests.mm in Sources */,
                                C2181FC218A948FB0025A235 /* JSExportTests.mm in Sources */,
index ffc30900ce3704f5ae1e31bc20a7e783a5dd8ba9..ce079d90dfaed8a29e554291368d0ab287b2000a 100644 (file)
@@ -1194,9 +1194,10 @@ public:
     {
         ASSERT(rn != ARMRegisters::pc); // LDR (literal)
         ASSERT(imm.isUInt12());
+        ASSERT(!(imm.getUInt12() & 1));
 
         if (!((rt | rn) & 8) && imm.isUInt6())
-            m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 2, rn, rt);
+            m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDRH_imm_T1, imm.getUInt6() >> 1, rn, rt);
         else
             m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDRH_imm_T2, rn, rt, imm.getUInt12());
     }
index c91e6160d232a13fb81ce7b543ce42d180c9a430..0e81cfa6693c5a895d67a2623a3b0a9d5e0a77c6 100644 (file)
@@ -366,9 +366,9 @@ RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, Regi
     if (m_base->isResolveNode() 
         && generator.willResolveToArguments(static_cast<ResolveNode*>(m_base)->identifier())
         && !generator.symbolTable().slowArguments()) {
-        RegisterID* property = generator.emitNode(m_subscript);
+        RefPtr<RegisterID> property = generator.emitNode(m_subscript);
         generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property);
+        return generator.emitGetArgumentByVal(generator.finalDestination(dst), generator.uncheckedRegisterForArguments(), property.get());
     }
 
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator));
@@ -392,9 +392,9 @@ RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, Register
     }
 
 nonArgumentsPath:
-    RegisterID* base = generator.emitNode(m_base);
+    RefPtr<RegisterID> base = generator.emitNode(m_base);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    return generator.emitGetById(generator.finalDestination(dst), base, m_ident);
+    return generator.emitGetById(generator.finalDestination(dst), base.get(), m_ident);
 }
 
 // ------------------------------ ArgumentListNode -----------------------------
@@ -508,9 +508,9 @@ RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator,
 RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.emitNode(m_base);
-    RegisterID* property = generator.emitNode(m_subscript);
+    RefPtr<RegisterID> property = generator.emitNode(m_subscript);
     generator.emitExpressionInfo(subexpressionDivot(), subexpressionStart(), subexpressionEnd());
-    RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property);
+    RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
     RefPtr<RegisterID> returnValue = generator.finalDestination(dst, function.get());
     CallArguments callArguments(generator, m_args);
     generator.emitMove(callArguments.thisRegister(), base.get());
@@ -736,21 +736,21 @@ RegisterID* PostfixNode::emitResolve(BytecodeGenerator& generator, RegisterID* d
     const Identifier& ident = resolve->identifier();
 
     if (Local local = generator.local(ident)) {
-        RegisterID* localReg = local.get();
+        RefPtr<RegisterID> localReg = local.get();
         if (local.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded();
-            localReg = generator.emitMove(generator.tempDestination(dst), localReg);
+            localReg = generator.emitMove(generator.tempDestination(dst), localReg.get());
         } else if (local.isCaptured()) {
             RefPtr<RegisterID> tempDst = generator.finalDestination(dst);
             ASSERT(dst != localReg);
             RefPtr<RegisterID> tempDstSrc = generator.newTemporary();
-            generator.emitToNumber(tempDst.get(), localReg);
-            generator.emitMove(tempDstSrc.get(), localReg);
+            generator.emitToNumber(tempDst.get(), localReg.get());
+            generator.emitMove(tempDstSrc.get(), localReg.get());
             emitIncOrDec(generator, tempDstSrc.get(), m_operator);
-            generator.emitMove(localReg, tempDstSrc.get());
+            generator.emitMove(localReg.get(), tempDstSrc.get());
             return tempDst.get();
         }
-        return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg, m_operator);
+        return emitPostIncOrDec(generator, generator.finalDestination(dst), localReg.get(), m_operator);
     }
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
@@ -835,20 +835,20 @@ RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, Regist
 RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> r0 = generator.emitNode(m_base);
-    RegisterID* r1 = generator.emitNode(m_subscript);
+    RefPtr<RegisterID> r1 = generator.emitNode(m_subscript);
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1);
+    return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get());
 }
 
 // ------------------------------ DeleteDotNode -----------------------------------
 
 RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    RegisterID* r0 = generator.emitNode(m_base);
+    RefPtr<RegisterID> r0 = generator.emitNode(m_base);
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident);
+    return generator.emitDeleteById(generator.finalDestination(dst), r0.get(), m_ident);
 }
 
 // ------------------------------ DeleteValueNode -----------------------------------
@@ -911,19 +911,19 @@ RegisterID* PrefixNode::emitResolve(BytecodeGenerator& generator, RegisterID* ds
     const Identifier& ident = resolve->identifier();
 
     if (Local local = generator.local(ident)) {
-        RegisterID* localReg = local.get();
+        RefPtr<RegisterID> localReg = local.get();
         if (local.isReadOnly()) {
             generator.emitReadOnlyExceptionIfNeeded();
-            localReg = generator.emitMove(generator.tempDestination(dst), localReg);
+            localReg = generator.emitMove(generator.tempDestination(dst), localReg.get());
         } else if (local.isCaptured()) {
             RefPtr<RegisterID> tempDst = generator.tempDestination(dst);
-            generator.emitMove(tempDst.get(), localReg);
+            generator.emitMove(tempDst.get(), localReg.get());
             emitIncOrDec(generator, tempDst.get(), m_operator);
-            generator.emitMove(localReg, tempDst.get());
+            generator.emitMove(localReg.get(), tempDst.get());
             return generator.moveToDestinationIfNeeded(dst, tempDst.get());
         }
-        emitIncOrDec(generator, localReg, m_operator);
-        return generator.moveToDestinationIfNeeded(dst, localReg);
+        emitIncOrDec(generator, localReg.get(), m_operator);
+        return generator.moveToDestinationIfNeeded(dst, localReg.get());
     }
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
@@ -991,9 +991,9 @@ RegisterID* PrefixNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
 
 RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    RegisterID* src = generator.emitNode(m_expr);
+    RefPtr<RegisterID> src = generator.emitNode(m_expr);
     generator.emitExpressionInfo(position(), position(), position());
-    return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src);
+    return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src.get());
 }
 
 // ------------------------------ BitwiseNotNode -----------------------------------
@@ -1001,8 +1001,8 @@ RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
 RegisterID* BitwiseNotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> src2 = generator.emitLoad(generator.newTemporary(), jsNumber(-1));
-    RegisterID* src1 = generator.emitNode(m_expr);
-    return generator.emitBinaryOp(op_bitxor, generator.finalDestination(dst, src1), src1, src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32()));
+    RefPtr<RegisterID> src1 = generator.emitNode(m_expr);
+    return generator.emitBinaryOp(op_bitxor, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr->resultDescriptor(), ResultType::numberTypeIsInt32()));
 }
  
 // ------------------------------ LogicalNotNode -----------------------------------
@@ -1217,19 +1217,19 @@ RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID*
 
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, right->isPure(generator));
     bool wasTypeof = generator.m_lastOpcodeID == op_typeof;
-    RegisterID* src2 = generator.emitNode(right);
+    RefPtr<RegisterID> src2 = generator.emitNode(right);
     generator.emitExpressionInfo(position(), position(), position());
     if (wasTypeof && (opcodeID == op_neq || opcodeID == op_nstricteq)) {
         RefPtr<RegisterID> tmp = generator.tempDestination(dst);
         if (opcodeID == op_neq)
-            generator.emitEqualityOp(op_eq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2);
+            generator.emitEqualityOp(op_eq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get());
         else if (opcodeID == op_nstricteq)
-            generator.emitEqualityOp(op_stricteq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2);
+            generator.emitEqualityOp(op_stricteq, generator.finalDestination(tmp.get(), src1.get()), src1.get(), src2.get());
         else
             RELEASE_ASSERT_NOT_REACHED();
         return generator.emitUnaryOp(op_not, generator.finalDestination(dst, tmp.get()), tmp.get());
     }
-    RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(left->resultDescriptor(), right->resultDescriptor()));
+    RegisterID* result = generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(left->resultDescriptor(), right->resultDescriptor()));
     if (opcodeID == op_urshift && dst != generator.ignoredResult())
         return generator.emitUnaryOp(op_unsigned, result, result);
     return result;
@@ -1249,8 +1249,8 @@ RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* ds
         std::swap(left, right);
 
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator));
-    RegisterID* src2 = generator.emitNode(right);
-    return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2);
+    RefPtr<RegisterID> src2 = generator.emitNode(right);
+    return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2.get());
 }
 
 RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -1261,16 +1261,16 @@ RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, Register
         std::swap(left, right);
 
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(left, m_rightHasAssignments, m_expr2->isPure(generator));
-    RegisterID* src2 = generator.emitNode(right);
-    return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2);
+    RefPtr<RegisterID> src2 = generator.emitNode(right);
+    return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2.get());
 }
 
 RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator));
-    RegisterID* src2 = generator.emitNode(m_expr2);
+    RefPtr<RegisterID> src2 = generator.emitNode(m_expr2);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
+    return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
 }
 
 RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
@@ -1469,9 +1469,9 @@ RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID
 {
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator));
     RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
-    RegisterID* result = generator.emitNode(value.get(), m_right);
+    RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right);
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result : generator.moveToDestinationIfNeeded(generator.tempDestination(result), result);
+    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
     generator.emitPutById(base.get(), m_ident, forwardResult);
     return generator.moveToDestinationIfNeeded(dst, forwardResult);
 }
@@ -1504,10 +1504,10 @@ RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, Regist
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator));
     RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator));
     RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
-    RegisterID* result = generator.emitNode(value.get(), m_right);
+    RefPtr<RegisterID> result = generator.emitNode(value.get(), m_right);
 
     generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
-    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result : generator.moveToDestinationIfNeeded(generator.tempDestination(result), result);
+    RegisterID* forwardResult = (dst == generator.ignoredResult()) ? result.get() : generator.moveToDestinationIfNeeded(generator.tempDestination(result.get()), result.get());
     generator.emitPutByVal(base.get(), property.get(), forwardResult);
     return generator.moveToDestinationIfNeeded(dst, forwardResult);
 }
index 9c67edbc8b0cadfbaae9bcbe8e2c974e6d82206f..084c985cef83fac6fcc566022fd62c6ee1729465 100644 (file)
@@ -406,7 +406,7 @@ public:
         case Array::ArrayStorage:
             return arrayModesWithIndexingShape(ArrayStorageShape);
         case Array::SlowPutArrayStorage:
-            return arrayModesWithIndexingShape(SlowPutArrayStorageShape);
+            return arrayModesWithIndexingShapes(SlowPutArrayStorageShape, ArrayStorageShape);
         default:
             return asArrayModes(NonArray);
         }
@@ -462,6 +462,13 @@ private:
         }
     }
     
+    ArrayModes arrayModesWithIndexingShapes(IndexingType shape1, IndexingType shape2) const
+    {
+        ArrayModes arrayMode1 = arrayModesWithIndexingShape(shape1);
+        ArrayModes arrayMode2 = arrayModesWithIndexingShape(shape2);
+        return arrayMode1 | arrayMode2;
+    }
+
     bool alreadyChecked(Graph&, Node*, AbstractValue&, IndexingType shape) const;
     
     union {
index c3a308baf02e7a7e5899ded899420d29e7ec7360..aa1a8541f7135519c9f53d5ae998dd06cfda1901 100644 (file)
@@ -481,6 +481,14 @@ public:
         return hasExitSite(node->origin.semantic, exitKind);
     }
     
+    bool usesArguments(InlineCallFrame* inlineCallFrame)
+    {
+        if (!inlineCallFrame)
+            return m_profiledBlock->usesArguments();
+        
+        return baselineCodeBlockForInlineCallFrame(inlineCallFrame)->usesArguments();
+    }
+    
     VirtualRegister argumentsRegisterFor(InlineCallFrame* inlineCallFrame)
     {
         if (!inlineCallFrame)
index c78a307e6dcaecb2db347844c6e7de68a97cf2de..6de782c2a292f6193e0d45ef2e9629fa0a67c5f8 100644 (file)
@@ -348,7 +348,10 @@ Plan::CompilationPath Plan::compileInThreadImpl(LongLivedState& longLivedState)
         }
             
         FTL::State state(dfg);
-        FTL::lowerDFGToLLVM(state);
+        if (!FTL::lowerDFGToLLVM(state)) {
+            FTL::fail(state);
+            return FTLPath;
+        }
         
         if (reportCompileTimes())
             beforeFTL = currentTimeMS();
index 0f869c077de6a136f4d8c7259604080283e58b1a..0722bfa23477911c8024952ed17b1ea65867470b 100644 (file)
@@ -105,7 +105,7 @@ public:
             usedLocals.set(codeBlock()->activationRegister().toLocal());
         for (InlineCallFrameSet::iterator iter = m_graph.m_plan.inlineCallFrames->begin(); !!iter; ++iter) {
             InlineCallFrame* inlineCallFrame = *iter;
-            if (!inlineCallFrame->executable->usesArguments())
+            if (!m_graph.usesArguments(inlineCallFrame))
                 continue;
             
             VirtualRegister argumentsRegister = m_graph.argumentsRegisterFor(inlineCallFrame);
@@ -171,7 +171,7 @@ public:
             InlineVariableData data = m_graph.m_inlineVariableData[i];
             InlineCallFrame* inlineCallFrame = data.inlineCallFrame;
             
-            if (inlineCallFrame->executable->usesArguments()) {
+            if (m_graph.usesArguments(inlineCallFrame)) {
                 inlineCallFrame->argumentsRegister = virtualRegisterForLocal(
                     allocation[m_graph.argumentsRegisterFor(inlineCallFrame).toLocal()]);
 
index 43ed442348ddd5ddfef3b0f63a871d2463202b95..c11acf8cb2dca3663ee334cf0388860f58954301 100644 (file)
@@ -91,8 +91,8 @@ static Opcode16GroupInitializer opcode16BitGroupList[] = {
     OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
     OPCODE_GROUP_ENTRY(0xe, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
     OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
-    OPCODE_GROUP_ENTRY(0x10, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord),
-    OPCODE_GROUP_ENTRY(0x11, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord),
+    OPCODE_GROUP_ENTRY(0x10, ARMv7DOpcodeStoreRegisterImmediateHalfWord),
+    OPCODE_GROUP_ENTRY(0x11, ARMv7DOpcodeLoadRegisterImmediateHalfWord),
     OPCODE_GROUP_ENTRY(0x12, ARMv7DOpcodeLoadStoreRegisterSPRelative),
     OPCODE_GROUP_ENTRY(0x13, ARMv7DOpcodeLoadStoreRegisterSPRelative),
     OPCODE_GROUP_ENTRY(0x14, ARMv7DOpcodeGeneratePCRelativeAddress),
@@ -514,6 +514,25 @@ const char* ARMv7DOpcodeLoadStoreRegisterImmediate::format()
     return m_formatBuffer;
 }
 
+unsigned ARMv7DOpcodeLoadStoreRegisterImmediate::scale()
+{
+    switch (op()) {
+    case 0:
+    case 1:
+        return 2;
+    case 2:
+    case 3:
+        return 0;
+    case 4:
+    case 5:
+        return 1;
+    default:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
 const char* const ARMv7DOpcodeLoadStoreRegisterOffsetT1::s_opNames[8] = {
     "str", "strh", "strb", "ldrsb", "ldr", "ldrh", "ldrb", "ldrsh"
 };
index b415298a91d598073b92326382eaaaf53d4c1552..4273c31dcc8b77cc40f2efac4cb355790b18e7ae 100644 (file)
@@ -275,7 +275,7 @@ protected:
     const char* opName() { return s_opNames[op()]; }
 
     unsigned op() { return (m_opcode >> 9) & 0x1; }
-    unsigned immediate3() { return (m_opcode >> 6) & 0x3; }
+    unsigned immediate3() { return (m_opcode >> 6) & 0x7; }
     unsigned rn() { return (m_opcode >> 3) & 0x7; }
 };
 
@@ -441,7 +441,7 @@ protected:
     unsigned immediate5() { return (m_opcode >> 6) & 0x01f; }
     unsigned rn() { return (m_opcode >> 3) & 0x7; }
     unsigned rt() { return m_opcode & 0x7; }
-    unsigned scale() { return 2 - (op() >> 1); }
+    unsigned scale();
 };
 
 class ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte : public ARMv7DOpcodeLoadStoreRegisterImmediate {
@@ -452,7 +452,7 @@ public:
     DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
 };
 
-class ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
+class ARMv7DOpcodeStoreRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
 public:
     static const uint16_t s_mask = 0xf800;
     static const uint16_t s_pattern = 0x8000;
@@ -460,6 +460,14 @@ public:
     DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
 };
 
+class ARMv7DOpcodeLoadRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
+public:
+    static const uint16_t s_mask = 0xf800;
+    static const uint16_t s_pattern = 0x8800;
+
+    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
+};
+
 class ARMv7DOpcodeLoadStoreRegisterOffsetT1 : public ARMv7D16BitOpcode {
 private:
     static const char* const s_opNames[8];
index 3f6050ab161e9200439dd481470cfb4701a4f64e..ecb1513f808dbc3167f2fdffaf72d09d5bbe64fc 100644 (file)
@@ -68,6 +68,7 @@ public:
     LowerDFGToLLVM(State& state)
         : m_graph(state.graph)
         , m_ftlState(state)
+        , m_loweringSucceeded(true)
         , m_heaps(state.context)
         , m_out(state.context)
         , m_availability(OperandsLike, state.graph.block(0)->variablesAtHead)
@@ -76,8 +77,12 @@ public:
         , m_stackmapIDs(0)
     {
     }
-    
-    void lower()
+
+
+#define LOWERING_FAILED(node, reason)                                  \
+    loweringFailed((node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, (reason));
+
+    bool lower()
     {
         CString name;
         if (verboseCompilationEnabled()) {
@@ -157,10 +162,16 @@ public:
             m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
         m_out.unreachable();
         
+        if (!m_loweringSucceeded)
+            return m_loweringSucceeded;
+
         Vector<BasicBlock*> depthFirst;
         m_graph.getBlocksInDepthFirstOrder(depthFirst);
-        for (unsigned i = 0; i < depthFirst.size(); ++i)
+        for (unsigned i = 0; i < depthFirst.size(); ++i) {
             compileBlock(depthFirst[i]);
+            if (!m_loweringSucceeded)
+                return m_loweringSucceeded;
+        }
         
         if (Options::dumpLLVMIR())
             dumpModule(m_ftlState.module);
@@ -169,6 +180,8 @@ public:
             m_ftlState.dumpState("after lowering");
         if (validationEnabled())
             verifyModule(m_ftlState.module);
+
+        return m_loweringSucceeded;
     }
 
 private:
@@ -201,8 +214,8 @@ private:
                     type = m_out.int64;
                     break;
                 default:
-                    RELEASE_ASSERT_NOT_REACHED();
-                    break;
+                    LOWERING_FAILED(node, "Bad Phi node result type");
+                    return;
                 }
                 m_phis.add(node, buildAlloca(m_out.m_builder, type));
             }
@@ -631,15 +644,13 @@ private:
         case AllocationProfileWatchpoint:
             break;
         default:
-            dataLog("Unrecognized node in FTL backend:\n");
-            m_graph.dump(WTF::dataFile(), "    ", m_node);
-            dataLog("\n");
-            dataLog("Full graph dump:\n");
-            m_graph.dump();
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Unrecognized node in FTL backend");
             break;
         }
         
+        if (!m_loweringSucceeded)
+            return false;
+
         if (shouldExecuteEffects)
             m_interpreter.executeEffects(nodeIndex);
         
@@ -670,7 +681,7 @@ private:
             m_out.set(lowJSValue(m_node->child1()), destination);
             break;
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -696,7 +707,7 @@ private:
             setJSValue(m_out.get(source));
             break;
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -739,7 +750,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
         }
     }
     
@@ -764,7 +775,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
         }
     }
     
@@ -788,7 +799,7 @@ private:
             return;
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
         }
     }
     
@@ -827,7 +838,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -860,7 +871,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad flush format");
             return;
         }
     }
@@ -890,7 +901,7 @@ private:
             setJSValue(jsValue);
             break;
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -961,8 +972,8 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
+            LOWERING_FAILED(m_node, "Bad flush format for argument");
+            return;
         }
         
         m_availability.operand(variable->local()) = Availability(variable->flushedAt());
@@ -1137,7 +1148,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -1211,7 +1222,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -1314,7 +1325,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -1412,7 +1423,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -1463,7 +1474,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -1489,7 +1500,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -1556,7 +1567,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             break;
         }
     }
@@ -1722,8 +1733,8 @@ private:
             vmCall(m_out.operation(operationEnsureArrayStorage), m_callFrame, cell);
             break;
         default:
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
+            LOWERING_FAILED(m_node, "Bad array type");
+            return;
         }
         
         structureID = m_out.load32(cell, m_heaps.JSCell_structureID);
@@ -1796,7 +1807,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             return;
         }
     }
@@ -1948,13 +1959,19 @@ private:
             // FIXME: FTL should support activations.
             // https://bugs.webkit.org/show_bug.cgi?id=129576
             
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Unimplemented");
+            return;
         }
         
         TypedPointer base;
-        if (codeOrigin.inlineCallFrame)
-            base = addressFor(codeOrigin.inlineCallFrame->arguments[1].virtualRegister());
-        else
+        if (codeOrigin.inlineCallFrame) {
+            VirtualRegister reg;
+            if (codeOrigin.inlineCallFrame->arguments.size() <= 1)
+                reg = virtualRegisterForLocal(0); // Doesn't matter what we do since we would have exited anyway.
+            else
+                reg = codeOrigin.inlineCallFrame->arguments[1].virtualRegister();
+            base = addressFor(reg);
+        } else
             base = addressFor(virtualRegisterForArgument(1));
         
         LValue pointer = m_out.baseIndex(
@@ -1985,7 +2002,7 @@ private:
                 return;
             }
             
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad array type");
             return;
         }
     }
@@ -2135,7 +2152,8 @@ private:
                         result = m_out.load32(pointer);
                         break;
                     default:
-                        RELEASE_ASSERT_NOT_REACHED();
+                        LOWERING_FAILED(m_node, "Bad element size");
+                        return;
                     }
                     
                     if (elementSize(type) < 4) {
@@ -2179,14 +2197,15 @@ private:
                     result = m_out.loadDouble(pointer);
                     break;
                 default:
-                    RELEASE_ASSERT_NOT_REACHED();
+                    LOWERING_FAILED(m_node, "Bad typed array type");
+                    return;
                 }
                 
                 setDouble(result);
                 return;
             }
             
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad array type");
             return;
         } }
     }
@@ -2292,7 +2311,8 @@ private:
             }
                 
             default:
-                RELEASE_ASSERT_NOT_REACHED();
+                LOWERING_FAILED(m_node, "Bad array type");
+                return;
             }
 
             m_out.jump(continuation);
@@ -2385,7 +2405,8 @@ private:
                     }
                         
                     default:
-                        RELEASE_ASSERT_NOT_REACHED();
+                        LOWERING_FAILED(m_node, "Bad use kind");
+                        return;
                     }
                     
                     switch (elementSize(type)) {
@@ -2402,7 +2423,8 @@ private:
                         refType = m_out.ref32;
                         break;
                     default:
-                        RELEASE_ASSERT_NOT_REACHED();
+                        LOWERING_FAILED(m_node, "Bad element size");
+                        return;
                     }
                 } else /* !isInt(type) */ {
                     LValue value = lowDouble(child3);
@@ -2416,7 +2438,8 @@ private:
                         refType = m_out.refDouble;
                         break;
                     default:
-                        RELEASE_ASSERT_NOT_REACHED();
+                        LOWERING_FAILED(m_node, "Bad typed array type");
+                        return;
                     }
                 }
                 
@@ -2440,8 +2463,8 @@ private:
                 return;
             }
             
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
+            LOWERING_FAILED(m_node, "Bad array type");
+            return;
         }
     }
     
@@ -2512,7 +2535,7 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad array type");
             return;
         }
     }
@@ -2570,7 +2593,7 @@ private:
         }
 
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad array type");
             return;
         }
     }
@@ -2929,8 +2952,8 @@ private:
         }
             
         default:
-            RELEASE_ASSERT_NOT_REACHED();
-            break;
+            LOWERING_FAILED(m_node, "Bad use kind");
+            return;
         }
     }
     
@@ -3021,7 +3044,8 @@ private:
                 m_out.operation(operationMakeRope3), m_callFrame, kids[0], kids[1], kids[2]));
             break;
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad number of children");
+            return;
             break;
         }
         m_out.jump(continuation);
@@ -3426,8 +3450,8 @@ private:
             nonSpeculativeCompare(LLVMIntEQ, operationCompareEq);
             return;
         }
-        
-        RELEASE_ASSERT_NOT_REACHED();
+
+        LOWERING_FAILED(m_node, "Bad use kinds");
     }
     
     void compileCompareEqConstant()
@@ -3520,7 +3544,7 @@ private:
             return;
         }
         
-        RELEASE_ASSERT_NOT_REACHED();
+        LOWERING_FAILED(m_node, "Bad use kinds");
     }
     
     void compileCompareStrictEqConstant()
@@ -3656,8 +3680,8 @@ private:
             }
                 
             default:
-                RELEASE_ASSERT_NOT_REACHED();
-                break;
+                LOWERING_FAILED(m_node, "Bad use kind");
+                return;
             }
             
             m_out.appendTo(switchOnInts, lastNext);
@@ -3702,8 +3726,8 @@ private:
             }
                 
             default:
-                RELEASE_ASSERT_NOT_REACHED();
-                break;
+                LOWERING_FAILED(m_node, "Bad use kind");
+                return;
             }
             
             LBasicBlock lengthIs1 = FTL_NEW_BLOCK(m_out, ("Switch/SwitchChar length is 1"));
@@ -3755,11 +3779,11 @@ private:
         }
         
         case SwitchString:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Unimplemented");
             break;
         }
         
-        RELEASE_ASSERT_NOT_REACHED();
+        LOWERING_FAILED(m_node, "Bad switch kind");
     }
     
     void compileReturn()
@@ -4216,7 +4240,7 @@ private:
             return;
         }
         
-        RELEASE_ASSERT_NOT_REACHED();
+        LOWERING_FAILED(m_node, "Bad use kinds");
     }
     
     void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild)
@@ -4495,7 +4519,7 @@ private:
             return m_out.phi(m_out.boolean, fastResult, slowResult);
         }
         default:
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Bad use kind");
             return 0;
         }
     }
@@ -4868,7 +4892,7 @@ private:
         case StrictInt52:
             return Int52;
         }
-        RELEASE_ASSERT_NOT_REACHED();
+        LOWERING_FAILED(m_node, "Bad use kind");
         return Int52;
     }
     
@@ -5013,7 +5037,7 @@ private:
             return result;
         }
         
-        RELEASE_ASSERT_NOT_REACHED();
+        LOWERING_FAILED(m_node, "Corrupt array class");
         return 0;
     }
     
@@ -5325,8 +5349,8 @@ private:
             speculateMisc(edge);
             break;
         default:
-            dataLog("Unsupported speculation use kind: ", edge.useKind(), "\n");
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Unsupported speculation use kind");
+            return;
         }
     }
     
@@ -5387,7 +5411,7 @@ private:
             
             switch (arrayMode.arrayClass()) {
             case Array::OriginalArray:
-                RELEASE_ASSERT_NOT_REACHED();
+                LOWERING_FAILED(m_node, "Unexpected original array");
                 return 0;
                 
             case Array::Array:
@@ -5407,7 +5431,8 @@ private:
                     m_out.constInt8(arrayMode.shapeMask()));
             }
             
-            RELEASE_ASSERT_NOT_REACHED();
+            LOWERING_FAILED(m_node, "Corrupt array class");
+            return 0;
         }
             
         default:
@@ -6043,7 +6068,7 @@ private:
             return;
         }
         
-        RELEASE_ASSERT_NOT_REACHED();
+        LOWERING_FAILED(m_node, "Corrupt int52 kind");
     }
     void setJSValue(Node* node, LValue value)
     {
@@ -6170,11 +6195,24 @@ private:
         return addressFor(operand, TagOffset);
     }
     
+    NO_RETURN_DUE_TO_ASSERT void loweringFailed(Node* node, const char* file, int line, const char* function, const char* assertion)
+    {
+        if (!ASSERT_DISABLED) {
+            dataLog("FTL ASSERTION FAILED: ", assertion, "\n");
+            dataLog(file, "(", line, ") : ", function, "\n");
+            dataLog("While handling node ", node, "\n");
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+
+        m_loweringSucceeded = false;
+    }
+
     VM& vm() { return m_graph.m_vm; }
     CodeBlock* codeBlock() { return m_graph.m_codeBlock; }
     
     Graph& m_graph;
     State& m_ftlState;
+    bool m_loweringSucceeded;
     AbstractHeapRepository m_heaps;
     Output m_out;
     
@@ -6215,10 +6253,10 @@ private:
     uint32_t m_stackmapIDs;
 };
 
-void lowerDFGToLLVM(State& state)
+bool lowerDFGToLLVM(State& state)
 {
     LowerDFGToLLVM lowering(state);
-    lowering.lower();
+    return lowering.lower();
 }
 
 } } // namespace JSC::FTL
index 0e38d7ba98d6243e3e3a7de3c8cdb4f39ba576bb..141b625c8d4c98c1e716f0052269845628d0f4a7 100644 (file)
@@ -33,7 +33,7 @@
 
 namespace JSC { namespace FTL {
 
-void lowerDFGToLLVM(State&);
+bool lowerDFGToLLVM(State&);
 
 } } // namespace JSC::FTL
 
index 08a09d15a9128301c122be3c3db61121c3b38ded..447383b667882fc29e7e805d039dd3d53ee2d6ec 100644 (file)
@@ -497,8 +497,9 @@ void Heap::markRoots(double gcStartTime)
     // We gather conservative roots before clearing mark bits because conservative
     // gathering uses the mark bits to determine whether a reference is valid.
     void* dummy;
+    ALLOCATE_AND_GET_REGISTER_STATE(registers);
     ConservativeRoots conservativeRoots(&m_objectSpace.blocks(), &m_storageSpace);
-    gatherStackRoots(conservativeRoots, &dummy);
+    gatherStackRoots(conservativeRoots, &dummy, registers);
     gatherJSStackRoots(conservativeRoots);
     gatherScratchBufferRoots(conservativeRoots);
 
@@ -558,11 +559,11 @@ void Heap::copyBackingStores()
         m_storageSpace.doneCopying();
 }
 
-void Heap::gatherStackRoots(ConservativeRoots& roots, void** dummy)
+void Heap::gatherStackRoots(ConservativeRoots& roots, void** dummy, MachineThreads::RegisterState& registers)
 {
     GCPHASE(GatherStackRoots);
     m_jitStubRoutines.clearMarks();
-    m_machineThreads.gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks, dummy);
+    m_machineThreads.gatherConservativeRoots(roots, m_jitStubRoutines, m_codeBlocks, dummy, registers);
 }
 
 void Heap::gatherJSStackRoots(ConservativeRoots& roots)
index 1858f1b663818c5ac431a9a96f24ad894607bc83..2f2e3e9fc245e1ff18ac4f54c96fd28f6582bb60 100644 (file)
@@ -271,7 +271,7 @@ private:
     void stopAllocation();
 
     void markRoots(double gcStartTime);
-    void gatherStackRoots(ConservativeRoots&, void** dummy);
+    void gatherStackRoots(ConservativeRoots&, void** dummy, MachineThreads::RegisterState& registers);
     void gatherJSStackRoots(ConservativeRoots&);
     void gatherScratchBufferRoots(ConservativeRoots&);
     void clearLivenessData();
index 0654ffe2c872d3b835edddbaa49aa79e89587999..c354e7754be1d477d141bfa3b878cc549074f401 100644 (file)
@@ -227,25 +227,8 @@ void MachineThreads::removeCurrentThread()
     }
 }
 
-#if COMPILER(GCC)
-#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
-#else
-#define REGISTER_BUFFER_ALIGNMENT
-#endif
-
-void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent)
+void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent, RegisterState& registers)
 {
-    // setjmp forces volatile registers onto the stack
-    jmp_buf registers REGISTER_BUFFER_ALIGNMENT;
-#if COMPILER(MSVC)
-#pragma warning(push)
-#pragma warning(disable: 4611)
-#endif
-    setjmp(registers);
-#if COMPILER(MSVC)
-#pragma warning(pop)
-#endif
-
     void* registersBegin = &registers;
     void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(&registers + 1)));
     swapIfBackwards(registersBegin, registersEnd);
@@ -257,14 +240,18 @@ void MachineThreads::gatherFromCurrentThread(ConservativeRoots& conservativeRoot
     conservativeRoots.add(stackBegin, stackEnd, jitStubRoutines, codeBlocks);
 }
 
-static inline void suspendThread(const PlatformThread& platformThread)
+static inline bool suspendThread(const PlatformThread& platformThread)
 {
 #if OS(DARWIN)
-    thread_suspend(platformThread);
+    kern_return_t result = thread_suspend(platformThread);
+    return result == KERN_SUCCESS;
 #elif OS(WINDOWS)
-    SuspendThread(platformThread);
+    bool threadIsSuspended = (SuspendThread(platformThread) != (DWORD)-1);
+    ASSERT(threadIsSuspended);
+    return threadIsSuspended;
 #elif USE(PTHREADS)
     pthread_kill(platformThread, SigThreadSuspendResume);
+    return true;
 #else
 #error Need a way to suspend threads on this platform
 #endif
@@ -460,24 +447,67 @@ void MachineThreads::gatherFromOtherThread(ConservativeRoots& conservativeRoots,
     freePlatformThreadRegisters(regs);
 }
 
-void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent)
+void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoots, JITStubRoutineSet& jitStubRoutines, CodeBlockSet& codeBlocks, void* stackCurrent, RegisterState& registers)
 {
-    gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, stackCurrent);
+    gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, stackCurrent, registers);
 
     if (m_threadSpecific) {
         PlatformThread currentPlatformThread = getCurrentPlatformThread();
 
         MutexLocker lock(m_registeredThreadsMutex);
 
+        Thread* threadsToBeDeleted = nullptr;
+
 #ifndef NDEBUG
         // Forbid malloc during the gather phase. The gather phase suspends
         // threads, so a malloc during gather would risk a deadlock with a
         // thread that had been suspended while holding the malloc lock.
         fastMallocForbid();
 #endif
-        for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
-            if (!equalThread(thread->platformThread, currentPlatformThread))
-                suspendThread(thread->platformThread);
+        int numberOfThreads = 0; // Using 0 to denote that we haven't counted the number of threads yet.
+        int index = 1;
+        Thread* previousThread = nullptr;
+        for (Thread* thread = m_registeredThreads; thread; index++) {
+            if (!equalThread(thread->platformThread, currentPlatformThread)) {
+                bool success = suspendThread(thread->platformThread);
+#if OS(DARWIN)
+                if (!success) {
+                    if (!numberOfThreads) {
+                        for (Thread* countedThread = m_registeredThreads; countedThread; countedThread = countedThread->next)
+                            numberOfThreads++;
+                    }
+                    
+                    // Re-do the suspension to get the actual failure result for logging.
+                    kern_return_t error = thread_suspend(thread->platformThread);
+                    ASSERT(error != KERN_SUCCESS);
+                    
+                    WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
+                        "JavaScript garbage collection encountered an invalid thread (err 0x%x): Thread [%d/%d: %p] platformThread %p.",
+                        error, index, numberOfThreads, thread, reinterpret_cast<void*>(thread->platformThread));
+                    
+                    // Put the invalid thread on the threadsToBeDeleted list.
+                    // We can't just delete it here because we have suspended other
+                    // threads, and they may still be holding the C heap lock which
+                    // we need for deleting the invalid thread. Hence, we need to
+                    // defer the deletion till after we have resumed all threads.
+                    Thread* nextThread = thread->next;
+                    thread->next = threadsToBeDeleted;
+                    threadsToBeDeleted = thread;
+                    
+                    if (previousThread)
+                        previousThread->next = nextThread;
+                    else
+                        m_registeredThreads = nextThread;
+                    thread = nextThread;
+                    continue;
+                }
+#else
+                UNUSED_PARAM(numberOfThreads);
+                ASSERT_UNUSED(success, success);
+#endif
+            }
+            previousThread = thread;
+            thread = thread->next;
         }
 
         // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held,
@@ -495,6 +525,11 @@ void MachineThreads::gatherConservativeRoots(ConservativeRoots& conservativeRoot
 #ifndef NDEBUG
         fastMallocAllow();
 #endif
+        for (Thread* thread = threadsToBeDeleted; thread; ) {
+            Thread* nextThread = thread->next;
+            delete thread;
+            thread = nextThread;
+        }
     }
 }
 
index 33b72c8614f06afeb41dc0490252a61067b53968..22b1d222ead4863223e7ac3fc11de1f60a065cc7 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef MachineThreads_h
 #define MachineThreads_h
 
+#include <setjmp.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/ThreadSpecific.h>
 #include <wtf/ThreadingPrimitives.h>
@@ -36,16 +37,18 @@ namespace JSC {
     class MachineThreads {
         WTF_MAKE_NONCOPYABLE(MachineThreads);
     public:
+        typedef jmp_buf RegisterState;
+
         MachineThreads(Heap*);
         ~MachineThreads();
 
-        void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackCurrent);
+        void gatherConservativeRoots(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackCurrent, RegisterState& registers);
 
         JS_EXPORT_PRIVATE void makeUsableFromMultipleThreads();
         JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
 
     private:
-        void gatherFromCurrentThread(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackCurrent);
+        void gatherFromCurrentThread(ConservativeRoots&, JITStubRoutineSet&, CodeBlockSet&, void* stackCurrent, RegisterState& registers);
 
         class Thread;
 
@@ -64,4 +67,24 @@ namespace JSC {
 
 } // namespace JSC
 
+#if COMPILER(GCC)
+#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
+#else
+#define REGISTER_BUFFER_ALIGNMENT
+#endif
+
+// ALLOCATE_AND_GET_REGISTER_STATE() is a macro so that it is always "inlined" even in debug builds.
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4611)
+#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
+    MachineThreads::RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
+    setjmp(registers)
+#pragma warning(pop)
+#else
+#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
+    MachineThreads::RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
+    setjmp(registers)
+#endif
+
 #endif // MachineThreads_h
index 785dad0ac88e4e70d985f6098805edc45baf68f1..1a2b9309897d475a9737b72362b69c9ef432e58f 100644 (file)
@@ -109,11 +109,12 @@ void InjectedScript::getFunctionDetails(ErrorString* errorString, const String&
     *result = Inspector::TypeBuilder::Debugger::FunctionDetails::runtimeCast(resultValue);
 }
 
-void InjectedScript::getProperties(ErrorString* errorString, const String& objectId, bool ownProperties, RefPtr<Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>* properties)
+void InjectedScript::getProperties(ErrorString* errorString, const String& objectId, bool ownProperties, bool ownAndGetterProperties, RefPtr<Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>* properties)
 {
     Deprecated::ScriptFunctionCall function(injectedScriptObject(), ASCIILiteral("getProperties"), inspectorEnvironment()->functionCallHandler());
     function.appendArgument(objectId);
     function.appendArgument(ownProperties);
+    function.appendArgument(ownAndGetterProperties);
 
     RefPtr<InspectorValue> result;
     makeCall(function, &result);
index 4c58b19e51f7f7109bdf2ad7400b0f9f7b27ab6e..fce17fc6306c950e3e0e79375eaf652f570a98bb 100644 (file)
@@ -60,7 +60,7 @@ public:
     void callFunctionOn(ErrorString*, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown);
     void evaluateOnCallFrame(ErrorString*, const Deprecated::ScriptValue& callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>* result, TypeBuilder::OptOutput<bool>* wasThrown);
     void getFunctionDetails(ErrorString*, const String& functionId, RefPtr<TypeBuilder::Debugger::FunctionDetails>* result);
-    void getProperties(ErrorString*, const String& objectId, bool ownProperties, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::PropertyDescriptor>>* result);
+    void getProperties(ErrorString*, const String& objectId, bool ownProperties, bool ownAndGetterProperties, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::PropertyDescriptor>>* result);
     void getInternalProperties(ErrorString*, const String& objectId, RefPtr<TypeBuilder::Array<TypeBuilder::Runtime::InternalPropertyDescriptor>>* result);
 
     PassRefPtr<TypeBuilder::Array<TypeBuilder::Debugger::CallFrame>> wrapCallFrames(const Deprecated::ScriptValue&);
index db331cf91f5074e612e5bb3bc6e20c036a56801a..a7a1e5cb1045b132a0655d2013717a89ebc21686 100644 (file)
@@ -216,12 +216,7 @@ InjectedScript.prototype = {
         return result;
     },
 
-    /**
-     * @param {string} objectId
-     * @param {boolean} ownProperties
-     * @return {Array.<RuntimeAgent.PropertyDescriptor>|boolean}
-     */
-    getProperties: function(objectId, ownProperties)
+    getProperties: function(objectId, ownProperties, ownAndGetterProperties)
     {
         var parsedObjectId = this._parseObjectId(objectId);
         var object = this._objectForId(parsedObjectId);
@@ -229,7 +224,8 @@ InjectedScript.prototype = {
 
         if (!this._isDefined(object))
             return false;
-        var descriptors = this._propertyDescriptors(object, ownProperties);
+
+        var descriptors = this._propertyDescriptors(object, ownProperties, ownAndGetterProperties);
 
         // Go over properties, wrap object values.
         for (var i = 0; i < descriptors.length; ++i) {
@@ -245,6 +241,7 @@ InjectedScript.prototype = {
             if (!("enumerable" in descriptor))
                 descriptor.enumerable = false;
         }
+
         return descriptors;
     },
 
@@ -317,70 +314,6 @@ InjectedScript.prototype = {
         delete this._idToObjectGroupName[id];
     },
 
-    /**
-     * @param {Object} object
-     * @param {boolean} ownProperties
-     * @return {Array.<Object>}
-     */
-    _propertyDescriptors: function(object, ownProperties)
-    {
-        var descriptors = [];
-        var nameProcessed = {};
-        nameProcessed["__proto__"] = null;
-        for (var o = object; this._isDefined(o); o = o.__proto__) {
-            var names = Object.getOwnPropertyNames(/** @type {!Object} */ (o));
-            for (var i = 0; i < names.length; ++i) {
-                var name = names[i];
-                if (nameProcessed[name])
-                    continue;
-
-                try {
-                    nameProcessed[name] = true;
-                    var descriptor = Object.getOwnPropertyDescriptor(/** @type {!Object} */ (object), name);
-                    if (!descriptor) {
-                        // Not all bindings provide proper descriptors. Fall back to the writable, configurable property.
-                        try {
-                            descriptor = { name: name, value: object[name], writable: false, configurable: false, enumerable: false};
-                            if (o === object)
-                                descriptor.isOwn = true;
-                            descriptors.push(descriptor);
-                        } catch (e) {
-                            // Silent catch.
-                        }
-                        continue;
-                    }
-                    if (descriptor.hasOwnProperty("get") && descriptor.hasOwnProperty("set") && !descriptor.get && !descriptor.set) {
-                        // Not all bindings provide proper descriptors. Fall back to the writable, configurable property.
-                        try {
-                            descriptor = { name: name, value: object[name], writable: false, configurable: false, enumerable: false};
-                            if (o === object)
-                                descriptor.isOwn = true;
-                            descriptors.push(descriptor);
-                        } catch (e) {
-                            // Silent catch.
-                        }
-                        continue;
-                    }
-                } catch (e) {
-                    var descriptor = {};
-                    descriptor.value = e;
-                    descriptor.wasThrown = true;
-                }
-
-                descriptor.name = name;
-                if (o === object)
-                    descriptor.isOwn = true;
-                descriptors.push(descriptor);
-            }
-            if (ownProperties) {
-                if (object.__proto__)
-                    descriptors.push({ name: "__proto__", value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true});
-                break;
-            }
-        }
-        return descriptors;
-    },
-
     /**
      * @param {string} expression
      * @param {string} objectGroup
@@ -679,6 +612,108 @@ InjectedScript.prototype = {
         return module;
     },
 
+    _propertyDescriptors: function(object, ownProperties, ownAndGetterProperties)
+    {
+        // Modes:
+        //  - ownProperties - only own properties and __proto__
+        //  - ownAndGetterProperties - own properties, __proto__, and getters in the prototype chain
+        //  - neither - get all properties in the prototype chain, exclude __proto__
+
+        var descriptors = [];
+        var nameProcessed = {};
+        nameProcessed["__proto__"] = null;
+
+        function createFakeValueDescriptor(name, descriptor, isOwnProperty)
+        {
+            try {
+                return {name: name, value: object[name], writable: descriptor.writable || false, configurable: descriptor.configurable || false, enumerable: descriptor.enumerable || false};
+            } catch (e) {
+                var errorDescriptor = {name: name, value: e, wasThrown: true};
+                if (isOwnProperty)
+                    errorDescriptor.isOwn = true;
+                return errorDescriptor;
+            }
+        }
+
+        function processDescriptor(descriptor, isOwnProperty, possibleNativeBindingGetter)
+        {
+            // Own properties only.
+            if (ownProperties) {
+                if (isOwnProperty)
+                    descriptors.push(descriptor);
+                return;
+            }
+
+            // Own and getter properties.
+            if (ownAndGetterProperties) {
+                if (isOwnProperty) {
+                    // Own property, include the descriptor as is.
+                    descriptors.push(descriptor);
+                } else if (descriptor.hasOwnProperty("get") && descriptor.get) {
+                    // Getter property in the prototype chain. Create a fake value descriptor.
+                    descriptors.push(createFakeValueDescriptor(descriptor.name, descriptor, isOwnProperty));
+                } else if (possibleNativeBindingGetter) {
+                    // Possible getter property in the prototype chain.
+                    descriptors.push(descriptor);
+                }
+                return;
+            }
+
+            // All properties.
+            descriptors.push(descriptor);
+        }
+
+        function processPropertyNames(o, names, isOwnProperty)
+        {
+            for (var i = 0; i < names.length; ++i) {
+                var name = names[i];
+                if (nameProcessed[name] || name === "__proto__")
+                    continue;
+
+                nameProcessed[name] = true;
+
+                var descriptor = Object.getOwnPropertyDescriptor(o, name);
+                if (!descriptor) {
+                    // FIXME: Bad descriptor. Can we get here?
+                    // Fall back to very restrictive settings.
+                    var fakeDescriptor = createFakeValueDescriptor(name, {writable: false, configurable: false, enumerable: false}, isOwnProperty);
+                    processDescriptor(fakeDescriptor, isOwnProperty);
+                    continue;
+                }
+
+                if (descriptor.hasOwnProperty("get") && descriptor.hasOwnProperty("set") && !descriptor.get && !descriptor.set) {
+                    // FIXME: <https://webkit.org/b/140575> Web Inspector: Native Bindings Descriptors are Incomplete
+                    // Developers may create such a descriptors, so we should be resilient:
+                    // var x = {}; Object.defineProperty(x, "p", {get:undefined}); Object.getOwnPropertyDescriptor(x, "p")
+                    var fakeDescriptor = createFakeValueDescriptor(name, descriptor, isOwnProperty);
+                    processDescriptor(fakeDescriptor, isOwnProperty, true);
+                    continue;
+                }
+
+                descriptor.name = name;
+                if (isOwnProperty)
+                    descriptor.isOwn = true;
+                processDescriptor(descriptor, isOwnProperty);
+            }
+        }
+
+        // Iterate prototype chain.
+        for (var o = object; this._isDefined(o); o = o.__proto__) {
+            var isOwnProperty = o === object;
+            processPropertyNames(o, Object.getOwnPropertyNames(o), isOwnProperty);
+            if (ownProperties)
+                break;
+        }
+        
+        // Include __proto__ at the end.
+        try {
+            if (object.__proto__)
+                descriptors.push({name: "__proto__", value: object.__proto__, writable: true, configurable: true, enumerable: false, isOwn: true});
+        } catch (e) {}
+
+        return descriptors;
+    },
+
     /**
      * @param {*} object
      * @return {boolean}
index 4b8301ad2a6d81bbd487f1dc4d89968543d08f86..ebdd1809625bdc85695bfe2e95c6c8a3dbc235a4 100644 (file)
 #include <dlfcn.h>
 #include <execinfo.h>
 
+#if ENABLE(REMOTE_INSPECTOR)
+#include "JSGlobalObjectDebuggable.h"
+#include "RemoteInspector.h"
+#endif
+
 using namespace JSC;
 
 namespace Inspector {
@@ -175,6 +180,19 @@ ConsoleClient* JSGlobalObjectInspectorController::consoleClient() const
     return m_consoleClient.get();
 }
 
+bool JSGlobalObjectInspectorController::developerExtrasEnabled() const
+{
+#if ENABLE(REMOTE_INSPECTOR)
+    if (!RemoteInspector::shared().enabled())
+        return false;
+
+    if (!m_globalObject.inspectorDebuggable().remoteDebuggingAllowed())
+        return false;
+#endif
+
+    return true;
+}
+
 InspectorFunctionCallHandler JSGlobalObjectInspectorController::functionCallHandler() const
 {
     return JSC::call;
index 983771723d6b018bd7f7d40c77ef62fec33ff90b..61ab1c13c2b70462e4d27a7cbf41df23ceaacacf 100644 (file)
@@ -71,7 +71,7 @@ public:
 
     JSC::ConsoleClient* consoleClient() const;
 
-    virtual bool developerExtrasEnabled() const override { return true; }
+    virtual bool developerExtrasEnabled() const override;
     virtual bool canAccessInspectedScriptState(JSC::ExecState*) const override { return true; }
     virtual InspectorFunctionCallHandler functionCallHandler() const override;
     virtual InspectorEvaluateHandler evaluateHandler() const override;
index d8d69a25417211afb876c00deb488435fcd38e3a..ac65979350c1330fd3b32f323a6a87c3c3344738 100644 (file)
@@ -157,7 +157,7 @@ void InspectorRuntimeAgent::callFunctionOn(ErrorString* errorString, const Strin
     }
 }
 
-void InspectorRuntimeAgent::getProperties(ErrorString* errorString, const String& objectId, const bool* const ownProperties, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>>& internalProperties)
+void InspectorRuntimeAgent::getProperties(ErrorString* errorString, const String& objectId, const bool* const ownProperties, const bool* const ownAndGetterProperties, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>>& internalProperties)
 {
     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
     if (injectedScript.hasNoValue()) {
@@ -168,7 +168,7 @@ void InspectorRuntimeAgent::getProperties(ErrorString* errorString, const String
     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = setPauseOnExceptionsState(m_scriptDebugServer, ScriptDebugServer::DontPauseOnExceptions);
     muteConsole();
 
-    injectedScript.getProperties(errorString, objectId, ownProperties ? *ownProperties : false, &result);
+    injectedScript.getProperties(errorString, objectId, ownProperties ? *ownProperties : false, ownAndGetterProperties ? *ownAndGetterProperties : false, &result);
     injectedScript.getInternalProperties(errorString, objectId, &internalProperties);
 
     unmuteConsole();
index d6c1eea20041e7681eca19f876175a7812b0af24..faf43788aa2cc36365b6e0cf3dd74eaa34813ab1 100644 (file)
@@ -63,7 +63,7 @@ public:
     virtual void evaluate(ErrorString*, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) override final;
     virtual void callFunctionOn(ErrorString*, const String& objectId, const String& expression, const RefPtr<Inspector::InspectorArray>* optionalArguments, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result, Inspector::TypeBuilder::OptOutput<bool>* wasThrown) override final;
     virtual void releaseObject(ErrorString*, const ErrorString& objectId) override final;
-    virtual void getProperties(ErrorString*, const String& objectId, const bool* ownProperties, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>>& internalProperties) override final;
+    virtual void getProperties(ErrorString*, const String& objectId, const bool* ownProperties, const bool* const ownAndGetterProperties, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::PropertyDescriptor>>& result, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Runtime::InternalPropertyDescriptor>>& internalProperties) override final;
     virtual void releaseObjectGroup(ErrorString*, const String& objectGroup) override final;
     virtual void run(ErrorString*) override;
 
index f7bf133b4ae4f793051715e4486e56bb08d7f777..b888aa32b75978b8e40bf98af67210b4a149bf26 100644 (file)
             "name": "getProperties",
             "parameters": [
                 { "name": "objectId", "$ref": "RemoteObjectId", "description": "Identifier of the object to return properties for." },
-                { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the element itself, not to its prototype chain." }
+                { "name": "ownProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging only to the object itself, not to its prototype chain." },
+                { "name": "ownAndGetterProperties", "optional": true, "type": "boolean", "description": "If true, returns properties belonging to the object itself, and getters in its prototype chain." }
             ],
             "returns": [
                 { "name": "result", "type": "array", "items": { "$ref": "PropertyDescriptor"}, "description": "Object properties." },
index f7c4dc811d4553abef5eb180f28821eec1b17860..fb074290200cc92ff747a0ad43f429f94084bfd4 100644 (file)
@@ -173,6 +173,7 @@ CallFrame* sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arg
     if (asObject(arguments)->classInfo() == Arguments::info()) {
         Arguments* argsObject = asArguments(arguments);
         unsigned argCount = argsObject->length(callFrame);
+        callFrame->vm().varargsLength = argCount;
         if (argCount >= firstVarArgOffset)
             argCount -= firstVarArgOffset;
         else
@@ -204,6 +205,7 @@ CallFrame* sizeFrameForVarargs(CallFrame* callFrame, JSStack* stack, JSValue arg
 
     JSObject* argObject = asObject(arguments);
     unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
+    callFrame->vm().varargsLength = argCount;
     if (argCount >= firstVarArgOffset)
         argCount -= firstVarArgOffset;
     else
@@ -240,7 +242,8 @@ void loadVarargs(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValu
     
     if (asObject(arguments)->classInfo() == Arguments::info()) {
         Arguments* argsObject = asArguments(arguments);
-        unsigned argCount = argsObject->length(callFrame);
+        unsigned argCount = callFrame->vm().varargsLength;
+        callFrame->vm().varargsLength = 0;
         if (argCount >= firstVarArgOffset) {
             argCount -= firstVarArgOffset;
             newCallFrame->setArgumentCountIncludingThis(argCount + 1);
@@ -264,8 +267,7 @@ void loadVarargs(CallFrame* callFrame, CallFrame* newCallFrame, JSValue thisValu
         return;
     }
     
-    JSObject* argObject = asObject(arguments);
-    unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
+    unsigned argCount = callFrame->vm().varargsLength;
     if (argCount >= firstVarArgOffset) {
         argCount -= firstVarArgOffset;
         newCallFrame->setArgumentCountIncludingThis(argCount + 1);
index de8adc45ca2c0d04dd20633a52ec2ba67a9dad74..25a843fcbade8e0dcf41b3b5285ad84da89c500e 100644 (file)
@@ -626,6 +626,11 @@ void JIT::emit_op_push_name_scope(Instruction* currentInstruction)
 
 void JIT::emit_op_catch(Instruction* currentInstruction)
 {
+    // Gotta restore the tag registers. We could be throwing from FTL, which may
+    // clobber them.
+    move(TrustedImm64(TagTypeNumber), tagTypeNumberRegister);
+    move(TrustedImm64(TagMask), tagMaskRegister);
+    
     move(TrustedImmPtr(m_vm), regT3);
     load64(Address(regT3, VM::callFrameForThrowOffset()), callFrameRegister);
 
index 608ebd5818fbb1ba29d77a7f964b8a476d8390ef..f93d99d70a119b92bce2528e7b6f427eb120eb40 100644 (file)
@@ -86,7 +86,6 @@ RegisterSet RegisterSet::calleeSaveRegisters()
     result.set(ARMRegisters::r5);
     result.set(ARMRegisters::r6);
     result.set(ARMRegisters::r8);
-    result.set(ARMRegisters::r9);
     result.set(ARMRegisters::r10);
     result.set(ARMRegisters::r11);
 #elif CPU(ARM64)
index 45a604cc2a64ebbe71b033f4217e83fefa4474c6..f0aa44ef07b818c28266527a08f24bcf18433d28 100644 (file)
@@ -63,6 +63,8 @@ const ValueFalse      = TagBitTypeOther | TagBitBool
 const ValueTrue       = TagBitTypeOther | TagBitBool | 1
 const ValueUndefined  = TagBitTypeOther | TagBitUndefined
 const ValueNull       = TagBitTypeOther
+    const TagTypeNumber   = 0xffff000000000000
+    const TagMask         = TagTypeNumber | TagBitTypeOther
 else
 const Int32Tag = -1
 const BooleanTag = -2
index 486b7b3580b8893e942a8467d71ab6d4cc88ffa0..67a8f1b8c9cf3d53616704c5e98a465852c063f4 100644 (file)
@@ -1978,6 +1978,11 @@ _llint_op_next_pname:
 
 
 _llint_op_catch:
+    # Gotta restore the tag registers. We could be throwing from FTL, which may
+    # clobber them.
+    move TagTypeNumber, tagTypeNumber
+    move TagMask, tagMask
+    
     # This is where we end up from the JIT's throw trampoline (because the
     # machine code return address will be set to _llint_op_catch), and from
     # the interpreter's throw trampoline (see _llint_throw_trampoline).
index 9ff2a427869e844f8d5fa5960b2f7ea7d30288cb..f9c11ce2e6240e78f12de977add2551a5a485c2a 100644 (file)
     macro(char *, GetTargetMachineFeatureString, (LLVMTargetMachineRef T)) \
     macro(LLVMTargetDataRef, GetTargetMachineData, (LLVMTargetMachineRef T)) \
     macro(LLVMBool, TargetMachineEmitToFile, (LLVMTargetMachineRef T, LLVMModuleRef M, char *Filename, LLVMCodeGenFileType codegen, char **ErrorMessage)) \
-    macro(void, LinkInJIT, (void)) \
     macro(void, LinkInMCJIT, (void)) \
-    macro(void, LinkInInterpreter, (void)) \
     macro(LLVMGenericValueRef, CreateGenericValueOfInt, (LLVMTypeRef Ty, unsigned long long N, LLVMBool IsSigned)) \
     macro(LLVMGenericValueRef, CreateGenericValueOfPointer, (void *P)) \
     macro(LLVMGenericValueRef, CreateGenericValueOfFloat, (LLVMTypeRef Ty, double N)) \
index 56cdfd0cfb2632e801b04c3488cea35d726e4595..b1979f2a302608e5779665c330c51914ea5f8666 100644 (file)
@@ -92,7 +92,6 @@ extern "C" JSC::LLVMAPI* initializeAndGetJSCLLVMAPI(void (*callback)(const char*
     
     const char* args[] = {
         "llvmForJSC.dylib",
-        "-enable-stackmap-liveness=true",
         "-enable-patchpoint-liveness=true"
     };
     llvm::cl::ParseCommandLineOptions(sizeof(args) / sizeof(const char*), args);
index e806d45e162d2a6f56011daa8c836b2d80616156..d8bc2cffa427314564fd1b0415c82475ce52b235 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef ParserArena_h
 #define ParserArena_h
 
+#include "CommonIdentifiers.h"
 #include "Identifier.h"
 #include <array>
 #include <wtf/SegmentedVector.h>
@@ -72,6 +73,8 @@ namespace JSC {
     template <typename T>
     ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifier(VM* vm, const T* characters, size_t length)
     {
+        if (!length)
+            return vm->propertyNames->emptyIdentifier;
         if (characters[0] >= MaximumCachableCharacter) {
             m_identifiers.append(Identifier(vm, characters, length));
             return m_identifiers.last();
@@ -93,6 +96,8 @@ namespace JSC {
 
     ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifierLCharFromUChar(VM* vm, const UChar* characters, size_t length)
     {
+        if (!length)
+            return vm->propertyNames->emptyIdentifier;
         if (characters[0] >= MaximumCachableCharacter) {
             m_identifiers.append(Identifier::createLCharFromUChar(vm, characters, length));
             return m_identifiers.last();
index b9e73ae31817d4b9f162351a25eff0148d43e06c..f09e03a2e7a122fe7717531693b7517d438b4063 100644 (file)
@@ -169,6 +169,8 @@ void MapData::replaceAndPackBackingStore(Entry* destination, int32_t newCapacity
     // Fixup for the hashmaps
     for (auto ptr = m_valueKeyedTable.begin(); ptr != m_valueKeyedTable.end(); ++ptr)
         ptr->value = m_entries[ptr->value].value.get().asInt32();
+    for (auto ptr = m_cellKeyedTable.begin(); ptr != m_cellKeyedTable.end(); ++ptr)
+        ptr->value = m_entries[ptr->value].value.get().asInt32();
     for (auto ptr = m_stringKeyedTable.begin(); ptr != m_stringKeyedTable.end(); ++ptr)
         ptr->value = m_entries[ptr->value].value.get().asInt32();
 
index 3f7fb0e1fa9928230113f34fff3d6fe02c0bdceb..fdfc06ee5cf0041b14535cbca7022bb5ee1de9d3 100644 (file)
@@ -198,6 +198,7 @@ VM::VM(VMType vmType, HeapType heapType)
     , interpreter(0)
     , jsArrayClassInfo(JSArray::info())
     , jsFinalObjectClassInfo(JSFinalObject::info())
+    , varargsLength(0)
     , sizeOfLastScratchBuffer(0)
     , entryScope(0)
     , m_regExpCache(new RegExpCache(this))
index 1f4d172a9eb2175d2fcfecc4ee926ace6ff5c3a1..8d55cb72aeb51a2c0959122ca5d46d96b80ae211 100644 (file)
@@ -414,6 +414,7 @@ namespace JSC {
 
         JSValue hostCallReturnValue;
         ExecState* newCallFrameReturnValue;
+        unsigned varargsLength;
         ExecState* callFrameForThrow;
         void* targetMachinePCForThrow;
         Instruction* targetInterpreterPCForThrow;
diff --git a/tests/stress/get-my-argument-by-val-inlined-no-formal-parameters.js b/tests/stress/get-my-argument-by-val-inlined-no-formal-parameters.js
new file mode 100644 (file)
index 0000000..eef298f
--- /dev/null
@@ -0,0 +1,33 @@
+var index;
+
+function foo() {
+    if (index >= 0)
+        return arguments[index];
+    else
+        return 13;
+}
+
+function bar() {
+    return foo();
+}
+
+noInline(bar);
+
+for (var i = 0; i < 100; ++i) {
+    index = i & 1;
+    var result = foo(42, 53);
+    if (result != [42, 53][index])
+        throw "Error: bad result in first loop: " + result;
+}
+
+for (var i = 0; i < 100000; ++i) {
+    index = -(i & 1) - 1;
+    var result = bar();
+    if (result !== 13)
+        throw "Error: bad result in second loop: " + result;
+}
+
+index = 0;
+var result = bar();
+if (result !== void 0)
+    throw "Error: bad result at end: " + result;
diff --git a/tests/stress/regress-141489.js b/tests/stress/regress-141489.js
new file mode 100644 (file)
index 0000000..bbca89c
--- /dev/null
@@ -0,0 +1,34 @@
+// this test checks that register r9 is not a callee save on ios armv7.
+function ident(a) { 
+    return a; 
+}
+
+function foo(array,obj) { 
+    var a = array[0]; 
+    var b = array[1]; 
+    var c = array[2]; 
+    obj.a = array;
+    obj.b = array;
+    obj.c = array;
+    obj.d = array;
+    obj.e = array;
+    obj.f = array;
+    obj.h = array;
+    return a(b(c(10)));
+}
+noInline(foo);
+
+var arr = [ident,ident,ident];
+
+for (var i = 0; i < 100; i++) {
+    var obj = {};
+    for (var j = 0; j < 200; j ++) {
+        obj["j"+j] = i;
+    }
+    foo(arr, obj);
+}
+
+for (var i = 0; i < 100; i++) {
+    var obj = {};
+    foo(arr, obj);
+}
\ No newline at end of file
diff --git a/tests/stress/throw-from-ftl-call-ic-slow-path-cells.js b/tests/stress/throw-from-ftl-call-ic-slow-path-cells.js
new file mode 100644 (file)
index 0000000..9e70485
--- /dev/null
@@ -0,0 +1,192 @@
+// Attempts to induce a crash resulting from the FTL emitting code that clobbers the tag registers and then
+// throwing an exception without restoring those tag registers' values.
+
+function ftlFunction(array, callee) {
+    // Gotta use lots of gprs.
+    var x0 = array[0];
+    var x1 = array[1];
+    var x2 = array[2];
+    var x3 = array[3];
+    var x4 = array[4];
+    var x5 = array[5];
+    var x6 = array[6];
+    var x7 = array[7];
+    var x8 = array[8];
+    var x9 = array[9];
+    var x10 = array[10];
+    var x11 = array[11];
+    var x12 = array[12];
+    var x13 = array[13];
+    var x14 = array[14];
+    var x15 = array[15];
+    var x16 = array[16];
+    var x17 = array[17];
+    var x18 = array[18];
+    var x19 = array[19];
+    var x20 = array[20];
+    var x21 = array[21];
+    var x22 = array[22];
+    var x23 = array[23];
+    var x24 = array[24];
+    var x25 = array[25];
+    var x26 = array[26];
+    var x27 = array[27];
+    var x28 = array[28];
+    var x29 = array[29];
+    var x30 = array[30];
+    var x31 = array[31];
+    var x32 = array[32];
+    var x33 = array[33];
+    var x34 = array[34];
+    var x35 = array[35];
+    var x36 = array[36];
+    var x37 = array[37];
+    var x38 = array[38];
+    var x39 = array[39];
+    var x40 = array[40];
+    var x41 = array[41];
+    var x42 = array[42];
+    var x43 = array[43];
+    var x44 = array[44];
+    var x45 = array[45];
+    var x46 = array[46];
+    var x47 = array[47];
+    var x48 = array[48];
+    var x49 = array[49];
+    var x50 = array[50];
+    var x51 = array[51];
+    var x52 = array[52];
+    var x53 = array[53];
+    var x54 = array[54];
+    var x55 = array[55];
+    var x56 = array[56];
+    var x57 = array[57];
+    var x58 = array[58];
+    var x59 = array[59];
+    var x60 = array[60];
+    var x61 = array[61];
+    var x62 = array[62];
+    var x63 = array[63];
+    
+    // Make a call that will throw, when we ask it to.
+    callee("hello");
+    
+    // Use all of those crazy values.
+    return [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63]
+}
+
+noInline(ftlFunction);
+
+// Create some callees that are too crazy to get inlined or devirtualized, but that don't have effects.
+
+function happyCallee0() { return 0 };
+function happyCallee1() { return 1 };
+function happyCallee2() { return 2 };
+function happyCallee3() { return 3 };
+function happyCallee4() { return 4 };
+function happyCallee5() { return 5 };
+function happyCallee6() { return 6 };
+function happyCallee7() { return 7 };
+function happyCallee8() { return 8 };
+function happyCallee9() { return 9 };
+function happyCallee10() { return 10 };
+function happyCallee11() { return 11 };
+function happyCallee12() { return 12 };
+function happyCallee13() { return 13 };
+function happyCallee14() { return 14 };
+function happyCallee15() { return 15 };
+function happyCallee16() { return 16 };
+function happyCallee17() { return 17 };
+function happyCallee18() { return 18 };
+function happyCallee19() { return 19 };
+function happyCallee20() { return 20 };
+function happyCallee21() { return 21 };
+function happyCallee22() { return 22 };
+function happyCallee23() { return 23 };
+function happyCallee24() { return 24 };
+function happyCallee25() { return 25 };
+function happyCallee26() { return 26 };
+function happyCallee27() { return 27 };
+function happyCallee28() { return 28 };
+function happyCallee29() { return 29 };
+function happyCallee30() { return 30 };
+function happyCallee31() { return 31 };
+function happyCallee32() { return 32 };
+function happyCallee33() { return 33 };
+function happyCallee34() { return 34 };
+function happyCallee35() { return 35 };
+function happyCallee36() { return 36 };
+function happyCallee37() { return 37 };
+function happyCallee38() { return 38 };
+function happyCallee39() { return 39 };
+function happyCallee40() { return 40 };
+function happyCallee41() { return 41 };
+function happyCallee42() { return 42 };
+function happyCallee43() { return 43 };
+function happyCallee44() { return 44 };
+function happyCallee45() { return 45 };
+function happyCallee46() { return 46 };
+function happyCallee47() { return 47 };
+function happyCallee48() { return 48 };
+function happyCallee49() { return 49 };
+function happyCallee50() { return 50 };
+function happyCallee51() { return 51 };
+function happyCallee52() { return 52 };
+function happyCallee53() { return 53 };
+function happyCallee54() { return 54 };
+function happyCallee55() { return 55 };
+function happyCallee56() { return 56 };
+function happyCallee57() { return 57 };
+function happyCallee58() { return 58 };
+function happyCallee59() { return 59 };
+function happyCallee60() { return 60 };
+function happyCallee61() { return 61 };
+function happyCallee62() { return 62 };
+function happyCallee63() { return 63 };
+
+var happyCallees = [happyCallee0, happyCallee1, happyCallee2, happyCallee3, happyCallee4, happyCallee5, happyCallee6, happyCallee7, happyCallee8, happyCallee9, happyCallee10, happyCallee11, happyCallee12, happyCallee13, happyCallee14, happyCallee15, happyCallee16, happyCallee17, happyCallee18, happyCallee19, happyCallee20, happyCallee21, happyCallee22, happyCallee23, happyCallee24, happyCallee25, happyCallee26, happyCallee27, happyCallee28, happyCallee29, happyCallee30, happyCallee31, happyCallee32, happyCallee33, happyCallee34, happyCallee35, happyCallee36, happyCallee37, happyCallee38, happyCallee39, happyCallee40, happyCallee41, happyCallee42, happyCallee43, happyCallee44, happyCallee45, happyCallee46, happyCallee47, happyCallee48, happyCallee49, happyCallee50, happyCallee51, happyCallee52, happyCallee53, happyCallee54, happyCallee55, happyCallee56, happyCallee57, happyCallee58, happyCallee59, happyCallee60, happyCallee61, happyCallee62, happyCallee63];
+
+for (var i = 0; i < happyCallees.length; ++i)
+    noInline(happyCallees[i]);
+
+// Unlike the other test (throw-from-ftl-call-ic-slow-path.js), we want to populate the registers with cells in
+// this test.
+var array = new Array();
+for (var i = 0; i < 64; ++i)
+    array[i] = new Object();
+
+// Now, do some warming up.
+for (var i = 0; i < 100000; ++i) {
+    var result = ftlFunction(array, happyCallees[i % happyCallees.length]);
+    if (result.length != array.length)
+        throw "Error: bad length: " + result;
+    for (var j = 0; j < result.length; ++j) {
+        if (result[j] != array[j])
+            throw "Error: bad entry at j = " + j + ": " + result;
+    }
+}
+
+// Finally, attempt to trigger the bug.
+var notACell = 42;
+for (var i = 0; i < 100; ++i) {
+    try {
+        ftlFunction(array, Int8Array);
+    } catch (e) {
+        if (e.message.indexOf("not a function") < 0)
+            throw "Error: bad exception message: " + e.message;
+        var result = notACell.f;
+        if (result !== void 0) {
+            print("Bad outcome of accessing f on notACell.");
+            print("Here's notACell:", notACell, describe(notACell));
+            print("Here's the result:", result, describe(result));
+            throw "Error: bad outcome of accessing f on " + notACell + ": " + result;
+        }
+        var result2 = result + 5;
+        var result3 = notACell + 5;
+        if ("" + result2 != "NaN")
+            throw "Error: bad outcome of adding 5 to result: " + result2;
+        if (result3 != 47)
+            throw "Error: bad outcome of adding 5 to 42: " + result3;
+    }
+}
+
diff --git a/tests/stress/throw-from-ftl-call-ic-slow-path-undefined.js b/tests/stress/throw-from-ftl-call-ic-slow-path-undefined.js
new file mode 100644 (file)
index 0000000..933a273
--- /dev/null
@@ -0,0 +1,192 @@
+// Attempts to induce a crash resulting from the FTL emitting code that clobbers the tag registers and then
+// throwing an exception without restoring those tag registers' values.
+
+function ftlFunction(array, callee) {
+    // Gotta use lots of gprs.
+    var x0 = array[0];
+    var x1 = array[1];
+    var x2 = array[2];
+    var x3 = array[3];
+    var x4 = array[4];
+    var x5 = array[5];
+    var x6 = array[6];
+    var x7 = array[7];
+    var x8 = array[8];
+    var x9 = array[9];
+    var x10 = array[10];
+    var x11 = array[11];
+    var x12 = array[12];
+    var x13 = array[13];
+    var x14 = array[14];
+    var x15 = array[15];
+    var x16 = array[16];
+    var x17 = array[17];
+    var x18 = array[18];
+    var x19 = array[19];
+    var x20 = array[20];
+    var x21 = array[21];
+    var x22 = array[22];
+    var x23 = array[23];
+    var x24 = array[24];
+    var x25 = array[25];
+    var x26 = array[26];
+    var x27 = array[27];
+    var x28 = array[28];
+    var x29 = array[29];
+    var x30 = array[30];
+    var x31 = array[31];
+    var x32 = array[32];
+    var x33 = array[33];
+    var x34 = array[34];
+    var x35 = array[35];
+    var x36 = array[36];
+    var x37 = array[37];
+    var x38 = array[38];
+    var x39 = array[39];
+    var x40 = array[40];
+    var x41 = array[41];
+    var x42 = array[42];
+    var x43 = array[43];
+    var x44 = array[44];
+    var x45 = array[45];
+    var x46 = array[46];
+    var x47 = array[47];
+    var x48 = array[48];
+    var x49 = array[49];
+    var x50 = array[50];
+    var x51 = array[51];
+    var x52 = array[52];
+    var x53 = array[53];
+    var x54 = array[54];
+    var x55 = array[55];
+    var x56 = array[56];
+    var x57 = array[57];
+    var x58 = array[58];
+    var x59 = array[59];
+    var x60 = array[60];
+    var x61 = array[61];
+    var x62 = array[62];
+    var x63 = array[63];
+    
+    // Make a call that will throw, when we ask it to.
+    callee("hello");
+    
+    // Use all of those crazy values.
+    return [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63]
+}
+
+noInline(ftlFunction);
+
+// Create some callees that are too crazy to get inlined or devirtualized, but that don't have effects.
+
+function happyCallee0() { return 0 };
+function happyCallee1() { return 1 };
+function happyCallee2() { return 2 };
+function happyCallee3() { return 3 };
+function happyCallee4() { return 4 };
+function happyCallee5() { return 5 };
+function happyCallee6() { return 6 };
+function happyCallee7() { return 7 };
+function happyCallee8() { return 8 };
+function happyCallee9() { return 9 };
+function happyCallee10() { return 10 };
+function happyCallee11() { return 11 };
+function happyCallee12() { return 12 };
+function happyCallee13() { return 13 };
+function happyCallee14() { return 14 };
+function happyCallee15() { return 15 };
+function happyCallee16() { return 16 };
+function happyCallee17() { return 17 };
+function happyCallee18() { return 18 };
+function happyCallee19() { return 19 };
+function happyCallee20() { return 20 };
+function happyCallee21() { return 21 };
+function happyCallee22() { return 22 };
+function happyCallee23() { return 23 };
+function happyCallee24() { return 24 };
+function happyCallee25() { return 25 };
+function happyCallee26() { return 26 };
+function happyCallee27() { return 27 };
+function happyCallee28() { return 28 };
+function happyCallee29() { return 29 };
+function happyCallee30() { return 30 };
+function happyCallee31() { return 31 };
+function happyCallee32() { return 32 };
+function happyCallee33() { return 33 };
+function happyCallee34() { return 34 };
+function happyCallee35() { return 35 };
+function happyCallee36() { return 36 };
+function happyCallee37() { return 37 };
+function happyCallee38() { return 38 };
+function happyCallee39() { return 39 };
+function happyCallee40() { return 40 };
+function happyCallee41() { return 41 };
+function happyCallee42() { return 42 };
+function happyCallee43() { return 43 };
+function happyCallee44() { return 44 };
+function happyCallee45() { return 45 };
+function happyCallee46() { return 46 };
+function happyCallee47() { return 47 };
+function happyCallee48() { return 48 };
+function happyCallee49() { return 49 };
+function happyCallee50() { return 50 };
+function happyCallee51() { return 51 };
+function happyCallee52() { return 52 };
+function happyCallee53() { return 53 };
+function happyCallee54() { return 54 };
+function happyCallee55() { return 55 };
+function happyCallee56() { return 56 };
+function happyCallee57() { return 57 };
+function happyCallee58() { return 58 };
+function happyCallee59() { return 59 };
+function happyCallee60() { return 60 };
+function happyCallee61() { return 61 };
+function happyCallee62() { return 62 };
+function happyCallee63() { return 63 };
+
+var happyCallees = [happyCallee0, happyCallee1, happyCallee2, happyCallee3, happyCallee4, happyCallee5, happyCallee6, happyCallee7, happyCallee8, happyCallee9, happyCallee10, happyCallee11, happyCallee12, happyCallee13, happyCallee14, happyCallee15, happyCallee16, happyCallee17, happyCallee18, happyCallee19, happyCallee20, happyCallee21, happyCallee22, happyCallee23, happyCallee24, happyCallee25, happyCallee26, happyCallee27, happyCallee28, happyCallee29, happyCallee30, happyCallee31, happyCallee32, happyCallee33, happyCallee34, happyCallee35, happyCallee36, happyCallee37, happyCallee38, happyCallee39, happyCallee40, happyCallee41, happyCallee42, happyCallee43, happyCallee44, happyCallee45, happyCallee46, happyCallee47, happyCallee48, happyCallee49, happyCallee50, happyCallee51, happyCallee52, happyCallee53, happyCallee54, happyCallee55, happyCallee56, happyCallee57, happyCallee58, happyCallee59, happyCallee60, happyCallee61, happyCallee62, happyCallee63];
+
+for (var i = 0; i < happyCallees.length; ++i)
+    noInline(happyCallees[i]);
+
+// Unlike the other test (throw-from-ftl-call-ic-slow-path.js), we want to populate the registers with undefined
+// in this test.
+var array = new Array();
+for (var i = 0; i < 64; ++i)
+    array[i] = void 0;
+
+// Now, do some warming up.
+for (var i = 0; i < 100000; ++i) {
+    var result = ftlFunction(array, happyCallees[i % happyCallees.length]);
+    if (result.length != array.length)
+        throw "Error: bad length: " + result;
+    for (var j = 0; j < result.length; ++j) {
+        if (result[j] != array[j])
+            throw "Error: bad entry at j = " + j + ": " + result;
+    }
+}
+
+// Finally, attempt to trigger the bug.
+var notACell = 42;
+for (var i = 0; i < 100; ++i) {
+    try {
+        ftlFunction(array, Int8Array);
+    } catch (e) {
+        if (e.message.indexOf("not a function") < 0)
+            throw "Error: bad exception message: " + e.message;
+        var result = notACell.f;
+        if (result !== void 0) {
+            print("Bad outcome of accessing f on notACell.");
+            print("Here's notACell:", notACell, describe(notACell));
+            print("Here's the result:", result, describe(result));
+            throw "Error: bad outcome of accessing f on " + notACell + ": " + result;
+        }
+        var result2 = result + 5;
+        var result3 = notACell + 5;
+        if ("" + result2 != "NaN")
+            throw "Error: bad outcome of adding 5 to result: " + result2;
+        if (result3 != 47)
+            throw "Error: bad outcome of adding 5 to 42: " + result3;
+    }
+}
+
diff --git a/tests/stress/throw-from-ftl-call-ic-slow-path.js b/tests/stress/throw-from-ftl-call-ic-slow-path.js
new file mode 100644 (file)
index 0000000..fb69204
--- /dev/null
@@ -0,0 +1,192 @@
+// Attempts to induce a crash resulting from the FTL emitting code that clobbers the tag registers and then
+// throwing an exception without restoring those tag registers' values.
+
+function ftlFunction(array, callee) {
+    // Gotta use lots of gprs.
+    var x0 = array[0];
+    var x1 = array[1];
+    var x2 = array[2];
+    var x3 = array[3];
+    var x4 = array[4];
+    var x5 = array[5];
+    var x6 = array[6];
+    var x7 = array[7];
+    var x8 = array[8];
+    var x9 = array[9];
+    var x10 = array[10];
+    var x11 = array[11];
+    var x12 = array[12];
+    var x13 = array[13];
+    var x14 = array[14];
+    var x15 = array[15];
+    var x16 = array[16];
+    var x17 = array[17];
+    var x18 = array[18];
+    var x19 = array[19];
+    var x20 = array[20];
+    var x21 = array[21];
+    var x22 = array[22];
+    var x23 = array[23];
+    var x24 = array[24];
+    var x25 = array[25];
+    var x26 = array[26];
+    var x27 = array[27];
+    var x28 = array[28];
+    var x29 = array[29];
+    var x30 = array[30];
+    var x31 = array[31];
+    var x32 = array[32];
+    var x33 = array[33];
+    var x34 = array[34];
+    var x35 = array[35];
+    var x36 = array[36];
+    var x37 = array[37];
+    var x38 = array[38];
+    var x39 = array[39];
+    var x40 = array[40];
+    var x41 = array[41];
+    var x42 = array[42];
+    var x43 = array[43];
+    var x44 = array[44];
+    var x45 = array[45];
+    var x46 = array[46];
+    var x47 = array[47];
+    var x48 = array[48];
+    var x49 = array[49];
+    var x50 = array[50];
+    var x51 = array[51];
+    var x52 = array[52];
+    var x53 = array[53];
+    var x54 = array[54];
+    var x55 = array[55];
+    var x56 = array[56];
+    var x57 = array[57];
+    var x58 = array[58];
+    var x59 = array[59];
+    var x60 = array[60];
+    var x61 = array[61];
+    var x62 = array[62];
+    var x63 = array[63];
+    
+    // Make a call that will throw, when we ask it to.
+    callee("hello");
+    
+    // Use all of those crazy values.
+    return [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63]
+}
+
+noInline(ftlFunction);
+
+// Create some callees that are too crazy to get inlined or devirtualized, but that don't have effects.
+
+function happyCallee0() { return 0 };
+function happyCallee1() { return 1 };
+function happyCallee2() { return 2 };
+function happyCallee3() { return 3 };
+function happyCallee4() { return 4 };
+function happyCallee5() { return 5 };
+function happyCallee6() { return 6 };
+function happyCallee7() { return 7 };
+function happyCallee8() { return 8 };
+function happyCallee9() { return 9 };
+function happyCallee10() { return 10 };
+function happyCallee11() { return 11 };
+function happyCallee12() { return 12 };
+function happyCallee13() { return 13 };
+function happyCallee14() { return 14 };
+function happyCallee15() { return 15 };
+function happyCallee16() { return 16 };
+function happyCallee17() { return 17 };
+function happyCallee18() { return 18 };
+function happyCallee19() { return 19 };
+function happyCallee20() { return 20 };
+function happyCallee21() { return 21 };
+function happyCallee22() { return 22 };
+function happyCallee23() { return 23 };
+function happyCallee24() { return 24 };
+function happyCallee25() { return 25 };
+function happyCallee26() { return 26 };
+function happyCallee27() { return 27 };
+function happyCallee28() { return 28 };
+function happyCallee29() { return 29 };
+function happyCallee30() { return 30 };
+function happyCallee31() { return 31 };
+function happyCallee32() { return 32 };
+function happyCallee33() { return 33 };
+function happyCallee34() { return 34 };
+function happyCallee35() { return 35 };
+function happyCallee36() { return 36 };
+function happyCallee37() { return 37 };
+function happyCallee38() { return 38 };
+function happyCallee39() { return 39 };
+function happyCallee40() { return 40 };
+function happyCallee41() { return 41 };
+function happyCallee42() { return 42 };
+function happyCallee43() { return 43 };
+function happyCallee44() { return 44 };
+function happyCallee45() { return 45 };
+function happyCallee46() { return 46 };
+function happyCallee47() { return 47 };
+function happyCallee48() { return 48 };
+function happyCallee49() { return 49 };
+function happyCallee50() { return 50 };
+function happyCallee51() { return 51 };
+function happyCallee52() { return 52 };
+function happyCallee53() { return 53 };
+function happyCallee54() { return 54 };
+function happyCallee55() { return 55 };
+function happyCallee56() { return 56 };
+function happyCallee57() { return 57 };
+function happyCallee58() { return 58 };
+function happyCallee59() { return 59 };
+function happyCallee60() { return 60 };
+function happyCallee61() { return 61 };
+function happyCallee62() { return 62 };
+function happyCallee63() { return 63 };
+
+var happyCallees = [happyCallee0, happyCallee1, happyCallee2, happyCallee3, happyCallee4, happyCallee5, happyCallee6, happyCallee7, happyCallee8, happyCallee9, happyCallee10, happyCallee11, happyCallee12, happyCallee13, happyCallee14, happyCallee15, happyCallee16, happyCallee17, happyCallee18, happyCallee19, happyCallee20, happyCallee21, happyCallee22, happyCallee23, happyCallee24, happyCallee25, happyCallee26, happyCallee27, happyCallee28, happyCallee29, happyCallee30, happyCallee31, happyCallee32, happyCallee33, happyCallee34, happyCallee35, happyCallee36, happyCallee37, happyCallee38, happyCallee39, happyCallee40, happyCallee41, happyCallee42, happyCallee43, happyCallee44, happyCallee45, happyCallee46, happyCallee47, happyCallee48, happyCallee49, happyCallee50, happyCallee51, happyCallee52, happyCallee53, happyCallee54, happyCallee55, happyCallee56, happyCallee57, happyCallee58, happyCallee59, happyCallee60, happyCallee61, happyCallee62, happyCallee63];
+
+for (var i = 0; i < happyCallees.length; ++i)
+    noInline(happyCallees[i]);
+
+// We want the input array to have an easy-to-deal-with type that isn't exactly the same as the type that
+// ftlFunction will return.
+var array = new Int32Array(64);
+for (var i = 0; i < array.length; ++i)
+    array[i] = i;
+
+// Now, do some warming up.
+for (var i = 0; i < 100000; ++i) {
+    var result = ftlFunction(array, happyCallees[i % happyCallees.length]);
+    if (result.length != array.length)
+        throw "Error: bad length: " + result;
+    for (var j = 0; j < result.length; ++j) {
+        if (result[j] != array[j])
+            throw "Error: bad entry at j = " + j + ": " + result;
+    }
+}
+
+// Finally, attempt to trigger the bug.
+var notACell = 42;
+for (var i = 0; i < 100; ++i) {
+    try {
+        ftlFunction(array, Int8Array);
+    } catch (e) {
+        if (e.message.indexOf("not a function") < 0)
+            throw "Error: bad exception message: " + e.message;
+        var result = notACell.f;
+        if (result !== void 0) {
+            print("Bad outcome of accessing f on notACell.");
+            print("Here's notACell:", notACell, describe(notACell));
+            print("Here's the result:", result, describe(result));
+            throw "Error: bad outcome of accessing f on " + notACell + ": " + result;
+        }
+        var result2 = result + 5;
+        var result3 = notACell + 5;
+        if ("" + result2 != "NaN")
+            throw "Error: bad outcome of adding 5 to result: " + result2;
+        if (result3 != 47)
+            throw "Error: bad outcome of adding 5 to 42: " + result3;
+    }
+}
+