source: webkit/trunk/JavaScriptCore/runtime/Executable.h@ 61623

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

2010-06-21 Oliver Hunt <[email protected]>

Reviewed by Geoffrey Garen.

Make JSC more resilient in the face of parse failures
https://bugs.webkit.org/show_bug.cgi?id=40951

A number of recent bugs have occurred due to issues like miscounting
BOMs, etc which lead to interesting crashes later on. Adding this
logic hardens JSC in the face of these errors, and has no impact on
performance (32bit jit actually gets 0.7% faster but I put that down
to cache effects).

  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::reparseForExceptionInfoIfNecessary): (JSC::CodeBlock::lineNumberForBytecodeOffset): (JSC::CodeBlock::expressionRangeForBytecodeOffset): (JSC::CodeBlock::getByIdExceptionInfoForBytecodeOffset):
  • bytecode/CodeBlock.h: (JSC::CodeBlock::bytecodeOffset):
  • interpreter/Interpreter.cpp: (JSC::Interpreter::execute): (JSC::Interpreter::executeCall): (JSC::Interpreter::executeConstruct): (JSC::Interpreter::prepareForRepeatCall): (JSC::Interpreter::privateExecute):
  • jit/JITOpcodes.cpp: (JSC::JIT::privateCompileCTIMachineTrampolines):
  • jit/JITOpcodes32_64.cpp: (JSC::JIT::privateCompileCTIMachineTrampolines):
  • jit/JITStubs.cpp: (JSC::DEFINE_STUB_FUNCTION):
  • runtime/ArrayPrototype.cpp: (JSC::isNumericCompareFunction):
  • runtime/Executable.cpp: (JSC::FunctionExecutable::compileForCall): (JSC::FunctionExecutable::compileForConstruct): (JSC::FunctionExecutable::generateJITCodeForCall): (JSC::FunctionExecutable::generateJITCodeForConstruct): (JSC::FunctionExecutable::reparseExceptionInfo): (JSC::EvalExecutable::reparseExceptionInfo):
  • runtime/Executable.h: (JSC::FunctionExecutable::bytecodeForCall): (JSC::FunctionExecutable::bytecodeForConstruct):
  • runtime/JSGlobalData.cpp: (JSC::JSGlobalData::numericCompareFunction):
