source: webkit/trunk/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp@ 47601

Last change on this file since 47601 was 47304, checked in by [email protected], 16 years ago

Remove AST nodes from use within the Runtime (outside of parsing), stage 1
https://bugs.webkit.org/show_bug.cgi?id=28330

Reviewed by Oliver Hunt.

Remove the EvalNode and ProgramNode from use in the runtime. They still exist
after this patch, but are hidden behind EvalExecutable and FunctionExecutable,
and are also still reachable behind CodeBlock::m_ownerNode.

The next step will be to beat back FunctionBodyNode in the same fashion.
Then remove the usage via CodeBlock, then only construct these nodes only on
demand during bytecode generation.

(JSC::GlobalCodeBlock::GlobalCodeBlock):
(JSC::GlobalCodeBlock::~GlobalCodeBlock):
(JSC::ProgramCodeBlock::ProgramCodeBlock):
(JSC::EvalCodeBlock::EvalCodeBlock):
(JSC::FunctionCodeBlock::FunctionCodeBlock):
(JSC::NativeCodeBlock::NativeCodeBlock):

  • bytecode/EvalCodeCache.h:

(JSC::EvalCodeCache::get):

  • debugger/Debugger.cpp:

(JSC::evaluateInGlobalCallFrame):

  • debugger/DebuggerCallFrame.cpp:

(JSC::DebuggerCallFrame::evaluate):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::callEval):
(JSC::Interpreter::execute):

  • interpreter/Interpreter.h:
  • parser/Nodes.cpp:

(JSC::FunctionBodyNode::createNativeThunk):
(JSC::FunctionBodyNode::generateBytecode):
(JSC::FunctionBodyNode::bytecodeForExceptionInfoReparse):

  • parser/Parser.h:

(JSC::Parser::parse):
(JSC::Parser::reparse):
(JSC::Parser::parseFunctionFromGlobalCode):
(JSC::::parse):

  • runtime/Completion.cpp:

(JSC::checkSyntax):
(JSC::evaluate):

  • runtime/Error.cpp:

(JSC::throwError):

  • runtime/Error.h:
  • runtime/Executable.h: Added.

(JSC::TemplateExecutable::TemplateExecutable):
(JSC::TemplateExecutable::markAggregate):
(JSC::TemplateExecutable::sourceURL):
(JSC::TemplateExecutable::lineNo):
(JSC::TemplateExecutable::bytecode):
(JSC::TemplateExecutable::jitCode):
(JSC::EvalExecutable::EvalExecutable):
(JSC::ProgramExecutable::ProgramExecutable):

  • runtime/FunctionConstructor.cpp:

(JSC::constructFunction):

  • runtime/FunctionConstructor.h:
  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::numericCompareFunction):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::~JSGlobalObject):
(JSC::JSGlobalObject::markChildren):

  • runtime/JSGlobalObject.h:

(JSC::JSGlobalObject::codeBlocks):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncEval):

  • Property svn:eol-style set to native
