Changeset 35016 in webkit for trunk/JavaScriptCore/kjs/Arguments.cpp
- Timestamp:
- Jul 5, 2008, 4:19:36 PM (17 years ago)
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/Arguments.cpp
r35006 r35016 1 // -*- c-basic-offset: 2 -*-2 1 /* 3 2 * Copyright (C) 1999-2002 Harri Porten ([email protected]) … … 25 24 26 25 #include "config.h" 26 #include "Arguments.h" 27 27 28 #include "JSFunction.h" 28 29 #include "ExecState.h" 30 #include "FunctionPrototype.h" 29 #include "JSGlobalObject.h" 31 30 #include "JSActivation.h" 32 #include "JSGlobalObject.h"33 #include "JSString.h"34 #include "Machine.h"35 #include "ObjectPrototype.h"36 #include "Parser.h"37 #include "PropertyNameArray.h"38 #include "ScopeChainMark.h"39 #include "debugger.h"40 #include "dtoa.h"41 #include "lexer.h"42 #include "nodes.h"43 #include "operations.h"44 #include <errno.h>45 #include <profiler/Profiler.h>46 #include <stdio.h>47 #include <stdlib.h>48 #include <string.h>49 #include <wtf/ASCIICType.h>50 #include <wtf/Assertions.h>51 #include <wtf/MathExtras.h>52 #include <wtf/unicode/UTF8.h>53 54 using namespace WTF;55 using namespace Unicode;56 31 57 32 namespace KJS { 58 59 // ----------------------------- JSFunction ----------------------------------60 61 const ClassInfo JSFunction::info = { "Function", &InternalFunction::info, 0, 0 };62 63 JSFunction::JSFunction(ExecState* exec, const Identifier& name, FunctionBodyNode* b, ScopeChainNode* scopeChain)64 : InternalFunction(exec->lexicalGlobalObject()->functionPrototype(), name)65 , body(b)66 , _scope(scopeChain)67 {68 }69 70 void JSFunction::mark()71 {72 InternalFunction::mark();73 body->mark();74 _scope.mark();75 }76 77 CallType JSFunction::getCallData(CallData& callData)78 {79 callData.js.functionBody = body.get();80 callData.js.scopeChain = _scope.node();81 return CallTypeJS;82 }83 84 JSValue* JSFunction::call(ExecState* exec, JSValue* thisValue, const ArgList& args)85 {86 return exec->machine()->execute(body.get(), exec, this, thisValue->toThisObject(exec), args, _scope.node(), exec->exceptionSlot());87 }88 89 JSValue* JSFunction::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)90 {91 JSFunction* thisObj = static_cast<JSFunction*>(slot.slotBase());92 return exec->machine()->retrieveArguments(exec, thisObj);93 }94 95 JSValue* JSFunction::callerGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)96 {97 JSFunction* thisObj = static_cast<JSFunction*>(slot.slotBase());98 return exec->machine()->retrieveCaller(exec, thisObj);99 }100 101 JSValue* JSFunction::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)102 {103 JSFunction* thisObj = static_cast<JSFunction*>(slot.slotBase());104 return jsNumber(exec, thisObj->body->parameters().size());105 }106 107 bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)108 {109 if (propertyName == exec->propertyNames().arguments) {110 slot.setCustom(this, argumentsGetter);111 return true;112 }113 114 if (propertyName == exec->propertyNames().length) {115 slot.setCustom(this, lengthGetter);116 return true;117 }118 119 if (propertyName == exec->propertyNames().caller) {120 slot.setCustom(this, callerGetter);121 return true;122 }123 124 return InternalFunction::getOwnPropertySlot(exec, propertyName, slot);125 }126 127 void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue* value)128 {129 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)130 return;131 InternalFunction::put(exec, propertyName, value);132 }133 134 bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName)135 {136 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)137 return false;138 return InternalFunction::deleteProperty(exec, propertyName);139 }140 141 /* Returns the parameter name corresponding to the given index. eg:142 * function f1(x, y, z): getParameterName(0) --> x143 *144 * If a name appears more than once, only the last index at which145 * it appears associates with it. eg:146 * function f2(x, x): getParameterName(0) --> null147 */148 const Identifier& JSFunction::getParameterName(int index)149 {150 Vector<Identifier>& parameters = body->parameters();151 152 if (static_cast<size_t>(index) >= body->parameters().size())153 return _scope.globalObject()->globalData()->propertyNames->nullIdentifier;154 155 const Identifier& name = parameters[index];156 157 // Are there any subsequent parameters with the same name?158 size_t size = parameters.size();159 for (size_t i = index + 1; i < size; ++i)160 if (parameters[i] == name)161 return _scope.globalObject()->globalData()->propertyNames->nullIdentifier;162 163 return name;164 }165 166 // ECMA 13.2.2 [[Construct]]167 ConstructType JSFunction::getConstructData(ConstructData& constructData)168 {169 constructData.js.functionBody = body.get();170 constructData.js.scopeChain = _scope.node();171 return ConstructTypeJS;172 }173 174 JSObject* JSFunction::construct(ExecState* exec, const ArgList& args)175 {176 JSObject* proto;177 JSValue* p = get(exec, exec->propertyNames().prototype);178 if (p->isObject())179 proto = static_cast<JSObject*>(p);180 else181 proto = exec->lexicalGlobalObject()->objectPrototype();182 183 JSObject* thisObj = new (exec) JSObject(proto);184 185 JSValue* result = exec->machine()->execute(body.get(), exec, this, thisObj, args, _scope.node(), exec->exceptionSlot());186 if (exec->hadException() || !result->isObject())187 return thisObj;188 return static_cast<JSObject*>(result);189 }190 191 // ------------------------------ IndexToNameMap ---------------------------------192 193 // We map indexes in the arguments array to their corresponding argument names.194 // Example: function f(x, y, z): arguments[0] = x, so we map 0 to Identifier("x").195 196 // Once we have an argument name, we can get and set the argument's value in the197 // activation object.198 199 // We use Identifier::null to indicate that a given argument's value200 // isn't stored in the activation object.201 202 IndexToNameMap::IndexToNameMap(JSFunction* func, const ArgList& args)203 {204 _map = new Identifier[args.size()];205 this->size = args.size();206 207 unsigned i = 0;208 ArgList::const_iterator end = args.end();209 for (ArgList::const_iterator it = args.begin(); it != end; ++i, ++it)210 _map[i] = func->getParameterName(i); // null if there is no corresponding parameter211 }212 213 IndexToNameMap::~IndexToNameMap()214 {215 delete [] _map;216 }217 218 bool IndexToNameMap::isMapped(const Identifier& index) const219 {220 bool indexIsNumber;221 unsigned indexAsNumber = index.toStrictUInt32(&indexIsNumber);222 223 if (!indexIsNumber)224 return false;225 226 if (indexAsNumber >= size)227 return false;228 229 if (_map[indexAsNumber].isNull())230 return false;231 232 return true;233 }234 235 void IndexToNameMap::unMap(ExecState* exec, const Identifier& index)236 {237 bool indexIsNumber;238 unsigned indexAsNumber = index.toStrictUInt32(&indexIsNumber);239 240 ASSERT(indexIsNumber && indexAsNumber < size);241 242 _map[indexAsNumber] = exec->propertyNames().nullIdentifier;243 }244 245 Identifier& IndexToNameMap::operator[](const Identifier& index)246 {247 bool indexIsNumber;248 unsigned indexAsNumber = index.toStrictUInt32(&indexIsNumber);249 250 ASSERT(indexIsNumber && indexAsNumber < size);251 252 return _map[indexAsNumber];253 }254 255 // ------------------------------ Arguments ---------------------------------256 33 257 34 const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 }; … … 316 93 } 317 94 318 // ------------------------------ Global Functions -----------------------------------319 320 static JSValue* encode(ExecState* exec, const ArgList& args, const char* do_not_escape)321 {322 UString r = "", s, str = args[0]->toString(exec);323 CString cstr = str.UTF8String(true);324 if (!cstr.c_str())325 return throwError(exec, URIError, "String contained an illegal UTF-16 sequence.");326 const char* p = cstr.c_str();327 for (size_t k = 0; k < cstr.size(); k++, p++) {328 char c = *p;329 if (c && strchr(do_not_escape, c)) {330 r.append(c);331 } else {332 char tmp[4];333 sprintf(tmp, "%%%02X", (unsigned char)c);334 r += tmp;335 }336 }337 return jsString(exec, r);338 }339 340 static JSValue* decode(ExecState* exec, const ArgList& args, const char* do_not_unescape, bool strict)341 {342 UString s = "", str = args[0]->toString(exec);343 int k = 0, len = str.size();344 const UChar* d = str.data();345 UChar u = 0;346 while (k < len) {347 const UChar* p = d + k;348 UChar c = *p;349 if (c == '%') {350 int charLen = 0;351 if (k <= len - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {352 const char b0 = Lexer::convertHex(p[1], p[2]);353 const int sequenceLen = UTF8SequenceLength(b0);354 if (sequenceLen != 0 && k <= len - sequenceLen * 3) {355 charLen = sequenceLen * 3;356 char sequence[5];357 sequence[0] = b0;358 for (int i = 1; i < sequenceLen; ++i) {359 const UChar* q = p + i * 3;360 if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))361 sequence[i] = Lexer::convertHex(q[1], q[2]);362 else {363 charLen = 0;364 break;365 }366 }367 if (charLen != 0) {368 sequence[sequenceLen] = 0;369 const int character = decodeUTF8Sequence(sequence);370 if (character < 0 || character >= 0x110000) {371 charLen = 0;372 } else if (character >= 0x10000) {373 // Convert to surrogate pair.374 s.append(static_cast<UChar>(0xD800 | ((character - 0x10000) >> 10)));375 u = static_cast<UChar>(0xDC00 | ((character - 0x10000) & 0x3FF));376 } else {377 u = static_cast<UChar>(character);378 }379 }380 }381 }382 if (charLen == 0) {383 if (strict)384 return throwError(exec, URIError);385 // The only case where we don't use "strict" mode is the "unescape" function.386 // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.387 if (k <= len - 6 && p[1] == 'u'388 && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])389 && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {390 charLen = 6;391 u = Lexer::convertUnicode(p[2], p[3], p[4], p[5]);392 }393 }394 if (charLen && (u == 0 || u >= 128 || !strchr(do_not_unescape, u))) {395 c = u;396 k += charLen - 1;397 }398 }399 k++;400 s.append(c);401 }402 return jsString(exec, s);403 }404 405 static bool isStrWhiteSpace(unsigned short c)406 {407 switch (c) {408 case 0x0009:409 case 0x000A:410 case 0x000B:411 case 0x000C:412 case 0x000D:413 case 0x0020:414 case 0x00A0:415 case 0x2028:416 case 0x2029:417 return true;418 default:419 return c > 0xff && isSeparatorSpace(c);420 }421 }422 423 static int parseDigit(unsigned short c, int radix)424 {425 int digit = -1;426 427 if (c >= '0' && c <= '9') {428 digit = c - '0';429 } else if (c >= 'A' && c <= 'Z') {430 digit = c - 'A' + 10;431 } else if (c >= 'a' && c <= 'z') {432 digit = c - 'a' + 10;433 }434 435 if (digit >= radix)436 return -1;437 return digit;438 }439 440 double parseIntOverflow(const char* s, int length, int radix)441 {442 double number = 0.0;443 double radixMultiplier = 1.0;444 445 for (const char* p = s + length - 1; p >= s; p--) {446 if (radixMultiplier == Inf) {447 if (*p != '0') {448 number = Inf;449 break;450 }451 } else {452 int digit = parseDigit(*p, radix);453 number += digit * radixMultiplier;454 }455 456 radixMultiplier *= radix;457 }458 459 return number;460 }461 462 static double parseInt(const UString& s, int radix)463 {464 int length = s.size();465 int p = 0;466 467 while (p < length && isStrWhiteSpace(s[p])) {468 ++p;469 }470 471 double sign = 1;472 if (p < length) {473 if (s[p] == '+') {474 ++p;475 } else if (s[p] == '-') {476 sign = -1;477 ++p;478 }479 }480 481 if ((radix == 0 || radix == 16) && length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {482 radix = 16;483 p += 2;484 } else if (radix == 0) {485 if (p < length && s[p] == '0')486 radix = 8;487 else488 radix = 10;489 }490 491 if (radix < 2 || radix > 36)492 return NaN;493 494 int firstDigitPosition = p;495 bool sawDigit = false;496 double number = 0;497 while (p < length) {498 int digit = parseDigit(s[p], radix);499 if (digit == -1)500 break;501 sawDigit = true;502 number *= radix;503 number += digit;504 ++p;505 }506 507 if (number >= mantissaOverflowLowerBound) {508 if (radix == 10)509 number = strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0);510 else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)511 number = parseIntOverflow(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), p - firstDigitPosition, radix);512 }513 514 if (!sawDigit)515 return NaN;516 517 return sign * number;518 }519 520 static double parseFloat(const UString& s)521 {522 // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.523 // Need to skip any whitespace and then one + or - sign.524 int length = s.size();525 int p = 0;526 while (p < length && isStrWhiteSpace(s[p])) {527 ++p;528 }529 if (p < length && (s[p] == '+' || s[p] == '-')) {530 ++p;531 }532 if (length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {533 return 0;534 }535 536 return s.toDouble( true /*tolerant*/, false /* NaN for empty string */ );537 }538 539 JSValue* globalFuncEval(ExecState* exec, JSObject* function, JSValue* thisValue, const ArgList& args)540 {541 JSObject* thisObject = thisValue->toThisObject(exec);542 JSGlobalObject* globalObject = thisObject->toGlobalObject(exec);543 if (!globalObject || globalObject->evalFunction() != function)544 return throwError(exec, EvalError, "The \"this\" value passed to eval must be the global object from which eval originated");545 546 JSValue* x = args[0];547 if (!x->isString())548 return x;549 550 UString s = x->toString(exec);551 552 int sourceId;553 int errLine;554 UString errMsg;555 556 RefPtr<EvalNode> evalNode = exec->parser()->parse<EvalNode>(exec, UString(), 1, UStringSourceProvider::create(s), &sourceId, &errLine, &errMsg);557 558 if (!evalNode)559 return throwError(exec, SyntaxError, errMsg, errLine, sourceId, NULL);560 561 return exec->machine()->execute(evalNode.get(), exec, thisObject, globalObject->globalScopeChain().node(), exec->exceptionSlot());562 }563 564 JSValue* globalFuncParseInt(ExecState* exec, JSObject*, JSValue*, const ArgList& args)565 {566 return jsNumber(exec, parseInt(args[0]->toString(exec), args[1]->toInt32(exec)));567 }568 569 JSValue* globalFuncParseFloat(ExecState* exec, JSObject*, JSValue*, const ArgList& args)570 {571 return jsNumber(exec, parseFloat(args[0]->toString(exec)));572 }573 574 JSValue* globalFuncIsNaN(ExecState* exec, JSObject*, JSValue*, const ArgList& args)575 {576 return jsBoolean(isnan(args[0]->toNumber(exec)));577 }578 579 JSValue* globalFuncIsFinite(ExecState* exec, JSObject*, JSValue*, const ArgList& args)580 {581 double n = args[0]->toNumber(exec);582 return jsBoolean(!isnan(n) && !isinf(n));583 }584 585 JSValue* globalFuncDecodeURI(ExecState* exec, JSObject*, JSValue*, const ArgList& args)586 {587 static const char do_not_unescape_when_decoding_URI[] =588 "#$&+,/:;=?@";589 590 return decode(exec, args, do_not_unescape_when_decoding_URI, true);591 }592 593 JSValue* globalFuncDecodeURIComponent(ExecState* exec, JSObject*, JSValue*, const ArgList& args)594 {595 return decode(exec, args, "", true);596 }597 598 JSValue* globalFuncEncodeURI(ExecState* exec, JSObject*, JSValue*, const ArgList& args)599 {600 static const char do_not_escape_when_encoding_URI[] =601 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"602 "abcdefghijklmnopqrstuvwxyz"603 "0123456789"604 "!#$&'()*+,-./:;=?@_~";605 606 return encode(exec, args, do_not_escape_when_encoding_URI);607 }608 609 JSValue* globalFuncEncodeURIComponent(ExecState* exec, JSObject*, JSValue*, const ArgList& args)610 {611 static const char do_not_escape_when_encoding_URI_component[] =612 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"613 "abcdefghijklmnopqrstuvwxyz"614 "0123456789"615 "!'()*-._~";616 617 return encode(exec, args, do_not_escape_when_encoding_URI_component);618 }619 620 JSValue* globalFuncEscape(ExecState* exec, JSObject*, JSValue*, const ArgList& args)621 {622 static const char do_not_escape[] =623 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"624 "abcdefghijklmnopqrstuvwxyz"625 "0123456789"626 "*+-./@_";627 628 UString r = "", s, str = args[0]->toString(exec);629 const UChar* c = str.data();630 for (int k = 0; k < str.size(); k++, c++) {631 int u = c[0];632 if (u > 255) {633 char tmp[7];634 sprintf(tmp, "%%u%04X", u);635 s = UString(tmp);636 } else if (u != 0 && strchr(do_not_escape, (char)u))637 s = UString(c, 1);638 else {639 char tmp[4];640 sprintf(tmp, "%%%02X", u);641 s = UString(tmp);642 }643 r += s;644 }645 646 return jsString(exec, r);647 }648 649 JSValue* globalFuncUnescape(ExecState* exec, JSObject*, JSValue*, const ArgList& args)650 {651 UString s = "", str = args[0]->toString(exec);652 int k = 0, len = str.size();653 while (k < len) {654 const UChar* c = str.data() + k;655 UChar u;656 if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {657 if (Lexer::isHexDigit(c[2]) && Lexer::isHexDigit(c[3]) && Lexer::isHexDigit(c[4]) && Lexer::isHexDigit(c[5])) {658 u = Lexer::convertUnicode(c[2], c[3], c[4], c[5]);659 c = &u;660 k += 5;661 }662 } else if (c[0] == '%' && k <= len - 3 && Lexer::isHexDigit(c[1]) && Lexer::isHexDigit(c[2])) {663 u = UChar(Lexer::convertHex(c[1], c[2]));664 c = &u;665 k += 2;666 }667 k++;668 s.append(*c);669 }670 671 return jsString(exec, s);672 }673 674 #ifndef NDEBUG675 JSValue* globalFuncKJSPrint(ExecState* exec, JSObject*, JSValue*, const ArgList& args)676 {677 CStringBuffer string;678 args[0]->toString(exec).getCString(string);679 puts(string.data());680 return jsUndefined();681 }682 #endif683 684 // ------------------------------ PrototypeFunction -------------------------------685 686 PrototypeFunction::PrototypeFunction(ExecState* exec, int len, const Identifier& name, NativeFunction function)687 : InternalFunction(exec->lexicalGlobalObject()->functionPrototype(), name)688 , m_function(function)689 {690 ASSERT_ARG(function, function);691 putDirect(exec->propertyNames().length, jsNumber(exec, len), DontDelete | ReadOnly | DontEnum);692 }693 694 PrototypeFunction::PrototypeFunction(ExecState* exec, FunctionPrototype* functionPrototype, int len, const Identifier& name, NativeFunction function)695 : InternalFunction(functionPrototype, name)696 , m_function(function)697 {698 ASSERT_ARG(function, function);699 putDirect(exec->propertyNames().length, jsNumber(exec, len), DontDelete | ReadOnly | DontEnum);700 }701 702 CallType PrototypeFunction::getCallData(CallData& callData)703 {704 callData.native.function = m_function;705 return CallTypeNative;706 }707 708 // ------------------------------ PrototypeReflexiveFunction -------------------------------709 710 GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, FunctionPrototype* functionPrototype, int len, const Identifier& name, NativeFunction function, JSGlobalObject* cachedGlobalObject)711 : PrototypeFunction(exec, functionPrototype, len, name, function)712 , m_cachedGlobalObject(cachedGlobalObject)713 {714 ASSERT_ARG(cachedGlobalObject, cachedGlobalObject);715 }716 717 void GlobalEvalFunction::mark()718 {719 PrototypeFunction::mark();720 if (!m_cachedGlobalObject->marked())721 m_cachedGlobalObject->mark();722 }723 724 95 } // namespace KJS
Note:
See TracChangeset
for help on using the changeset viewer.