File size: 15.4 KB
Line 
1/*
2 * Copyright (C) 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 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef Executable_h
27#define Executable_h
28
29#include "CallData.h"
30#include "JSFunction.h"
31#include "Interpreter.h"
32#include "Nodes.h"
33#include "SamplingTool.h"
34
35namespace JSC {
36
37 class CodeBlock;
38 class Debugger;
39 class EvalCodeBlock;
40 class FunctionCodeBlock;
41 class ProgramCodeBlock;
42 class ScopeChainNode;
43
44 struct ExceptionInfo;
45
46 class ExecutableBase : public RefCounted<ExecutableBase> {
47 friend class JIT;
48
49 protected:
50 static const int NUM_PARAMETERS_IS_HOST = 0;
51 static const int NUM_PARAMETERS_NOT_COMPILED = -1;
52
53 public:
54 ExecutableBase(int numParameters)
55 : m_numParametersForCall(numParameters)
56 , m_numParametersForConstruct(numParameters)
57 {
58 }
59
60 virtual ~ExecutableBase() {}
61
62 bool isHostFunction() const
63 {
64 ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
65 return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
66 }
67
68 protected:
69 int m_numParametersForCall;
70 int m_numParametersForConstruct;
71
72#if ENABLE(JIT)
73 public:
74 JITCode& generatedJITCodeForCall()
75 {
76 ASSERT(m_jitCodeForCall);
77 return m_jitCodeForCall;
78 }
79
80 JITCode& generatedJITCodeForConstruct()
81 {
82 ASSERT(m_jitCodeForConstruct);
83 return m_jitCodeForConstruct;
84 }
85
86 protected:
87 JITCode m_jitCodeForCall;
88 JITCode m_jitCodeForConstruct;
89 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
90 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
91#endif
92 };
93
94#if ENABLE(JIT)
95 class NativeExecutable : public ExecutableBase {
96 friend class JIT;
97 public:
98 static PassRefPtr<NativeExecutable> create(MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor)
99 {
100 return adoptRef(new NativeExecutable(JITCode::HostFunction(callThunk), function, JITCode::HostFunction(constructThunk), constructor));
101 }
102
103 ~NativeExecutable();
104
105 NativeFunction function() { return m_function; }
106
107 private:
108 NativeExecutable(JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor)
109 : ExecutableBase(NUM_PARAMETERS_IS_HOST)
110 , m_function(function)
111 , m_constructor(constructor)
112 {
113 m_jitCodeForCall = callThunk;
114 m_jitCodeForConstruct = constructThunk;
115 m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
116 m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
117 }
118
119 NativeFunction m_function;
120 // Probably should be a NativeConstructor, but this will currently require rewriting the JIT
121 // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList.
122 NativeFunction m_constructor;
123 };
124#endif
125
126 class VPtrHackExecutable : public ExecutableBase {
127 public:
128 VPtrHackExecutable()
129 : ExecutableBase(NUM_PARAMETERS_IS_HOST)
130 {
131 }
132
133 ~VPtrHackExecutable();
134 };
135
136 class ScriptExecutable : public ExecutableBase {
137 public:
138 ScriptExecutable(JSGlobalData* globalData, const SourceCode& source)
139 : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
140 , m_source(source)
141 , m_features(0)
142 {
143#if ENABLE(CODEBLOCK_SAMPLING)
144 if (SamplingTool* sampler = globalData->interpreter->sampler())
145 sampler->notifyOfScope(this);
146#else
147 UNUSED_PARAM(globalData);
148#endif
149 }
150
151 ScriptExecutable(ExecState* exec, const SourceCode& source)
152 : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
153 , m_source(source)
154 , m_features(0)
155 {
156#if ENABLE(CODEBLOCK_SAMPLING)
157 if (SamplingTool* sampler = exec->globalData().interpreter->sampler())
158 sampler->notifyOfScope(this);
159#else
160 UNUSED_PARAM(exec);
161#endif
162 }
163
164 const SourceCode& source() { return m_source; }
165 intptr_t sourceID() const { return m_source.provider()->asID(); }
166 const UString& sourceURL() const { return m_source.provider()->url(); }
167 int lineNo() const { return m_firstLine; }
168 int lastLine() const { return m_lastLine; }
169
170 bool usesEval() const { return m_features & EvalFeature; }
171 bool usesArguments() const { return m_features & ArgumentsFeature; }
172 bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
173
174 virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
175
176 protected:
177 void recordParse(CodeFeatures features, int firstLine, int lastLine)
178 {
179 m_features = features;
180 m_firstLine = firstLine;
181 m_lastLine = lastLine;
182 }
183
184 SourceCode m_source;
185 CodeFeatures m_features;
186 int m_firstLine;
187 int m_lastLine;
188 };
189
190 class EvalExecutable : public ScriptExecutable {
191 public:
192
193 ~EvalExecutable();
194
195 EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
196 {
197 if (!m_evalCodeBlock) {
198 JSObject* error = compile(exec, scopeChainNode);
199 ASSERT_UNUSED(!error, error);
200 }
201 return *m_evalCodeBlock;
202 }
203
204 JSObject* compile(ExecState*, ScopeChainNode*);
205
206 ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
207 static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); }
208
209 private:
210 EvalExecutable(ExecState* exec, const SourceCode& source)
211 : ScriptExecutable(exec, source)
212 , m_evalCodeBlock(0)
213 {
214 }
215 EvalCodeBlock* m_evalCodeBlock;
216
217#if ENABLE(JIT)
218 public:
219 JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
220 {
221 if (!m_jitCodeForCall)
222 generateJITCode(exec, scopeChainNode);
223 return m_jitCodeForCall;
224 }
225
226 private:
227 void generateJITCode(ExecState*, ScopeChainNode*);
228#endif
229 };
230
231 class ProgramExecutable : public ScriptExecutable {
232 public:
233 static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source)
234 {
235 return adoptRef(new ProgramExecutable(exec, source));
236 }
237
238 ~ProgramExecutable();
239
240 ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
241 {
242 if (!m_programCodeBlock) {
243 JSObject* error = compile(exec, scopeChainNode);
244 ASSERT_UNUSED(!error, error);
245 }
246 return *m_programCodeBlock;
247 }
248
249 JSObject* checkSyntax(ExecState*);
250 JSObject* compile(ExecState*, ScopeChainNode*);
251
252 // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information.
253 ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; }
254
255 private:
256 ProgramExecutable(ExecState* exec, const SourceCode& source)
257 : ScriptExecutable(exec, source)
258 , m_programCodeBlock(0)
259 {
260 }
261 ProgramCodeBlock* m_programCodeBlock;
262
263#if ENABLE(JIT)
264 public:
265 JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
266 {
267 if (!m_jitCodeForCall)
268 generateJITCode(exec, scopeChainNode);
269 return m_jitCodeForCall;
270 }
271
272 private:
273 void generateJITCode(ExecState*, ScopeChainNode*);
274#endif
275 };
276
277 class FunctionExecutable : public ScriptExecutable {
278 friend class JIT;
279 public:
280 static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
281 {
282 return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine));
283 }
284
285 static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
286 {
287 return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine));
288 }
289
290 ~FunctionExecutable();
291
292 JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
293 {
294 return new (exec) JSFunction(exec, this, scopeChain);
295 }
296
297 // Returns either call or construct bytecode. This can be appropriate
298 // for answering questions that that don't vary between call and construct --
299 // for example, argumentsRegister().
300 FunctionCodeBlock& generatedByteCode()
301 {
302 if (m_codeBlockForCall)
303 return *m_codeBlockForCall;
304 ASSERT(m_codeBlockForConstruct);
305 return *m_codeBlockForConstruct;
306 }
307
308 FunctionCodeBlock* bytecodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
309 {
310 ASSERT(scopeChainNode);
311 if (!m_codeBlockForCall)
312 compileForCall(exec, scopeChainNode);
313 return m_codeBlockForCall;
314 }
315
316 bool isGeneratedForCall() const
317 {
318 return m_codeBlockForCall;
319 }
320
321 FunctionCodeBlock& generatedBytecodeForCall()
322 {
323 ASSERT(m_codeBlockForCall);
324 return *m_codeBlockForCall;
325 }
326
327 FunctionCodeBlock* bytecodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
328 {
329 ASSERT(scopeChainNode);
330 if (!m_codeBlockForConstruct)
331 compileForConstruct(exec, scopeChainNode);
332 return m_codeBlockForConstruct;
333 }
334
335 bool isGeneratedForConstruct() const
336 {
337 return m_codeBlockForConstruct;
338 }
339
340 FunctionCodeBlock& generatedBytecodeForConstruct()
341 {
342 ASSERT(m_codeBlockForConstruct);
343 return *m_codeBlockForConstruct;
344 }
345
346 const Identifier& name() { return m_name; }
347 size_t parameterCount() const { return m_parameters->size(); }
348 unsigned variableCount() const { return m_numVariables; }
349 UString paramString() const;
350 SharedSymbolTable* symbolTable() const { return m_symbolTable; }
351
352 void recompile(ExecState*);
353 ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
354 void markAggregate(MarkStack& markStack);
355 static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0);
356
357 private:
358 FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
359 : ScriptExecutable(globalData, source)
360 , m_numVariables(0)
361 , m_forceUsesArguments(forceUsesArguments)
362 , m_parameters(parameters)
363 , m_codeBlockForCall(0)
364 , m_codeBlockForConstruct(0)
365 , m_name(name)
366 , m_symbolTable(0)
367 {
368 m_firstLine = firstLine;
369 m_lastLine = lastLine;
370 }
371
372 FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
373 : ScriptExecutable(exec, source)
374 , m_numVariables(0)
375 , m_forceUsesArguments(forceUsesArguments)
376 , m_parameters(parameters)
377 , m_codeBlockForCall(0)
378 , m_codeBlockForConstruct(0)
379 , m_name(name)
380 , m_symbolTable(0)
381 {
382 m_firstLine = firstLine;
383 m_lastLine = lastLine;
384 }
385
386 bool compileForCall(ExecState*, ScopeChainNode*);
387 bool compileForConstruct(ExecState*, ScopeChainNode*);
388
389 unsigned m_numVariables : 31;
390 bool m_forceUsesArguments : 1;
391
392 RefPtr<FunctionParameters> m_parameters;
393 FunctionCodeBlock* m_codeBlockForCall;
394 FunctionCodeBlock* m_codeBlockForConstruct;
395 Identifier m_name;
396 SharedSymbolTable* m_symbolTable;
397
398#if ENABLE(JIT)
399 public:
400 JITCode& jitCodeForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
401 {
402 if (!m_jitCodeForCall)
403 generateJITCodeForCall(exec, scopeChainNode);
404 return m_jitCodeForCall;
405 }
406
407 JITCode& jitCodeForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
408 {
409 if (!m_jitCodeForConstruct)
410 generateJITCodeForConstruct(exec, scopeChainNode);
411 return m_jitCodeForConstruct;
412 }
413
414 MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
415 {
416 ASSERT(m_jitCodeForCall);
417 ASSERT(m_jitCodeForCallWithArityCheck);
418 return m_jitCodeForCallWithArityCheck;
419 }
420
421 MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
422 {
423 ASSERT(m_jitCodeForConstruct);
424 ASSERT(m_jitCodeForConstructWithArityCheck);
425 return m_jitCodeForConstructWithArityCheck;
426 }
427
428 private:
429 void generateJITCodeForCall(ExecState*, ScopeChainNode*);
430 void generateJITCodeForConstruct(ExecState*, ScopeChainNode*);
431#endif
432 };
433
434 inline FunctionExecutable* JSFunction::jsExecutable() const
435 {
436 ASSERT(!isHostFunctionNonInline());
437 return static_cast<FunctionExecutable*>(m_executable.get());
438 }
439
440 inline bool JSFunction::isHostFunction() const
441 {
442 ASSERT(m_executable);
443 return m_executable->isHostFunction();
444 }
445
446#if ENABLE(JIT)
447 inline NativeFunction JSFunction::nativeFunction()
448 {
449 ASSERT(isHostFunction());
450 return static_cast<NativeExecutable*>(m_executable.get())->function();
451 }
452#endif
453}
454
455#endif
Note: See TracBrowser for help on using the repository browser.