File size: 13.5 KB
Line 
1/*
2 * Copyright (C) 1999-2002 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich ([email protected])
6 * Copyright (C) 2007 Maks Orlovich
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "JSGlobalObjectFunctions.h"
27
28#include "CallFrame.h"
29#include "GlobalEvalFunction.h"
30#include "JSGlobalObject.h"
31#include "LiteralParser.h"
32#include "JSString.h"
33#include "Interpreter.h"
34#include "Parser.h"
35#include "dtoa.h"
36#include "Lexer.h"
37#include "Nodes.h"
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <wtf/ASCIICType.h>
42#include <wtf/Assertions.h>
43#include <wtf/MathExtras.h>
44#include <wtf/unicode/UTF8.h>
45
46using namespace WTF;
47using namespace Unicode;
48
49namespace JSC {
50
51static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEscape)
52{
53 UString str = args.at(0).toString(exec);
54 CString cstr = str.UTF8String(true);
55 if (!cstr.c_str())
56 return throwError(exec, URIError, "String contained an illegal UTF-16 sequence.");
57
58 UString result = "";
59 const char* p = cstr.c_str();
60 for (size_t k = 0; k < cstr.size(); k++, p++) {
61 char c = *p;
62 if (c && strchr(doNotEscape, c))
63 result.append(c);
64 else {
65 char tmp[4];
66 sprintf(tmp, "%%%02X", static_cast<unsigned char>(c));
67 result += tmp;
68 }
69 }
70 return jsString(exec, result);
71}
72
73static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUnescape, bool strict)
74{
75 UString result = "";
76 UString str = args.at(0).toString(exec);
77 int k = 0;
78 int len = str.size();
79 const UChar* d = str.data();
80 UChar u = 0;
81 while (k < len) {
82 const UChar* p = d + k;
83 UChar c = *p;
84 if (c == '%') {
85 int charLen = 0;
86 if (k <= len - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {
87 const char b0 = Lexer::convertHex(p[1], p[2]);
88 const int sequenceLen = UTF8SequenceLength(b0);
89 if (sequenceLen != 0 && k <= len - sequenceLen * 3) {
90 charLen = sequenceLen * 3;
91 char sequence[5];
92 sequence[0] = b0;
93 for (int i = 1; i < sequenceLen; ++i) {
94 const UChar* q = p + i * 3;
95 if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))
96 sequence[i] = Lexer::convertHex(q[1], q[2]);
97 else {
98 charLen = 0;
99 break;
100 }
101 }
102 if (charLen != 0) {
103 sequence[sequenceLen] = 0;
104 const int character = decodeUTF8Sequence(sequence);
105 if (character < 0 || character >= 0x110000)
106 charLen = 0;
107 else if (character >= 0x10000) {
108 // Convert to surrogate pair.
109 result.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));
110 u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));
111 } else
112 u = static_cast<UChar>(character);
113 }
114 }
115 }
116 if (charLen == 0) {
117 if (strict)
118 return throwError(exec, URIError);
119 // The only case where we don't use "strict" mode is the "unescape" function.
120 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
121 if (k <= len - 6 && p[1] == 'u'
122 && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])
123 && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {
124 charLen = 6;
125 u = Lexer::convertUnicode(p[2], p[3], p[4], p[5]);
126 }
127 }
128 if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) {
129 c = u;
130 k += charLen - 1;
131 }
132 }
133 k++;
134 result.append(c);
135 }
136 return jsString(exec, result);
137}
138
139bool isStrWhiteSpace(UChar c)
140{
141 switch (c) {
142 case 0x0009:
143 case 0x000A:
144 case 0x000B:
145 case 0x000C:
146 case 0x000D:
147 case 0x0020:
148 case 0x00A0:
149 case 0x2028:
150 case 0x2029:
151 return true;
152 default:
153 return c > 0xff && isSeparatorSpace(c);
154 }
155}
156
157static int parseDigit(unsigned short c, int radix)
158{
159 int digit = -1;
160
161 if (c >= '0' && c <= '9')
162 digit = c - '0';
163 else if (c >= 'A' && c <= 'Z')
164 digit = c - 'A' + 10;
165 else if (c >= 'a' && c <= 'z')
166 digit = c - 'a' + 10;
167
168 if (digit >= radix)
169 return -1;
170 return digit;
171}
172
173double parseIntOverflow(const char* s, int length, int radix)
174{
175 double number = 0.0;
176 double radixMultiplier = 1.0;
177
178 for (const char* p = s + length - 1; p >= s; p--) {
179 if (radixMultiplier == Inf) {
180 if (*p != '0') {
181 number = Inf;
182 break;
183 }
184 } else {
185 int digit = parseDigit(*p, radix);
186 number += digit * radixMultiplier;
187 }
188
189 radixMultiplier *= radix;
190 }
191
192 return number;
193}
194
195static double parseInt(const UString& s, int radix)
196{
197 int length = s.size();
198 const UChar* data = s.data();
199 int p = 0;
200
201 while (p < length && isStrWhiteSpace(data[p]))
202 ++p;
203
204 double sign = 1;
205 if (p < length) {
206 if (data[p] == '+')
207 ++p;
208 else if (data[p] == '-') {
209 sign = -1;
210 ++p;
211 }
212 }
213
214 if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {
215 radix = 16;
216 p += 2;
217 } else if (radix == 0) {
218 if (p < length && data[p] == '0')
219 radix = 8;
220 else
221 radix = 10;
222 }
223
224 if (radix < 2 || radix > 36)
225 return NaN;
226
227 int firstDigitPosition = p;
228 bool sawDigit = false;
229 double number = 0;
230 while (p < length) {
231 int digit = parseDigit(data[p], radix);
232 if (digit == -1)
233 break;
234 sawDigit = true;
235 number *= radix;
236 number += digit;
237 ++p;
238 }
239
240 if (number >= mantissaOverflowLowerBound) {
241 if (radix == 10)
242 number = WTF::strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0);
243 else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
244 number = parseIntOverflow(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), p - firstDigitPosition, radix);
245 }
246
247 if (!sawDigit)
248 return NaN;
249
250 return sign * number;
251}
252
253static double parseFloat(const UString& s)
254{
255 // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
256 // Need to skip any whitespace and then one + or - sign.
257 int length = s.size();
258 const UChar* data = s.data();
259 int p = 0;
260 while (p < length && isStrWhiteSpace(data[p]))
261 ++p;
262
263 if (p < length && (data[p] == '+' || data[p] == '-'))
264 ++p;
265
266 if (length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X'))
267 return 0;
268
269 return s.toDouble(true /*tolerant*/, false /* NaN for empty string */);
270}
271
272JSValue JSC_HOST_CALL globalFuncEval(ExecState* exec, JSObject* function, JSValue thisValue, const ArgList& args)
273{
274 JSObject* thisObject = thisValue.toThisObject(exec);
275 JSObject* unwrappedObject = thisObject->unwrappedObject();
276 if (!unwrappedObject->isGlobalObject() || static_cast<JSGlobalObject*>(unwrappedObject)->evalFunction() != function)
277 return throwError(exec, EvalError, "The \"this\" value passed to eval must be the global object from which eval originated");
278
279 JSValue x = args.at(0);
280 if (!x.isString())
281 return x;
282
283 UString s = x.toString(exec);
284
285 LiteralParser preparser(exec, s, LiteralParser::NonStrictJSON);
286 if (JSValue parsedObject = preparser.tryLiteralParse())
287 return parsedObject;
288
289 EvalExecutable eval(makeSource(s));
290 JSObject* error = eval.parse(exec);
291 if (error)
292 return throwError(exec, error);
293
294 return exec->interpreter()->execute(&eval, exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node(), exec->exceptionSlot());
295}
296
297JSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec, JSObject*, JSValue, const ArgList& args)
298{
299 JSValue value = args.at(0);
300 int32_t radix = args.at(1).toInt32(exec);
301
302 if (radix != 0 && radix != 10)
303 return jsNumber(exec, parseInt(value.toString(exec), radix));
304
305 if (value.isInt32())
306 return value;
307
308 if (value.isDouble()) {
309 double d = value.asDouble();
310 if (isfinite(d))
311 return jsNumber(exec, (d > 0) ? floor(d) : ceil(d));
312 if (isnan(d) || isinf(d))
313 return jsNaN(exec);
314 return jsNumber(exec, 0);
315 }
316
317 return jsNumber(exec, parseInt(value.toString(exec), radix));
318}
319
320JSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec, JSObject*, JSValue, const ArgList& args)
321{
322 return jsNumber(exec, parseFloat(args.at(0).toString(exec)));
323}
324
325JSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec, JSObject*, JSValue, const ArgList& args)
326{
327 return jsBoolean(isnan(args.at(0).toNumber(exec)));
328}
329
330JSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec, JSObject*, JSValue, const ArgList& args)
331{
332 double n = args.at(0).toNumber(exec);
333 return jsBoolean(!isnan(n) && !isinf(n));
334}
335
336JSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec, JSObject*, JSValue, const ArgList& args)
337{
338 static const char do_not_unescape_when_decoding_URI[] =
339 "#$&+,/:;=?@";
340
341 return decode(exec, args, do_not_unescape_when_decoding_URI, true);
342}
343
344JSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec, JSObject*, JSValue, const ArgList& args)
345{
346 return decode(exec, args, "", true);
347}
348
349JSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec, JSObject*, JSValue, const ArgList& args)
350{
351 static const char do_not_escape_when_encoding_URI[] =
352 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
353 "abcdefghijklmnopqrstuvwxyz"
354 "0123456789"
355 "!#$&'()*+,-./:;=?@_~";
356
357 return encode(exec, args, do_not_escape_when_encoding_URI);
358}
359
360JSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec, JSObject*, JSValue, const ArgList& args)
361{
362 static const char do_not_escape_when_encoding_URI_component[] =
363 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
364 "abcdefghijklmnopqrstuvwxyz"
365 "0123456789"
366 "!'()*-._~";
367
368 return encode(exec, args, do_not_escape_when_encoding_URI_component);
369}
370
371JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, const ArgList& args)
372{
373 static const char do_not_escape[] =
374 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
375 "abcdefghijklmnopqrstuvwxyz"
376 "0123456789"
377 "*+-./@_";
378
379 UString result = "";
380 UString s;
381 UString str = args.at(0).toString(exec);
382 const UChar* c = str.data();
383 for (int k = 0; k < str.size(); k++, c++) {
384 int u = c[0];
385 if (u > 255) {
386 char tmp[7];
387 sprintf(tmp, "%%u%04X", u);
388 s = UString(tmp);
389 } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u)))
390 s = UString(c, 1);
391 else {
392 char tmp[4];
393 sprintf(tmp, "%%%02X", u);
394 s = UString(tmp);
395 }
396 result += s;
397 }
398
399 return jsString(exec, result);
400}
401
402JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, const ArgList& args)
403{
404 UString result = "";
405 UString str = args.at(0).toString(exec);
406 int k = 0;
407 int len = str.size();
408 while (k < len) {
409 const UChar* c = str.data() + k;
410 UChar u;
411 if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
412 if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
413 u = Lexer::convertUnicode(c[2], c[3], c[4], c[5]);
414 c = &u;
415 k += 5;
416 }
417 } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
418 u = UChar(Lexer::convertHex(c[1], c[2]));
419 c = &u;
420 k += 2;
421 }
422 k++;
423 result.append(*c);
424 }
425
426 return jsString(exec, result);
427}
428
429#ifndef NDEBUG
430JSValue JSC_HOST_CALL globalFuncJSCPrint(ExecState* exec, JSObject*, JSValue, const ArgList& args)
431{
432 CStringBuffer string;
433 args.at(0).toString(exec).getCString(string);
434 puts(string.data());
435 return jsUndefined();
436}
437#endif
438
439} // namespace JSC
Note: See TracBrowser for help on using the repository browser.