source: webkit/trunk/JavaScriptCore/runtime/ExceptionHelpers.cpp@ 52956

Last change on this file since 52956 was 52028, checked in by [email protected], 15 years ago

https://bugs.webkit.org/show_bug.cgi?id=32454
Refactor construction of simple strings to avoid string concatenation.

Reviewed by Oliver Hunt.

Building strings through concatenation has a memory and performance cost -
a memory cost since we must over-allocate the buffer to leave space to append
into, and performance in that the string may still require reallocation (and
thus copying during construction). Instead move the full construction to
within a single function call (makeString), so that the arguments' lengths
can be calculated and an appropriate sized buffer allocated before copying
any characters.

~No performance change (~2% progression on date tests).

  • bytecode/CodeBlock.cpp:

(JSC::escapeQuotes):
(JSC::valueToSourceString):
(JSC::constantName):
(JSC::idName):
(JSC::CodeBlock::registerName):
(JSC::regexpToSourceString):
(JSC::regexpName):

  • bytecompiler/NodesCodegen.cpp:

(JSC::substitute):

  • profiler/Profiler.cpp:

(JSC::Profiler::createCallIdentifier):

  • runtime/DateConstructor.cpp:

(JSC::callDate):

  • runtime/DateConversion.cpp:

(JSC::formatDate):
(JSC::formatDateUTCVariant):
(JSC::formatTime):
(JSC::formatTimeUTC):

  • runtime/DateConversion.h:

(JSC::):

  • runtime/DatePrototype.cpp:

(JSC::dateProtoFuncToString):
(JSC::dateProtoFuncToUTCString):
(JSC::dateProtoFuncToDateString):
(JSC::dateProtoFuncToTimeString):
(JSC::dateProtoFuncToGMTString):

  • runtime/ErrorPrototype.cpp:

(JSC::errorProtoFuncToString):

  • runtime/ExceptionHelpers.cpp:

(JSC::createUndefinedVariableError):
(JSC::createErrorMessage):
(JSC::createInvalidParamError):

  • runtime/FunctionPrototype.cpp:

(JSC::insertSemicolonIfNeeded):
(JSC::functionProtoFuncToString):

  • runtime/ObjectPrototype.cpp:

(JSC::objectProtoFuncToString):

  • runtime/RegExpConstructor.cpp:

(JSC::constructRegExp):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::match):

  • runtime/RegExpPrototype.cpp:

(JSC::regExpProtoFuncCompile):
(JSC::regExpProtoFuncToString):

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncBig):
(JSC::stringProtoFuncSmall):
(JSC::stringProtoFuncBlink):
(JSC::stringProtoFuncBold):
(JSC::stringProtoFuncFixed):
(JSC::stringProtoFuncItalics):
(JSC::stringProtoFuncStrike):
(JSC::stringProtoFuncSub):
(JSC::stringProtoFuncSup):
(JSC::stringProtoFuncFontcolor):
(JSC::stringProtoFuncFontsize):
(JSC::stringProtoFuncAnchor):

  • runtime/UString.h:

(JSC::):
(JSC::makeString):

