source: webkit/trunk/JavaScriptCore/VM/ExceptionHelpers.cpp@ 37682

Last change on this file since 37682 was 37297, checked in by Darin Adler, 17 years ago

JavaScriptCore:

2008-10-04 Darin Adler <Darin Adler>

Reviewed by Cameron Zwarich.

10% faster on Richards; other v8 benchmarks faster too.
A wash on SunSpider.

This does the minimum necessary to get the speedup. Next step in
cleaning this up is to replace ExecState with a CallFrame class,
and be more judicious about when to pass a call frame and when
to pass a global data pointer, global object pointer, or perhaps
something else entirely.

  • VM/CTI.cpp: Remove the debug-only check of the exception in ctiVMThrowTrampoline -- already checked in the code the trampoline jumps to, so not all that useful. Removed the exec argument from ctiTrampoline. Removed emitDebugExceptionCheck -- no longer needed. (JSC::CTI::emitCall): Removed code to set ExecState::m_callFrame. (JSC::CTI::privateCompileMainPass): Removed code in catch to extract the exception from ExecState::m_exception; instead, the code that jumps into catch will make sure the exception is already in eax.
  • VM/CTI.h: Removed exec from the ctiTrampoline. Also removed the non-helpful "volatile". Temporarily left ARG_exec in as a synonym for ARG_r; I'll change that on a future cleanup pass when introducing more use of the CallFrame type. (JSC::CTI::execute): Removed the ExecState* argument.
  • VM/ExceptionHelpers.cpp: (JSC::InterruptedExecutionError::InterruptedExecutionError): Take JSGlobalData* instead of ExecState*. (JSC::createInterruptedExecutionException): Ditto.
  • VM/ExceptionHelpers.h: Ditto. Also removed an unneeded include.
  • VM/Machine.cpp: (JSC::slideRegisterWindowForCall): Removed the exec and exceptionValue arguments. Changed to return 0 when there's a stack overflow rather than using a separate exception argument to cut down on memory accesses in the calling convention. (JSC::Machine::unwindCallFrame): Removed the exec argument when constructing a DebuggerCallFrame. Also removed code to set ExecState::m_callFrame. (JSC::Machine::throwException): Removed the exec argument when construction a DebuggerCallFrame. (JSC::Machine::execute): Updated to use the register instead of ExecState and also removed various uses of ExecState. (JSC::Machine::debug): (JSC::Machine::privateExecute): Put globalData into a local variable so it can be used throughout the interpreter. Changed the VM_CHECK_EXCEPTION to get the exception in globalData instead of through ExecState. (JSC::Machine::retrieveLastCaller): Turn exec into a registers pointer by calling registers() instead of by getting m_callFrame. (JSC::Machine::callFrame): Ditto. Tweaked exception macros. Made new versions for when you know you have an exception. Get at global exception with ARG_globalData. Got rid of the need to pass in the return value type. (JSC::Machine::cti_op_add): Update to use new version of exception macros. (JSC::Machine::cti_op_pre_inc): Ditto. (JSC::Machine::cti_timeout_check): Ditto. (JSC::Machine::cti_op_instanceof): Ditto. (JSC::Machine::cti_op_new_func): Ditto. (JSC::Machine::cti_op_call_JSFunction): Optimized by using the ARG values directly instead of through local variables -- this gets rid of code that just shuffles things around in the stack frame. Also get rid of ExecState and update for the new way exceptions are handled in slideRegisterWindowForCall. (JSC::Machine::cti_vm_compile): Update to make exec out of r since they are both the same thing now. (JSC::Machine::cti_op_call_NotJSFunction): Ditto. (JSC::Machine::cti_op_init_arguments): Ditto. (JSC::Machine::cti_op_resolve): Ditto. (JSC::Machine::cti_op_construct_JSConstruct): Ditto. (JSC::Machine::cti_op_construct_NotJSConstruct): Ditto. (JSC::Machine::cti_op_resolve_func): Ditto. (JSC::Machine::cti_op_put_by_val): Ditto. (JSC::Machine::cti_op_put_by_val_array): Ditto. (JSC::Machine::cti_op_resolve_skip): Ditto. (JSC::Machine::cti_op_resolve_global): Ditto. (JSC::Machine::cti_op_post_inc): Ditto. (JSC::Machine::cti_op_resolve_with_base): Ditto. (JSC::Machine::cti_op_post_dec): Ditto. (JSC::Machine::cti_op_call_eval): Ditto. (JSC::Machine::cti_op_throw): Ditto. Also rearranged to return the exception value as the return value so it can be used by op_catch. (JSC::Machine::cti_op_push_scope): Ditto. (JSC::Machine::cti_op_in): Ditto. (JSC::Machine::cti_op_del_by_val): Ditto. (JSC::Machine::cti_vm_throw): Ditto. Also rearranged to return the exception value as the return value so it can be used by op_catch.
  • kjs/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::functionName): Pass globalData. (JSC::DebuggerCallFrame::evaluate): Eliminated code to make a new ExecState.
  • kjs/DebuggerCallFrame.h: Removed ExecState argument from constructor.
  • kjs/ExecState.h: Eliminated all data members and made ExecState inherit privately from Register instead. Also added a typedef to the future name for this class, which is CallFrame. It's just a Register* that knows it's a pointer at a call frame. The new class can't be constructed or copied. Changed all functions to use the this pointer instead of m_callFrame. Changed exception-related functions to access an exception in JSGlobalData. Removed functions used by CTI to pass the return address to the throw machinery -- this is now done directly with a global in the global data.
  • kjs/FunctionPrototype.cpp: (JSC::functionProtoFuncToString): Pass globalData instead of exec.
  • kjs/InternalFunction.cpp: (JSC::InternalFunction::name): Take globalData instead of exec.
  • kjs/InternalFunction.h: Ditto.
  • kjs/JSGlobalData.cpp: Initialize the new exception global to 0.
  • kjs/JSGlobalData.h: Declare two new globals. One for the current exception and another for the return address used by CTI to implement the throw operation.
  • kjs/JSGlobalObject.cpp: (JSC::JSGlobalObject::init): Removed code to set up globalExec, which is now the same thing as globalCallFrame. (JSC::JSGlobalObject::reset): Get globalExec from our globalExec function so we don't have to repeat the logic twice. (JSC::JSGlobalObject::mark): Removed code to mark the exception; the exception is now stored in JSGlobalData and marked there. (JSC::JSGlobalObject::globalExec): Return a pointer to the end of the global call frame.
  • kjs/JSGlobalObject.h: Removed the globalExec data member.
  • kjs/JSObject.cpp: (JSC::JSObject::putDirectFunction): Pass globalData instead of exec.
  • kjs/collector.cpp: (JSC::Heap::collect): Mark the global exception.
  • profiler/ProfileGenerator.cpp: (JSC::ProfileGenerator::addParentForConsoleStart): Pass globalData instead of exec to createCallIdentifier.
  • profiler/Profiler.cpp: (JSC::Profiler::willExecute): Pass globalData instead of exec to createCallIdentifier. (JSC::Profiler::didExecute): Ditto. (JSC::Profiler::createCallIdentifier): Take globalData instead of exec. (JSC::createCallIdentifierFromFunctionImp): Ditto.
  • profiler/Profiler.h: Change interface to take a JSGlobalData instead of an ExecState.

