summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/interpreter')
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.cpp35
-rw-r--r--Source/JavaScriptCore/interpreter/VMInspector.cpp463
-rw-r--r--Source/JavaScriptCore/interpreter/VMInspector.h47
3 files changed, 525 insertions, 20 deletions
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index 0d475b416..397ac8474 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -100,9 +100,9 @@ Interpreter::ErrorHandlingMode::~ErrorHandlingMode()
// The Interpreter::StackPolicy class is used to compute a stack capacity
// requirement to ensure that we have enough room on the native stack for:
-// 1. the max cummulative stack used by the interpreter and all code
+// 1. the max cumulative stack used by the interpreter and all code
// paths sub of it up till leaf functions.
-// 2. the max cummulative stack used by the interpreter before it reaches
+// 2. the max cumulative stack used by the interpreter before it reaches
// the next checkpoint (execute...() function) in the interpreter.
//
// The interpreter can be run on different threads and hence, different
@@ -116,11 +116,11 @@ Interpreter::ErrorHandlingMode::~ErrorHandlingMode()
Interpreter::StackPolicy::StackPolicy(Interpreter& interpreter, const StackBounds& stack)
: m_interpreter(interpreter)
{
- int size = stack.size();
+ const size_t size = stack.size();
- const int DEFAULT_REQUIRED_STACK = 1024 * 1024;
- const int DEFAULT_MINIMUM_USEABLE_STACK = 128 * 1024;
- const int DEFAULT_ERROR_MODE_REQUIRED_STACK = 32 * 1024;
+ const size_t DEFAULT_REQUIRED_STACK = 1024 * 1024;
+ const size_t DEFAULT_MINIMUM_USEABLE_STACK = 128 * 1024;
+ const size_t DEFAULT_ERROR_MODE_REQUIRED_STACK = 32 * 1024;
// Here's the policy in a nutshell:
//
@@ -152,7 +152,7 @@ Interpreter::StackPolicy::StackPolicy(Interpreter& interpreter, const StackBound
// ^ ^
// start current sp
//
- // This smaller requried capacity also means that we won't re-trigger
+ // This smaller required capacity also means that we won't re-trigger
// a stack overflow for processing the exception caused by the original
// StackOverflowError.
//
@@ -169,15 +169,16 @@ Interpreter::StackPolicy::StackPolicy(Interpreter& interpreter, const StackBound
// The minimum useable capacity is DEFAULT_MINIMUM_USEABLE_STACK.
// In this case, the requiredCapacity is whatever is left of the
// total stack capacity after we have give JS its minimum stack
- // i.e. requiredCapcity can even be 0 if there's not enough stack.
+ // i.e. requiredCapacity can even be 0 if there's not enough stack.
// Policy 1: Normal mode: required = DEFAULT_REQUIRED_STACK.
- // Policy 2: Erro mode: required = DEFAULT_ERROR_MODE_REQUIRED_STACK.
- int requiredCapacity = !m_interpreter.m_errorHandlingModeReentry ?
+ // Policy 2: Error mode: required = DEFAULT_ERROR_MODE_REQUIRED_STACK.
+ size_t requiredCapacity = !m_interpreter.m_errorHandlingModeReentry ?
DEFAULT_REQUIRED_STACK : DEFAULT_ERROR_MODE_REQUIRED_STACK;
- int useableStack = size - requiredCapacity;
+ size_t useableStack = (requiredCapacity <= size) ?
+ size - requiredCapacity : DEFAULT_MINIMUM_USEABLE_STACK;
// Policy 3: Ensure the useable stack is not too small:
if (useableStack < DEFAULT_MINIMUM_USEABLE_STACK)
@@ -190,9 +191,8 @@ Interpreter::StackPolicy::StackPolicy(Interpreter& interpreter, const StackBound
// Re-compute the requiredCapacity based on the adjusted useable stack
// size:
- // interpreter stack checks:
requiredCapacity = size - useableStack;
- ASSERT((requiredCapacity >= 0) && (requiredCapacity < size));
+ ASSERT(requiredCapacity < size);
m_requiredCapacity = requiredCapacity;
}
@@ -948,10 +948,13 @@ failedJSONP:
// object.
// Compile source to bytecode if necessary:
- JSObject* error = program->compile(callFrame, scope);
- if (error)
+ if (JSObject* error = program->initalizeGlobalProperties(globalData, callFrame, scope))
return checkedReturn(throwError(callFrame, error));
- CodeBlock* codeBlock = &program->generatedBytecode();
+
+ if (JSObject* error = program->compile(callFrame, scope))
+ return checkedReturn(throwError(callFrame, error));
+
+ ProgramCodeBlock* codeBlock = &program->generatedBytecode();
// Push the call frame for this invocation:
ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
diff --git a/Source/JavaScriptCore/interpreter/VMInspector.cpp b/Source/JavaScriptCore/interpreter/VMInspector.cpp
index 566d4e8e0..58bc15075 100644
--- a/Source/JavaScriptCore/interpreter/VMInspector.cpp
+++ b/Source/JavaScriptCore/interpreter/VMInspector.cpp
@@ -28,6 +28,10 @@
#if ENABLE(VMINSPECTOR)
+#include <stdio.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/text/WTFString.h>
+
namespace JSC {
const char* VMInspector::getTypeName(JSValue value)
@@ -105,6 +109,465 @@ int VMInspector::countFrames(CallFrame* frame)
return count;
}
+
+//============================================================================
+// class FormatPrinter
+// - implements functionality to support fprintf.
+//
+// The FormatPrinter classes do the real formatting and printing.
+// By default, the superclass FormatPrinter will print to stdout (printf).
+// Each of the subclass will implement the other ...printf() options.
+// The subclasses are:
+//
+// FileFormatPrinter - fprintf
+// StringFormatPrinter - sprintf
+// StringNFormatPrinter - snprintf
+
+class FormatPrinter {
+public:
+ virtual ~FormatPrinter() { }
+
+ void print(const char* format, va_list args);
+
+protected:
+ // Low level printers:
+ bool printArg(const char* format, ...);
+ virtual bool printArg(const char* format, va_list args);
+
+ // JS type specific printers:
+ void printWTFString(va_list args, bool verbose);
+};
+
+
+// The public print() function is the real workhorse behind the printf
+// family of functions. print() deciphers the % formatting, translate them
+// to primitive formats, and dispatches to underlying printArg() functions
+// to do the printing.
+//
+// The non-public internal printArg() function is virtual and is responsible
+// for handling the variations between printf, fprintf, sprintf, and snprintf.
+
+void FormatPrinter::print(const char* format, va_list args)
+{
+ const char* p = format;
+ const char* errorStr;
+
+ // buffer is only used for 2 purposes:
+ // 1. To temporarily hold a copy of normal chars (not needing formatting)
+ // to be passed to printArg() and printed.
+ //
+ // The incoming format string may contain a string of normal chars much
+ // longer than 128, but we handle this by breaking them out to 128 chars
+ // fragments and printing each fragment before re-using the buffer to
+ // load up the next fragment.
+ //
+ // 2. To hold a single "%..." format to be passed to printArg() to process
+ // a single va_arg.
+
+ char buffer[129]; // 128 chars + null terminator.
+ char* end = &buffer[sizeof(buffer) - 1];
+ const char* startOfFormatSpecifier = 0;
+
+ while (true) {
+ char c = *p++;
+ char* curr = buffer;
+
+ // Print leading normal chars:
+ while (c != '\0' && c != '%') {
+ *curr++ = c;
+ if (curr == end) {
+ // Out of buffer space. Flush the fragment, and start over.
+ *curr = '\0';
+ bool success = printArg("%s", buffer);
+ if (!success) {
+ errorStr = buffer;
+ goto handleError;
+ }
+ curr = buffer;
+ }
+ c = *p++;
+ }
+ // If we have stuff in the buffer, flush the fragment:
+ if (curr != buffer) {
+ ASSERT(curr < end + 1);
+ *curr = '\0';
+ bool success = printArg("%s", buffer);
+ if (!success) {
+ errorStr = buffer;
+ goto handleError;
+ }
+ }
+
+ // End if there are not more chars to print:
+ if (c == '\0')
+ break;
+
+ // If we get here, we've must have seen a '%':
+ startOfFormatSpecifier = p - 1;
+ ASSERT(*startOfFormatSpecifier == '%');
+ c = *p++;
+
+ // Check for "%%" case:
+ if (c == '%') {
+ bool success = printArg("%c", '%');
+ if (!success) {
+ errorStr = p - 2;
+ goto handleError;
+ }
+ continue;
+ }
+
+ // Check for JS (%J<x>) formatting extensions:
+ if (c == 'J') {
+ bool verbose = false;
+
+ c = *p++;
+ if (UNLIKELY(c == '\0')) {
+ errorStr = p - 2; // Rewind to % in "%J\0"
+ goto handleError;
+ }
+
+ if (c == '+') {
+ verbose = true;
+ c= *p++;
+ if (UNLIKELY(c == '\0')) {
+ errorStr = p - 3; // Rewind to % in "%J+\0"
+ goto handleError;
+ }
+ }
+
+ switch (c) {
+ // %Js - WTF::String*
+ case 's': {
+ printWTFString(args, verbose);
+ continue;
+ }
+ } // END switch.
+
+ // Check for non-JS extensions:
+ } else if (c == 'b') {
+ int value = va_arg(args, int);
+ printArg("%s", value ? "TRUE" : "FALSE");
+ continue;
+ }
+
+ // If we didn't handle the format in one of the above cases,
+ // rewind p and let the standard formatting check handle it
+ // if possible:
+ p = startOfFormatSpecifier;
+ ASSERT(*p == '%');
+
+ // Check for standard formatting:
+ // A format specifier always starts with a % and ends with some
+ // alphabet. We'll do the simple thing and scan until the next
+ // alphabet, or the end of string.
+
+ // In the following, we're going to use buffer as storage for a copy
+ // of a single format specifier. Hence, conceptually, we can think of
+ // 'buffer' as synonymous with 'argFormat' here:
+
+#define ABORT_IF_FORMAT_TOO_LONG(curr) \
+ do { \
+ if (UNLIKELY(curr >= end)) \
+ goto formatTooLong; \
+ } while (false)
+
+ curr = buffer;
+ *curr++ = *p++; // Output the first % in the format specifier.
+ c = *p++; // Grab the next char in the format specifier.
+
+ // Checks for leading modifiers e.g. "%-d":
+ // 0, -, ' ', +, '\''
+ if (c == '0' || c == '-' || c == ' ' || c == '+' || c == '\'' || c == '#') {
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr++ = c;
+ c = *p++;
+ }
+
+ // Checks for decimal digit field width modifiers e.g. "%2f":
+ while (c >= '0' && c <= '9') {
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr++ = c;
+ c = *p++;
+ }
+
+ // Checks for '.' e.g. "%2.f":
+ if (c == '.') {
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr++ = c;
+ c = *p++;
+
+ // Checks for decimal digit precision modifiers e.g. "%.2f":
+ while (c >= '0' && c <= '9') {
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr++ = c;
+ c = *p++;
+ }
+ }
+
+ // Checks for the modifier <m> where <m> can be:
+ // l, h, j, t, z
+ // e.g. "%ld"
+ if (c == 'l' || c == 'h' || c == 'j' || c == 't' || c == 'z' || c == 'L') {
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr++ = c;
+ char prevChar = c;
+ c = *p++;
+
+ // Checks for the modifier ll or hh in %<x><m>:
+ if ((prevChar == 'l' || prevChar == 'h') && c == prevChar) {
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr++ = c;
+ c = *p++;
+ }
+ }
+
+ // Checks for %<x> where <x> can be:
+ // d, i, n, o, u, x, X
+ // But hey, we're just going to do the simple thing and allow any
+ // alphabet. The user is expected to pass correct format specifiers.
+ // We won't do any format checking here. We'll just pass it on, and the
+ // underlying ...printf() implementation may do the needed checking
+ // at its discretion.
+ while (c != '\0' && !isASCIIAlpha(c)) {
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr++ = c;
+ c = *p++;
+ }
+
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr++ = c;
+ if (c == '\0') {
+ // Uh oh. Bad format. We should have gotten an alphabet instead.
+ // Print the supposed format as a string instead:
+ errorStr = buffer;
+ goto handleError;
+ }
+
+ // Otherwise, we have the alpha that terminates the format.
+ // Terminate the buffer (i.e. argFormat) string:
+ ASSERT(isASCIIAlpha(c));
+ ABORT_IF_FORMAT_TOO_LONG(curr);
+ *curr = '\0';
+
+ bool success = printArg(buffer, args);
+ if (!success) {
+ errorStr = buffer;
+ goto handleError;
+ }
+ }
+#undef ABORT_IF_FORMAT_TOO_LONG
+
+ return;
+
+formatTooLong:
+ // Print the error string:
+ ASSERT(!!startOfFormatSpecifier);
+ p = startOfFormatSpecifier;
+ ASSERT(p >= format);
+ printArg("ERROR @ Format too long at \"%s\"\n", p);
+ return;
+
+handleError:
+ // We've got an error. Can't do any more work. Print an error message if
+ // possible and then just return.
+
+ // The errorStr may be pointing into the middle of buffer, or the original
+ // format string. Move the string to buffer for consistency, and also so
+ // that we can strip it of newlines below.
+ if (errorStr != buffer) {
+ size_t length = strlen(errorStr);
+ if (length > sizeof(buffer) - 1)
+ length = sizeof(buffer) - 1;
+ memmove(buffer, errorStr, length);
+ buffer[length] = '\0'; // Terminate the moved error string.
+ }
+ // Strip the newlines:
+ char* cp = buffer;
+ while (*cp) {
+ if (*cp == '\n' || *cp == '\r')
+ *cp = ' ';
+ cp++;
+ }
+ // Print the error string:
+ printArg("ERROR @ \"%s\"\n", buffer);
+}
+
+
+bool FormatPrinter::printArg(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ bool success = printArg(format, args);
+ va_end(args);
+ return success;
+}
+
+bool FormatPrinter::printArg(const char* format, va_list args)
+{
+ int count = ::vprintf(format, args);
+ return (count >= 0); // Fail if less than 0 chars printed.
+}
+
+
+// %Js - WTF::String*
+// verbose mode prints: WTF::String "<your string>"
+void FormatPrinter::printWTFString(va_list args, bool verbose)
+{
+ const String* str = va_arg(args, const String*);
+
+ // Print verbose header if appropriate:
+ if (verbose)
+ printArg("WTF::String \"");
+
+ // Print the string itself:
+ if (!str->isEmpty()) {
+ if (str->is8Bit()) {
+ const LChar* chars = str->characters8();
+ printArg("%s", reinterpret_cast<const char*>(chars));
+ } else {
+ const UChar* chars = str->characters16();
+ printArg("%S", reinterpret_cast<const wchar_t*>(chars));
+ }
+ }
+
+ // Print verbose footer if appropriate:
+ if (verbose)
+ printArg("\"");
+}
+
+
+//============================================================================
+// class FileFormatPrinter
+// - implements functionality to support fprintf.
+
+class FileFormatPrinter: public FormatPrinter {
+public:
+ FileFormatPrinter(FILE*);
+private:
+ virtual bool printArg(const char* format, va_list args);
+
+ FILE* m_file;
+};
+
+FileFormatPrinter::FileFormatPrinter(FILE* file)
+ : m_file(file)
+{
+}
+
+bool FileFormatPrinter::printArg(const char* format, va_list args)
+{
+ int count = ::vfprintf(m_file, format, args);
+ return (count >= 0); // Fail if less than 0 chars printed.
+}
+
+
+//============================================================================
+// class StringFormatPrinter
+// - implements functionality to support sprintf.
+
+class StringFormatPrinter: public FormatPrinter {
+public:
+ StringFormatPrinter(char* buffer);
+private:
+ virtual bool printArg(const char* format, va_list args);
+
+ char* m_buffer;
+};
+
+StringFormatPrinter::StringFormatPrinter(char* buffer)
+ : m_buffer(buffer)
+{
+}
+
+bool StringFormatPrinter::printArg(const char* format, va_list args)
+{
+ int count = ::vsprintf(m_buffer, format, args);
+ m_buffer += count;
+ return (count >= 0); // Fail if less than 0 chars printed.
+}
+
+
+//============================================================================
+// class StringNFormatPrinter
+// - implements functionality to support snprintf.
+
+class StringNFormatPrinter: public FormatPrinter {
+public:
+ StringNFormatPrinter(char* buffer, size_t);
+private:
+ virtual bool printArg(const char* format, va_list args);
+
+ char* m_buffer;
+ size_t m_size;
+};
+
+
+StringNFormatPrinter::StringNFormatPrinter(char* buffer, size_t size)
+ : m_buffer(buffer)
+ , m_size(size)
+{
+}
+
+bool StringNFormatPrinter::printArg(const char* format, va_list args)
+{
+ if (m_size > 0) {
+ int count = ::vsnprintf(m_buffer, m_size, format, args);
+
+ // According to vsnprintf specs, ...
+ bool success = (count >= 0);
+ if (static_cast<size_t>(count) >= m_size) {
+ // If count > size, then we didn't have enough buffer space.
+ count = m_size;
+ }
+
+ // Adjust the buffer to what's left if appropriate:
+ if (success) {
+ m_buffer += count;
+ m_size -= count;
+ }
+ return success;
+ }
+ // No more room to print. Declare it a fail:
+ return false;
+}
+
+
+//============================================================================
+// VMInspector printf family of methods:
+
+void VMInspector::fprintf(FILE* file, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ FileFormatPrinter(file).print(format, args);
+ va_end(args);
+}
+
+void VMInspector::printf(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ FormatPrinter().print(format, args);
+ va_end(args);
+}
+
+void VMInspector::sprintf(char* buffer, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ StringFormatPrinter(buffer).print(format, args);
+ va_end(args);
+}
+
+void VMInspector::snprintf(char* buffer, size_t size, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ StringNFormatPrinter(buffer, size).print(format, args);
+ va_end(args);
+}
+
} // namespace JSC
#endif // ENABLE(VMINSPECTOR)
diff --git a/Source/JavaScriptCore/interpreter/VMInspector.h b/Source/JavaScriptCore/interpreter/VMInspector.h
index 6806cafa1..81ca26c6f 100644
--- a/Source/JavaScriptCore/interpreter/VMInspector.h
+++ b/Source/JavaScriptCore/interpreter/VMInspector.h
@@ -28,23 +28,62 @@
#define ENABLE_VMINSPECTOR 0
-#if ENABLE(VMINSPECTOR)
-
#include "CallFrame.h"
#include "JSValue.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <wtf/text/WTFString.h>
namespace JSC {
+#if ENABLE(VMINSPECTOR)
+
class VMInspector {
public:
static JS_EXPORT_PRIVATE const char* getTypeName(JSValue);
static JS_EXPORT_PRIVATE void dumpFrame0(CallFrame*);
static JS_EXPORT_PRIVATE void dumpFrame(CallFrame*, const char* prefix = 0, const char* funcName = 0, const char* file = 0, int line = -1);
static JS_EXPORT_PRIVATE int countFrames(CallFrame*);
-};
-} // namespace JSC
+ // Special family of ...printf() functions that support, in addition to the
+ // standard % formats (e.g. %d, %s, etc), the following extra JSC formatting
+ // options, %J<x>, where <x> consists of:
+ //
+ // + - verbose mode modifier.
+ // Used in combination with other options. Must come after the %J.
+ // s - WTF::String*
+ //
+ // Examples of usage:
+ //
+ // WTF::String str("My WTF String");
+ //
+ // // Printing the string. Will print:
+ // // The wtf string says: "My WTF String" and is NOT EMPTY.
+ //
+ // VMInspector::printf("The wtf string says: \"%Js\" and is %s\n",
+ // &str, str.isEmpty()?"EMPTY":"NOT EMPTY");
+ //
+ // // Printing the string with verbose mode. Will print:
+ // // <WTF::String "My WTF String">
+ //
+ // VMInspector::printf("<%J+s>\n", &str);
+ //
+ // Also added some convenience non-JS formats:
+ //
+ // %b - boolean (va_args will look for an int).
+ // Prints TRUE if non-zero, else prints FALSE.
+ //
+ // Caution: the user is expected to pass the correctly matched arguments
+ // to pair with the corresponding % fomatting.
+
+ static JS_EXPORT_PRIVATE void fprintf(FILE*, const char* format, ...);
+ static JS_EXPORT_PRIVATE void printf(const char* format, ...);
+ static JS_EXPORT_PRIVATE void sprintf(char*, const char* format, ...);
+ static JS_EXPORT_PRIVATE void snprintf(char*, size_t, const char* format, ...);
+};
#endif // ENABLE(VMINSPECTOR)
+} // namespace JSC
+
#endif // VMInspector.h