Modified: trunk/Source/_javascript_Core/tools/JSDollarVM.cpp (233128 => 233129)
--- trunk/Source/_javascript_Core/tools/JSDollarVM.cpp 2018-06-23 15:30:33 UTC (rev 233128)
+++ trunk/Source/_javascript_Core/tools/JSDollarVM.cpp 2018-06-23 15:48:25 UTC (rev 233129)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -56,6 +56,74 @@
namespace {
+class JSDollarVMCallFrame : public JSDestructibleObject {
+ using Base = JSDestructibleObject;
+public:
+ JSDollarVMCallFrame(VM& vm, Structure* structure)
+ : Base(vm, structure)
+ { }
+
+ static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ }
+
+ static JSDollarVMCallFrame* create(ExecState* exec, unsigned requestedFrameIndex)
+ {
+ VM& vm = exec->vm();
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ Structure* structure = createStructure(vm, globalObject, jsNull());
+ JSDollarVMCallFrame* frame = new (NotNull, allocateCell<JSDollarVMCallFrame>(vm.heap, sizeof(JSDollarVMCallFrame))) JSDollarVMCallFrame(vm, structure);
+ frame->finishCreation(vm, exec, requestedFrameIndex);
+ return frame;
+ }
+
+ void finishCreation(VM& vm, CallFrame* frame, unsigned requestedFrameIndex)
+ {
+ Base::finishCreation(vm);
+
+ auto addProperty = [&] (VM& vm, const char* name, JSValue value) {
+ JSDollarVMCallFrame::addProperty(vm, name, value);
+ };
+
+ unsigned frameIndex = 0;
+ bool isValid = false;
+ frame->iterate([&] (StackVisitor& visitor) {
+
+ if (frameIndex++ != requestedFrameIndex)
+ return StackVisitor::Continue;
+
+ addProperty(vm, "name", jsString(&vm, visitor->functionName()));
+
+ if (visitor->callee().isCell())
+ addProperty(vm, "callee", visitor->callee().asCell());
+
+ CodeBlock* codeBlock = visitor->codeBlock();
+ if (!codeBlock) {
+ addProperty(vm, "codeBlock", codeBlock);
+ addProperty(vm, "unlinkedCodeBlock", codeBlock->unlinkedCodeBlock());
+ addProperty(vm, "executable", codeBlock->ownerExecutable());
+ }
+ isValid = true;
+
+ return StackVisitor::Done;
+ });
+
+ addProperty(vm, "valid", jsBoolean(isValid));
+ }
+
+ DECLARE_INFO;
+
+private:
+ void addProperty(VM& vm, const char* name, JSValue value)
+ {
+ Identifier identifier = Identifier::fromString(&vm, name);
+ putDirect(vm, identifier, value);
+ }
+};
+
+const ClassInfo JSDollarVMCallFrame::s_info = { "CallFrame", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSDollarVMCallFrame) };
+
class ElementHandleOwner;
class Root;
@@ -1245,26 +1313,47 @@
return JSValue::encode(jsUndefined());
}
+// Gets a JSDollarVMCallFrame for a specified frame index.
+// Usage: var callFrame = $vm.callFrame(0) // frame 0 is the top frame.
+// Usage: var callFrame = $vm.callFrame() // implies frame 0 i.e. current frame.
+static EncodedJSValue JSC_HOST_CALL functionCallFrame(ExecState* exec)
+{
+ unsigned frameNumber = 1;
+ if (exec->argumentCount() >= 1) {
+ JSValue value = exec->uncheckedArgument(0);
+ if (!value.isUInt32())
+ return JSValue::encode(jsUndefined());
+
+ // We need to inc the frame number because the caller would consider
+ // its own frame as frame 0. Hence, we need discount the frame for this
+ // function.
+ frameNumber = value.asUInt32() + 1;
+ }
+
+ return JSValue::encode(JSDollarVMCallFrame::create(exec, frameNumber));
+}
+
// Gets a token for the CodeBlock for a specified frame index.
// Usage: codeBlockToken = $vm.codeBlockForFrame(0) // frame 0 is the top frame.
+// Usage: codeBlockToken = $vm.codeBlockForFrame() // implies frame 0 i.e. current frame.
static EncodedJSValue JSC_HOST_CALL functionCodeBlockForFrame(ExecState* exec)
{
- if (exec->argumentCount() < 1)
- return JSValue::encode(jsUndefined());
+ unsigned frameNumber = 1;
+ if (exec->argumentCount() >= 1) {
+ JSValue value = exec->uncheckedArgument(0);
+ if (!value.isUInt32())
+ return JSValue::encode(jsUndefined());
- JSValue value = exec->uncheckedArgument(0);
- if (!value.isUInt32())
- return JSValue::encode(jsUndefined());
+ // We need to inc the frame number because the caller would consider
+ // its own frame as frame 0. Hence, we need discount the frame for this
+ // function.
+ frameNumber = value.asUInt32() + 1;
+ }
- // We need to inc the frame number because the caller would consider
- // its own frame as frame 0. Hence, we need discount the frame for this
- // function.
- unsigned frameNumber = value.asUInt32() + 1;
CodeBlock* codeBlock = VMInspector::codeBlockForFrame(exec, frameNumber);
- // Though CodeBlock is a JSCell, it is not safe to return it directly back to JS code
- // as it is an internal type that the JS code cannot handle. Hence, we first encode the
- // CodeBlock* as a double token (which is safe for JS code to handle) before returning it.
- return JSValue::encode(JSValue(bitwise_cast<double>(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(codeBlock)))));
+ if (codeBlock)
+ return JSValue::encode(codeBlock);
+ return JSValue::encode(jsUndefined());
}
static CodeBlock* codeBlockFromArg(ExecState* exec)
@@ -1282,12 +1371,8 @@
candidateCodeBlock = nullptr;
else
candidateCodeBlock = func->jsExecutable()->eitherCodeBlock();
- }
- } else if (value.isDouble()) {
- // If the value is a double, it may be an encoded CodeBlock* that came from
- // $vm.codeBlockForFrame(). We'll treat it as a candidate codeBlock and check if it's
- // valid below before using.
- candidateCodeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble()));
+ } else
+ candidateCodeBlock = reinterpret_cast<CodeBlock*>(value.asCell());
}
if (candidateCodeBlock && VMInspector::isValidCodeBlock(exec, candidateCodeBlock))
@@ -1333,19 +1418,43 @@
return JSValue::encode(jsUndefined());
}
-// Prints a series of comma separate strings without inserting a newline.
-// Usage: $vm.print(str1, str2, str3)
-static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
+static EncodedJSValue doPrintln(ExecState* exec, bool addLineFeed)
{
auto scope = DECLARE_THROW_SCOPE(exec->vm());
for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+ JSValue arg = exec->uncheckedArgument(i);
+ if (arg.isCell()
+ && !arg.isObject()
+ && !arg.isString()
+ && !arg.isBigInt()) {
+ dataLog(arg);
+ continue;
+ }
String argStr = exec->uncheckedArgument(i).toWTFString(exec);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
dataLog(argStr);
}
+ if (addLineFeed)
+ dataLog("\n");
return JSValue::encode(jsUndefined());
}
+// Prints a series of comma separate strings without appending a newline.
+// Usage: $vm.print(str1, str2, str3)
+static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
+{
+ const bool addLineFeed = false;
+ return doPrintln(exec, addLineFeed);
+}
+
+// Prints a series of comma separate strings and appends a newline.
+// Usage: $vm.println(str1, str2, str3)
+static EncodedJSValue JSC_HOST_CALL functionPrintln(ExecState* exec)
+{
+ const bool addLineFeed = true;
+ return doPrintln(exec, addLineFeed);
+}
+
// Prints the current CallFrame.
// Usage: $vm.printCallFrame()
static EncodedJSValue JSC_HOST_CALL functionPrintCallFrame(ExecState* exec)
@@ -1717,6 +1826,30 @@
return JSValue::encode(jsUndefined());
}
+static EncodedJSValue changeDebuggerModeWhenIdle(ExecState* exec, DebuggerMode mode)
+{
+ bool newDebuggerMode = (mode == DebuggerOn);
+ if (Options::forceDebuggerBytecodeGeneration() == newDebuggerMode)
+ return JSValue::encode(jsUndefined());
+
+ VM* vm = &exec->vm();
+ vm->whenIdle([=] () {
+ Options::forceDebuggerBytecodeGeneration() = newDebuggerMode;
+ vm->deleteAllCode(PreventCollectionAndDeleteAllCode);
+ });
+ return JSValue::encode(jsUndefined());
+}
+
+static EncodedJSValue JSC_HOST_CALL functionEnableDebuggerModeWhenIdle(ExecState* exec)
+{
+ return changeDebuggerModeWhenIdle(exec, DebuggerOn);
+}
+
+static EncodedJSValue JSC_HOST_CALL functionDisableDebuggerModeWhenIdle(ExecState* exec)
+{
+ return changeDebuggerModeWhenIdle(exec, DebuggerOff);
+}
+
static EncodedJSValue JSC_HOST_CALL functionGlobalObjectCount(ExecState* exec)
{
return JSValue::encode(jsNumber(exec->vm().heap.globalObjectCount()));
@@ -1832,6 +1965,7 @@
addFunction(vm, "gc", functionGC, 0);
addFunction(vm, "edenGC", functionEdenGC, 0);
+ addFunction(vm, "callFrame", functionCallFrame, 1);
addFunction(vm, "codeBlockFor", functionCodeBlockFor, 1);
addFunction(vm, "codeBlockForFrame", functionCodeBlockForFrame, 1);
addFunction(vm, "printSourceFor", functionPrintSourceFor, 1);
@@ -1838,6 +1972,7 @@
addFunction(vm, "printBytecodeFor", functionPrintBytecodeFor, 1);
addFunction(vm, "print", functionPrint, 1);
+ addFunction(vm, "println", functionPrintln, 1);
addFunction(vm, "printCallFrame", functionPrintCallFrame, 0);
addFunction(vm, "printStack", functionPrintStack, 0);
@@ -1882,6 +2017,9 @@
addFunction(vm, "enableExceptionFuzz", functionEnableExceptionFuzz, 0);
+ addFunction(vm, "enableDebuggerModeWhenIdle", functionEnableDebuggerModeWhenIdle, 0);
+ addFunction(vm, "disableDebuggerModeWhenIdle", functionDisableDebuggerModeWhenIdle, 0);
+
addFunction(vm, "globalObjectCount", functionGlobalObjectCount, 0);
addFunction(vm, "globalObjectForObject", functionGlobalObjectForObject, 1);