File size: 10.5 KB
Line 
1/*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "ExceptionHelpers.h"
31
32#include "CodeBlock.h"
33#include "CallFrame.h"
34#include "JSGlobalObjectFunctions.h"
35#include "JSObject.h"
36#include "JSNotAnObject.h"
37#include "Interpreter.h"
38#include "Nodes.h"
39
40namespace JSC {
41
42class InterruptedExecutionError : public JSObject {
43public:
44 InterruptedExecutionError(JSGlobalData* globalData)
45 : JSObject(globalData->interruptedExecutionErrorStructure)
46 {
47 }
48
49 virtual bool isWatchdogException() const { return true; }
50
51 virtual UString toString(ExecState*) const { return "JavaScript execution exceeded timeout."; }
52};
53
54JSValue createInterruptedExecutionException(JSGlobalData* globalData)
55{
56 return new (globalData) InterruptedExecutionError(globalData);
57}
58
59static JSValue createError(ExecState* exec, ErrorType e, const char* msg)
60{
61 return Error::create(exec, e, msg, -1, -1, 0);
62}
63
64JSValue createStackOverflowError(ExecState* exec)
65{
66 return createError(exec, RangeError, "Maximum call stack size exceeded.");
67}
68
69JSValue createTypeError(ExecState* exec, const char* message)
70{
71 return createError(exec, TypeError, message);
72}
73
74JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock)
75{
76 int startOffset = 0;
77 int endOffset = 0;
78 int divotPoint = 0;
79 int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
80 JSObject* exception = Error::create(exec, ReferenceError, makeString("Can't find variable: ", ident.ustring()), line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
81 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
82 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
83 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
84 return exception;
85}
86
87static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue value, UString error)
88{
89 if (!expressionStop || expressionStart > codeBlock->source()->length())
90 return makeString(value.toString(exec), " is ", error);
91 if (expressionStart < expressionStop)
92 return makeString("Result of expression '", codeBlock->source()->getRange(expressionStart, expressionStop), "' [", value.toString(exec), "] is ", error, ".");
93
94 // No range information, so give a few characters of context
95 const UChar* data = codeBlock->source()->data();
96 int dataLength = codeBlock->source()->length();
97 int start = expressionStart;
98 int stop = expressionStart;
99 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
100 // then strip whitespace.
101 while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
102 start--;
103 while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
104 start++;
105 while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
106 stop++;
107 while (stop > expressionStart && isStrWhiteSpace(data[stop]))
108 stop--;
109 return makeString("Result of expression near '...", codeBlock->source()->getRange(start, stop), "...' [", value.toString(exec), "] is ", error, ".");
110}
111
112JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock)
113{
114 int startOffset = 0;
115 int endOffset = 0;
116 int divotPoint = 0;
117 int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
118 UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, makeString("not a valid argument for '", op, "'"));
119 JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
120 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
121 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
122 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
123 return exception;
124}
125
126JSObject* createNotAConstructorError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock)
127{
128 int startOffset = 0;
129 int endOffset = 0;
130 int divotPoint = 0;
131 int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
132
133 // We're in a "new" expression, so we need to skip over the "new.." part
134 int startPoint = divotPoint - (startOffset ? startOffset - 4 : 0); // -4 for "new "
135 const UChar* data = codeBlock->source()->data();
136 while (startPoint < divotPoint && isStrWhiteSpace(data[startPoint]))
137 startPoint++;
138
139 UString errorMessage = createErrorMessage(exec, codeBlock, line, startPoint, divotPoint, value, "not a constructor");
140 JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
141 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
142 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
143 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
144 return exception;
145}
146
147JSValue createNotAFunctionError(ExecState* exec, JSValue value, unsigned bytecodeOffset, CodeBlock* codeBlock)
148{
149 int startOffset = 0;
150 int endOffset = 0;
151 int divotPoint = 0;
152 int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
153 UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, value, "not a function");
154 JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
155 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
156 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
157 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
158 return exception;
159}
160
161JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState* exec, bool isNull)
162{
163 return new (exec) JSNotAnObjectErrorStub(exec, isNull);
164}
165
166JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, unsigned bytecodeOffset, CodeBlock* codeBlock)
167{
168 // Both op_construct and op_instanceof require a use of op_get_by_id to get
169 // the prototype property from an object. The exception messages for exceptions
170 // thrown by these instances op_get_by_id need to reflect this.
171 OpcodeID followingOpcodeID;
172 if (codeBlock->getByIdExceptionInfoForBytecodeOffset(exec, bytecodeOffset, followingOpcodeID)) {
173 ASSERT(followingOpcodeID == op_construct || followingOpcodeID == op_instanceof);
174 if (followingOpcodeID == op_construct)
175 return createNotAConstructorError(exec, error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock);
176 return createInvalidParamError(exec, "instanceof", error->isNull() ? jsNull() : jsUndefined(), bytecodeOffset, codeBlock);
177 }
178
179 int startOffset = 0;
180 int endOffset = 0;
181 int divotPoint = 0;
182 int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset);
183 UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, error->isNull() ? jsNull() : jsUndefined(), "not an object");
184 JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
185 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
186 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
187 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
188 return exception;
189}
190
191} // namespace JSC
Note: See TracBrowser for help on using the repository browser.