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());
}
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()))
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;
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;
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);
}
/*
- * 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
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)
definition.className = className;
m_classRef = JSClassCreate(&definition);
- [self allocateConstructorAndPrototypeWithSuperClassInfo:superClassInfo];
-
return self;
}
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) {
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.
});
// 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
}
}
- 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));
- (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
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
#include "CustomGlobalObjectClassTest.h"
+#include <JavaScriptCore/JSObjectRefPrivate.h>
#include <JavaScriptCore/JavaScriptCore.h>
#include <stdio.h>
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);
+}
#define CustomGlobalObjectClassTest_h
void customGlobalObjectClassTest(void);
+void globalObjectSetPrototypeTest(void);
+void globalObjectPrivatePropertyTest(void);
#endif // CustomGlobalObjectClassTest_h
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
printf("PASS: global context name behaves as expected.\n");
customGlobalObjectClassTest();
+ globalObjectSetPrototypeTest();
+ globalObjectPrivatePropertyTest();
if (failed) {
printf("FAIL: Some tests failed.\n");
/*
- * 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
#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);
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");
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
+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.
// 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))
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.
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 */,
{
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());
}
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));
}
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 -----------------------------
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());
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());
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 -----------------------------------
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());
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 -----------------------------------
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 -----------------------------------
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;
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)
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)
{
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);
}
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);
}
case Array::ArrayStorage:
return arrayModesWithIndexingShape(ArrayStorageShape);
case Array::SlowPutArrayStorage:
- return arrayModesWithIndexingShape(SlowPutArrayStorageShape);
+ return arrayModesWithIndexingShapes(SlowPutArrayStorageShape, ArrayStorageShape);
default:
return asArrayModes(NonArray);
}
}
}
+ 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 {
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)
}
FTL::State state(dfg);
- FTL::lowerDFGToLLVM(state);
+ if (!FTL::lowerDFGToLLVM(state)) {
+ FTL::fail(state);
+ return FTLPath;
+ }
if (reportCompileTimes())
beforeFTL = currentTimeMS();
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);
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()]);
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),
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"
};
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; }
};
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 {
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;
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];
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)
, m_stackmapIDs(0)
{
}
-
- void lower()
+
+
+#define LOWERING_FAILED(node, reason) \
+ loweringFailed((node), __FILE__, __LINE__, WTF_PRETTY_FUNCTION, (reason));
+
+ bool lower()
{
CString name;
if (verboseCompilationEnabled()) {
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);
m_ftlState.dumpState("after lowering");
if (validationEnabled())
verifyModule(m_ftlState.module);
+
+ return m_loweringSucceeded;
}
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));
}
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);
m_out.set(lowJSValue(m_node->child1()), destination);
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
setJSValue(m_out.get(source));
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
}
}
return;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad flush format");
return;
}
}
setJSValue(jsValue);
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
+ LOWERING_FAILED(m_node, "Bad flush format for argument");
+ return;
}
m_availability.operand(variable->local()) = Availability(variable->flushedAt());
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
break;
}
}
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);
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
return;
}
}
// 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(
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad array type");
return;
}
}
result = m_out.load32(pointer);
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad element size");
+ return;
}
if (elementSize(type) < 4) {
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;
} }
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad array type");
+ return;
}
m_out.jump(continuation);
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
+ return;
}
switch (elementSize(type)) {
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);
refType = m_out.refDouble;
break;
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad typed array type");
+ return;
}
}
return;
}
- RELEASE_ASSERT_NOT_REACHED();
- break;
+ LOWERING_FAILED(m_node, "Bad array type");
+ return;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad array type");
return;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad array type");
return;
}
}
}
default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
+ LOWERING_FAILED(m_node, "Bad use kind");
+ return;
}
}
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);
nonSpeculativeCompare(LLVMIntEQ, operationCompareEq);
return;
}
-
- RELEASE_ASSERT_NOT_REACHED();
+
+ LOWERING_FAILED(m_node, "Bad use kinds");
}
void compileCompareEqConstant()
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kinds");
}
void compileCompareStrictEqConstant()
}
default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
+ LOWERING_FAILED(m_node, "Bad use kind");
+ return;
}
m_out.appendTo(switchOnInts, lastNext);
}
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"));
}
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()
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kinds");
}
void compareEqObjectOrOtherToObject(Edge leftChild, Edge rightChild)
return m_out.phi(m_out.boolean, fastResult, slowResult);
}
default:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
return 0;
}
}
case StrictInt52:
return Int52;
}
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Bad use kind");
return Int52;
}
return result;
}
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Corrupt array class");
return 0;
}
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;
}
}
switch (arrayMode.arrayClass()) {
case Array::OriginalArray:
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Unexpected original array");
return 0;
case Array::Array:
m_out.constInt8(arrayMode.shapeMask()));
}
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Corrupt array class");
+ return 0;
}
default:
return;
}
- RELEASE_ASSERT_NOT_REACHED();
+ LOWERING_FAILED(m_node, "Corrupt int52 kind");
}
void setJSValue(Node* node, LValue value)
{
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;
uint32_t m_stackmapIDs;
};
-void lowerDFGToLLVM(State& state)
+bool lowerDFGToLLVM(State& state)
{
LowerDFGToLLVM lowering(state);
- lowering.lower();
+ return lowering.lower();
}
} } // namespace JSC::FTL
namespace JSC { namespace FTL {
-void lowerDFGToLLVM(State&);
+bool lowerDFGToLLVM(State&);
} } // namespace JSC::FTL
// 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);
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)
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();
}
}
-#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 = ®isters;
void* registersEnd = reinterpret_cast<void*>(roundUpToMultipleOf<sizeof(void*)>(reinterpret_cast<uintptr_t>(®isters + 1)));
swapIfBackwards(registersBegin, registersEnd);
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
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,
#ifndef NDEBUG
fastMallocAllow();
#endif
+ for (Thread* thread = threadsToBeDeleted; thread; ) {
+ Thread* nextThread = thread->next;
+ delete thread;
+ thread = nextThread;
+ }
}
}
#ifndef MachineThreads_h
#define MachineThreads_h
+#include <setjmp.h>
#include <wtf/Noncopyable.h>
#include <wtf/ThreadSpecific.h>
#include <wtf/ThreadingPrimitives.h>
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;
} // 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
*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);
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&);
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);
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) {
if (!("enumerable" in descriptor))
descriptor.enumerable = false;
}
+
return descriptors;
},
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
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}
#include <dlfcn.h>
#include <execinfo.h>
+#if ENABLE(REMOTE_INSPECTOR)
+#include "JSGlobalObjectDebuggable.h"
+#include "RemoteInspector.h"
+#endif
+
using namespace JSC;
namespace Inspector {
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;
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;
}
}
-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()) {
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();
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;
"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." },
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
JSObject* argObject = asObject(arguments);
unsigned argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
+ callFrame->vm().varargsLength = argCount;
if (argCount >= firstVarArgOffset)
argCount -= firstVarArgOffset;
else
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);
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);
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);
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)
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
_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).
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)) \
const char* args[] = {
"llvmForJSC.dylib",
- "-enable-stackmap-liveness=true",
"-enable-patchpoint-liveness=true"
};
llvm::cl::ParseCommandLineOptions(sizeof(args) / sizeof(const char*), args);
#ifndef ParserArena_h
#define ParserArena_h
+#include "CommonIdentifiers.h"
#include "Identifier.h"
#include <array>
#include <wtf/SegmentedVector.h>
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();
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();
// 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();
, interpreter(0)
, jsArrayClassInfo(JSArray::info())
, jsFinalObjectClassInfo(JSFinalObject::info())
+ , varargsLength(0)
, sizeOfLastScratchBuffer(0)
, entryScope(0)
, m_regExpCache(new RegExpCache(this))
JSValue hostCallReturnValue;
ExecState* newCallFrameReturnValue;
+ unsigned varargsLength;
ExecState* callFrameForThrow;
void* targetMachinePCForThrow;
Instruction* targetInterpreterPCForThrow;
--- /dev/null
+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;
--- /dev/null
+// 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
--- /dev/null
+// 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;
+ }
+}
+
--- /dev/null
+// 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;
+ }
+}
+
--- /dev/null
+// 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;
+ }
+}
+