WebKit/mac:

2008-10-04 Darin Adler <Darin Adler>

Reviewed by Cameron Zwarich.

  • WebView/WebScriptDebugger.mm: (WebScriptDebugger::WebScriptDebugger): Remove 0 passed for ExecState.
File size: 10.9 KB
Line 
1/*
2 * Copyright (C) 2008 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 "ExecState.h"
34#include "JSObject.h"
35#include "JSNotAnObject.h"
36#include "Machine.h"
37#include "nodes.h"
38
39namespace JSC {
40
41static void substitute(UString& string, const UString& substring)
42{
43 int position = string.find("%s");
44 ASSERT(position != -1);
45 UString newString = string.substr(0, position);
46 newString.append(substring);
47 newString.append(string.substr(position + 2));
48 string = newString;
49}
50
51class InterruptedExecutionError : public JSObject {
52public:
53 InterruptedExecutionError(JSGlobalData* globalData)
54 : JSObject(globalData->nullProtoStructureID)
55 {
56 }
57
58 virtual bool isWatchdogException() const { return true; }
59};
60
61JSValue* createInterruptedExecutionException(JSGlobalData* globalData)
62{
63 return new (globalData) InterruptedExecutionError(globalData);
64}
65
66JSValue* createError(ExecState* exec, ErrorType e, const char* msg)
67{
68 return Error::create(exec, e, msg, -1, -1, 0);
69}
70
71JSValue* createError(ExecState* exec, ErrorType e, const char* msg, const Identifier& label)
72{
73 UString message = msg;
74 substitute(message, label.ustring());
75 return Error::create(exec, e, message, -1, -1, 0);
76}
77
78JSValue* createError(ExecState* exec, ErrorType e, const char* msg, JSValue* v)
79{
80 UString message = msg;
81 substitute(message, v->toString(exec));
82 return Error::create(exec, e, message, -1, -1, 0);
83}
84
85JSValue* createStackOverflowError(ExecState* exec)
86{
87 return createError(exec, RangeError, "Maximum call stack size exceeded.");
88}
89
90JSValue* createUndefinedVariableError(ExecState* exec, const Identifier& ident, const Instruction* vPC, CodeBlock* codeBlock)
91{
92 int startOffset = 0;
93 int endOffset = 0;
94 int divotPoint = 0;
95 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
96 UString message = "Can't find variable: ";
97 message.append(ident.ustring());
98 JSObject* exception = Error::create(exec, ReferenceError, message, line, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->sourceURL());
99 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
100 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
101 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
102 return exception;
103}
104
105bool isStrWhiteSpace(UChar c);
106
107static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue* value, UString error)
108{
109 if (!expressionStop || expressionStart > codeBlock->source->length()) {
110 UString errorText = value->toString(exec);
111 errorText.append(" is ");
112 errorText.append(error);
113 return errorText;
114 }
115
116 UString errorText = "Result of expression ";
117
118 if (expressionStart < expressionStop) {
119 errorText.append('\'');
120 errorText.append(codeBlock->source->getRange(expressionStart, expressionStop));
121 errorText.append("' [");
122 errorText.append(value->toString(exec));
123 errorText.append("] is ");
124 } else {
125 // No range information, so give a few characters of context
126 const UChar* data = codeBlock->source->data();
127 int dataLength = codeBlock->source->length();
128 int start = expressionStart;
129 int stop = expressionStart;
130 // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
131 // then strip whitespace.
132 while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
133 start--;
134 while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
135 start++;
136 while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
137 stop++;
138 while (stop > expressionStart && isStrWhiteSpace(data[stop]))
139 stop--;
140 errorText.append("near '...");
141 errorText.append(codeBlock->source->getRange(start, stop));
142 errorText.append("...' [");
143 errorText.append(value->toString(exec));
144 errorText.append("] is ");
145 }
146 errorText.append(error);
147 errorText.append(".");
148 return errorText;
149}
150
151JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue* value, const Instruction* vPC, CodeBlock* codeBlock)
152{
153 UString message = "not a valid argument for '";
154 message.append(op);
155 message.append("'");
156
157 int startOffset = 0;
158 int endOffset = 0;
159 int divotPoint = 0;
160 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
161 UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, message);
162 JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->sourceURL());
163 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
164 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
165 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
166 return exception;
167}
168
169JSObject* createNotAConstructorError(ExecState* exec, JSValue* value, const Instruction* vPC, CodeBlock* codeBlock)
170{
171 int startOffset = 0;
172 int endOffset = 0;
173 int divotPoint = 0;
174 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
175
176 // We're in a "new" expression, so we need to skip over the "new.." part
177 int startPoint = divotPoint - (startOffset ? startOffset - 4 : 0); // -4 for "new "
178 const UChar* data = codeBlock->source->data();
179 while (startPoint < divotPoint && isStrWhiteSpace(data[startPoint]))
180 startPoint++;
181
182 UString errorMessage = createErrorMessage(exec, codeBlock, line, startPoint, divotPoint, value, "not a constructor");
183 JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->sourceURL());
184 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
185 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
186 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
187 return exception;
188}
189
190JSValue* createNotAFunctionError(ExecState* exec, JSValue* value, const Instruction* vPC, CodeBlock* codeBlock)
191{
192 int startOffset = 0;
193 int endOffset = 0;
194 int divotPoint = 0;
195 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
196 UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, value, "not a function");
197 JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->sourceURL());
198 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
199 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
200 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
201 return exception;
202}
203
204JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState* exec, bool isNull)
205{
206 return new (exec) JSNotAnObjectErrorStub(exec, isNull);
207}
208
209JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, const Instruction* vPC, CodeBlock* codeBlock)
210{
211 if (vPC[8].u.opcode == exec->machine()->getOpcode(op_instanceof))
212 return createInvalidParamError(exec, "instanceof", error->isNull() ? jsNull() : jsUndefined(), vPC, codeBlock);
213 if (vPC[8].u.opcode == exec->machine()->getOpcode(op_construct))
214 return createNotAConstructorError(exec, error->isNull() ? jsNull() : jsUndefined(), vPC, codeBlock);
215
216 int startOffset = 0;
217 int endOffset = 0;
218 int divotPoint = 0;
219 int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
220 UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, error->isNull() ? jsNull() : jsUndefined(), "not an object");
221 JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode->sourceID(), codeBlock->ownerNode->sourceURL());
222 exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
223 exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
224 exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
225 return exception;
226}
227
228} // namespace JSC
Note: See TracBrowser for help on using the repository browser.