1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsfun.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1926 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* 1.11 + * JS function support. 1.12 + */ 1.13 + 1.14 +#include "jsfuninlines.h" 1.15 + 1.16 +#include "mozilla/ArrayUtils.h" 1.17 +#include "mozilla/PodOperations.h" 1.18 + 1.19 +#include <string.h> 1.20 + 1.21 +#include "jsapi.h" 1.22 +#include "jsarray.h" 1.23 +#include "jsatom.h" 1.24 +#include "jscntxt.h" 1.25 +#include "jsobj.h" 1.26 +#include "jsproxy.h" 1.27 +#include "jsscript.h" 1.28 +#include "jsstr.h" 1.29 +#include "jstypes.h" 1.30 +#include "jswrapper.h" 1.31 + 1.32 +#include "builtin/Eval.h" 1.33 +#include "builtin/Object.h" 1.34 +#include "frontend/BytecodeCompiler.h" 1.35 +#include "frontend/TokenStream.h" 1.36 +#include "gc/Marking.h" 1.37 +#ifdef JS_ION 1.38 +#include "jit/Ion.h" 1.39 +#include "jit/JitFrameIterator.h" 1.40 +#endif 1.41 +#include "vm/Interpreter.h" 1.42 +#include "vm/Shape.h" 1.43 +#include "vm/StringBuffer.h" 1.44 +#include "vm/WrapperObject.h" 1.45 +#include "vm/Xdr.h" 1.46 + 1.47 +#include "jsscriptinlines.h" 1.48 + 1.49 +#include "vm/Interpreter-inl.h" 1.50 +#include "vm/Stack-inl.h" 1.51 + 1.52 +using namespace js; 1.53 +using namespace js::gc; 1.54 +using namespace js::types; 1.55 +using namespace js::frontend; 1.56 + 1.57 +using mozilla::ArrayLength; 1.58 +using mozilla::PodCopy; 1.59 + 1.60 +static bool 1.61 +fun_getProperty(JSContext *cx, HandleObject obj_, HandleId id, MutableHandleValue vp) 1.62 +{ 1.63 + RootedObject obj(cx, obj_); 1.64 + while (!obj->is<JSFunction>()) { 1.65 + if (!JSObject::getProto(cx, obj, &obj)) 1.66 + return false; 1.67 + if (!obj) 1.68 + return true; 1.69 + } 1.70 + RootedFunction fun(cx, &obj->as<JSFunction>()); 1.71 + 1.72 + /* Set to early to null in case of error */ 1.73 + vp.setNull(); 1.74 + 1.75 + /* Find fun's top-most activation record. */ 1.76 + NonBuiltinScriptFrameIter iter(cx); 1.77 + for (; !iter.done(); ++iter) { 1.78 + if (!iter.isFunctionFrame() || iter.isEvalFrame()) 1.79 + continue; 1.80 + if (iter.callee() == fun) 1.81 + break; 1.82 + } 1.83 + if (iter.done()) 1.84 + return true; 1.85 + 1.86 + if (JSID_IS_ATOM(id, cx->names().arguments)) { 1.87 + if (fun->hasRest()) { 1.88 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.89 + JSMSG_FUNCTION_ARGUMENTS_AND_REST); 1.90 + return false; 1.91 + } 1.92 + /* Warn if strict about f.arguments or equivalent unqualified uses. */ 1.93 + if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT, js_GetErrorMessage, 1.94 + nullptr, JSMSG_DEPRECATED_USAGE, js_arguments_str)) { 1.95 + return false; 1.96 + } 1.97 + 1.98 + ArgumentsObject *argsobj = ArgumentsObject::createUnexpected(cx, iter); 1.99 + if (!argsobj) 1.100 + return false; 1.101 + 1.102 +#ifdef JS_ION 1.103 + // Disabling compiling of this script in IonMonkey. 1.104 + // IonMonkey does not guarantee |f.arguments| can be 1.105 + // fully recovered, so we try to mitigate observing this behavior by 1.106 + // detecting its use early. 1.107 + JSScript *script = iter.script(); 1.108 + jit::ForbidCompilation(cx, script); 1.109 +#endif 1.110 + 1.111 + vp.setObject(*argsobj); 1.112 + return true; 1.113 + } 1.114 + 1.115 + if (JSID_IS_ATOM(id, cx->names().caller)) { 1.116 + ++iter; 1.117 + if (iter.done() || !iter.isFunctionFrame()) { 1.118 + JS_ASSERT(vp.isNull()); 1.119 + return true; 1.120 + } 1.121 + 1.122 + /* Callsite clones should never escape to script. */ 1.123 + JSObject &maybeClone = iter.calleev().toObject(); 1.124 + if (maybeClone.is<JSFunction>()) 1.125 + vp.setObject(*maybeClone.as<JSFunction>().originalFunction()); 1.126 + else 1.127 + vp.set(iter.calleev()); 1.128 + 1.129 + if (!cx->compartment()->wrap(cx, vp)) 1.130 + return false; 1.131 + 1.132 + /* 1.133 + * Censor the caller if we don't have full access to it. 1.134 + */ 1.135 + RootedObject caller(cx, &vp.toObject()); 1.136 + if (caller->is<WrapperObject>() && Wrapper::wrapperHandler(caller)->hasSecurityPolicy()) { 1.137 + vp.setNull(); 1.138 + } else if (caller->is<JSFunction>()) { 1.139 + JSFunction *callerFun = &caller->as<JSFunction>(); 1.140 + if (callerFun->isInterpreted() && callerFun->strict()) { 1.141 + JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, nullptr, 1.142 + JSMSG_CALLER_IS_STRICT); 1.143 + return false; 1.144 + } 1.145 + } 1.146 + 1.147 + return true; 1.148 + } 1.149 + 1.150 + MOZ_ASSUME_UNREACHABLE("fun_getProperty"); 1.151 +} 1.152 + 1.153 + 1.154 + 1.155 +/* NB: no sentinels at ends -- use ArrayLength to bound loops. 1.156 + * Properties censored into [[ThrowTypeError]] in strict mode. */ 1.157 +static const uint16_t poisonPillProps[] = { 1.158 + NAME_OFFSET(arguments), 1.159 + NAME_OFFSET(caller), 1.160 +}; 1.161 + 1.162 +static bool 1.163 +fun_enumerate(JSContext *cx, HandleObject obj) 1.164 +{ 1.165 + JS_ASSERT(obj->is<JSFunction>()); 1.166 + 1.167 + RootedId id(cx); 1.168 + bool found; 1.169 + 1.170 + if (!obj->isBoundFunction() && !obj->as<JSFunction>().isArrow()) { 1.171 + id = NameToId(cx->names().prototype); 1.172 + if (!JSObject::hasProperty(cx, obj, id, &found)) 1.173 + return false; 1.174 + } 1.175 + 1.176 + id = NameToId(cx->names().length); 1.177 + if (!JSObject::hasProperty(cx, obj, id, &found)) 1.178 + return false; 1.179 + 1.180 + id = NameToId(cx->names().name); 1.181 + if (!JSObject::hasProperty(cx, obj, id, &found)) 1.182 + return false; 1.183 + 1.184 + for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) { 1.185 + const uint16_t offset = poisonPillProps[i]; 1.186 + id = NameToId(AtomStateOffsetToName(cx->names(), offset)); 1.187 + if (!JSObject::hasProperty(cx, obj, id, &found)) 1.188 + return false; 1.189 + } 1.190 + 1.191 + return true; 1.192 +} 1.193 + 1.194 +static JSObject * 1.195 +ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj) 1.196 +{ 1.197 +#ifdef DEBUG 1.198 + JSFunction *fun = &obj->as<JSFunction>(); 1.199 + JS_ASSERT(fun->isInterpreted()); 1.200 + JS_ASSERT(!fun->isFunctionPrototype()); 1.201 +#endif 1.202 + 1.203 + // Assert that fun is not a compiler-created function object, which 1.204 + // must never leak to script or embedding code and then be mutated. 1.205 + // Also assert that obj is not bound, per the ES5 15.3.4.5 ref above. 1.206 + JS_ASSERT(!IsInternalFunctionObject(obj)); 1.207 + JS_ASSERT(!obj->isBoundFunction()); 1.208 + 1.209 + // Make the prototype object an instance of Object with the same parent as 1.210 + // the function object itself, unless the function is an ES6 generator. In 1.211 + // that case, per the 15 July 2013 ES6 draft, section 15.19.3, its parent is 1.212 + // the GeneratorObjectPrototype singleton. 1.213 + bool isStarGenerator = obj->as<JSFunction>().isStarGenerator(); 1.214 + Rooted<GlobalObject*> global(cx, &obj->global()); 1.215 + JSObject *objProto; 1.216 + if (isStarGenerator) 1.217 + objProto = GlobalObject::getOrCreateStarGeneratorObjectPrototype(cx, global); 1.218 + else 1.219 + objProto = obj->global().getOrCreateObjectPrototype(cx); 1.220 + if (!objProto) 1.221 + return nullptr; 1.222 + const Class *clasp = &JSObject::class_; 1.223 + 1.224 + RootedObject proto(cx, NewObjectWithGivenProto(cx, clasp, objProto, nullptr, SingletonObject)); 1.225 + if (!proto) 1.226 + return nullptr; 1.227 + 1.228 + // Per ES5 15.3.5.2 a user-defined function's .prototype property is 1.229 + // initially non-configurable, non-enumerable, and writable. 1.230 + RootedValue protoVal(cx, ObjectValue(*proto)); 1.231 + if (!JSObject::defineProperty(cx, obj, cx->names().prototype, 1.232 + protoVal, JS_PropertyStub, JS_StrictPropertyStub, 1.233 + JSPROP_PERMANENT)) 1.234 + { 1.235 + return nullptr; 1.236 + } 1.237 + 1.238 + // Per ES5 13.2 the prototype's .constructor property is configurable, 1.239 + // non-enumerable, and writable. However, per the 15 July 2013 ES6 draft, 1.240 + // section 15.19.3, the .prototype of a generator function does not link 1.241 + // back with a .constructor. 1.242 + if (!isStarGenerator) { 1.243 + RootedValue objVal(cx, ObjectValue(*obj)); 1.244 + if (!JSObject::defineProperty(cx, proto, cx->names().constructor, 1.245 + objVal, JS_PropertyStub, JS_StrictPropertyStub, 0)) 1.246 + { 1.247 + return nullptr; 1.248 + } 1.249 + } 1.250 + 1.251 + return proto; 1.252 +} 1.253 + 1.254 +bool 1.255 +js::FunctionHasResolveHook(const JSAtomState &atomState, PropertyName *name) 1.256 +{ 1.257 + if (name == atomState.prototype || name == atomState.length || name == atomState.name) 1.258 + return true; 1.259 + 1.260 + for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) { 1.261 + const uint16_t offset = poisonPillProps[i]; 1.262 + 1.263 + if (name == AtomStateOffsetToName(atomState, offset)) 1.264 + return true; 1.265 + } 1.266 + 1.267 + return false; 1.268 +} 1.269 + 1.270 +bool 1.271 +js::fun_resolve(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp) 1.272 +{ 1.273 + if (!JSID_IS_ATOM(id)) 1.274 + return true; 1.275 + 1.276 + RootedFunction fun(cx, &obj->as<JSFunction>()); 1.277 + 1.278 + if (JSID_IS_ATOM(id, cx->names().prototype)) { 1.279 + /* 1.280 + * Built-in functions do not have a .prototype property per ECMA-262, 1.281 + * or (Object.prototype, Function.prototype, etc.) have that property 1.282 + * created eagerly. 1.283 + * 1.284 + * ES5 15.3.4: the non-native function object named Function.prototype 1.285 + * does not have a .prototype property. 1.286 + * 1.287 + * ES5 15.3.4.5: bound functions don't have a prototype property. The 1.288 + * isBuiltin() test covers this case because bound functions are native 1.289 + * (and thus built-in) functions by definition/construction. 1.290 + * 1.291 + * ES6 19.2.4.3: arrow functions also don't have a prototype property. 1.292 + */ 1.293 + if (fun->isBuiltin() || fun->isArrow() || fun->isFunctionPrototype()) 1.294 + return true; 1.295 + 1.296 + if (!ResolveInterpretedFunctionPrototype(cx, fun)) 1.297 + return false; 1.298 + objp.set(fun); 1.299 + return true; 1.300 + } 1.301 + 1.302 + if (JSID_IS_ATOM(id, cx->names().length) || JSID_IS_ATOM(id, cx->names().name)) { 1.303 + JS_ASSERT(!IsInternalFunctionObject(obj)); 1.304 + 1.305 + RootedValue v(cx); 1.306 + if (JSID_IS_ATOM(id, cx->names().length)) { 1.307 + if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) 1.308 + return false; 1.309 + uint16_t length = fun->hasScript() ? fun->nonLazyScript()->funLength() : 1.310 + fun->nargs() - fun->hasRest(); 1.311 + v.setInt32(length); 1.312 + } else { 1.313 + v.setString(fun->atom() == nullptr ? cx->runtime()->emptyString : fun->atom()); 1.314 + } 1.315 + 1.316 + if (!DefineNativeProperty(cx, fun, id, v, JS_PropertyStub, JS_StrictPropertyStub, 1.317 + JSPROP_PERMANENT | JSPROP_READONLY)) { 1.318 + return false; 1.319 + } 1.320 + objp.set(fun); 1.321 + return true; 1.322 + } 1.323 + 1.324 + for (unsigned i = 0; i < ArrayLength(poisonPillProps); i++) { 1.325 + const uint16_t offset = poisonPillProps[i]; 1.326 + 1.327 + if (JSID_IS_ATOM(id, AtomStateOffsetToName(cx->names(), offset))) { 1.328 + JS_ASSERT(!IsInternalFunctionObject(fun)); 1.329 + 1.330 + PropertyOp getter; 1.331 + StrictPropertyOp setter; 1.332 + unsigned attrs = JSPROP_PERMANENT | JSPROP_SHARED; 1.333 + if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) 1.334 + return false; 1.335 + if (fun->isInterpreted() ? fun->strict() : fun->isBoundFunction()) { 1.336 + JSObject *throwTypeError = fun->global().getThrowTypeError(); 1.337 + 1.338 + getter = CastAsPropertyOp(throwTypeError); 1.339 + setter = CastAsStrictPropertyOp(throwTypeError); 1.340 + attrs |= JSPROP_GETTER | JSPROP_SETTER; 1.341 + } else { 1.342 + getter = fun_getProperty; 1.343 + setter = JS_StrictPropertyStub; 1.344 + } 1.345 + 1.346 + if (!DefineNativeProperty(cx, fun, id, UndefinedHandleValue, getter, setter, attrs)) 1.347 + return false; 1.348 + objp.set(fun); 1.349 + return true; 1.350 + } 1.351 + } 1.352 + 1.353 + return true; 1.354 +} 1.355 + 1.356 +template<XDRMode mode> 1.357 +bool 1.358 +js::XDRInterpretedFunction(XDRState<mode> *xdr, HandleObject enclosingScope, HandleScript enclosingScript, 1.359 + MutableHandleObject objp) 1.360 +{ 1.361 + enum FirstWordFlag { 1.362 + HasAtom = 0x1, 1.363 + IsStarGenerator = 0x2, 1.364 + IsLazy = 0x4, 1.365 + HasSingletonType = 0x8 1.366 + }; 1.367 + 1.368 + /* NB: Keep this in sync with CloneFunctionAndScript. */ 1.369 + RootedAtom atom(xdr->cx()); 1.370 + uint32_t firstword = 0; /* bitmask of FirstWordFlag */ 1.371 + uint32_t flagsword = 0; /* word for argument count and fun->flags */ 1.372 + 1.373 + JSContext *cx = xdr->cx(); 1.374 + RootedFunction fun(cx); 1.375 + RootedScript script(cx); 1.376 + Rooted<LazyScript *> lazy(cx); 1.377 + 1.378 + if (mode == XDR_ENCODE) { 1.379 + fun = &objp->as<JSFunction>(); 1.380 + if (!fun->isInterpreted()) { 1.381 + JSAutoByteString funNameBytes; 1.382 + if (const char *name = GetFunctionNameBytes(cx, fun, &funNameBytes)) { 1.383 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.384 + JSMSG_NOT_SCRIPTED_FUNCTION, name); 1.385 + } 1.386 + return false; 1.387 + } 1.388 + 1.389 + if (fun->atom() || fun->hasGuessedAtom()) 1.390 + firstword |= HasAtom; 1.391 + 1.392 + if (fun->isStarGenerator()) 1.393 + firstword |= IsStarGenerator; 1.394 + 1.395 + if (fun->isInterpretedLazy()) { 1.396 + // This can only happen for re-lazified cloned functions, so this 1.397 + // does not apply to any JSFunction produced by the parser, only to 1.398 + // JSFunction created by the runtime. 1.399 + JS_ASSERT(!fun->lazyScript()->maybeScript()); 1.400 + 1.401 + // Encode a lazy script. 1.402 + firstword |= IsLazy; 1.403 + lazy = fun->lazyScript(); 1.404 + } else { 1.405 + // Encode the script. 1.406 + script = fun->nonLazyScript(); 1.407 + } 1.408 + 1.409 + if (fun->hasSingletonType()) 1.410 + firstword |= HasSingletonType; 1.411 + 1.412 + atom = fun->displayAtom(); 1.413 + flagsword = (fun->nargs() << 16) | fun->flags(); 1.414 + 1.415 + // The environment of any function which is not reused will always be 1.416 + // null, it is later defined when a function is cloned or reused to 1.417 + // mirror the scope chain. 1.418 + JS_ASSERT_IF(fun->hasSingletonType() && 1.419 + !((lazy && lazy->hasBeenCloned()) || (script && script->hasBeenCloned())), 1.420 + fun->environment() == nullptr); 1.421 + } 1.422 + 1.423 + if (!xdr->codeUint32(&firstword)) 1.424 + return false; 1.425 + 1.426 + if ((firstword & HasAtom) && !XDRAtom(xdr, &atom)) 1.427 + return false; 1.428 + if (!xdr->codeUint32(&flagsword)) 1.429 + return false; 1.430 + 1.431 + if (mode == XDR_DECODE) { 1.432 + JSObject *proto = nullptr; 1.433 + if (firstword & IsStarGenerator) { 1.434 + proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global()); 1.435 + if (!proto) 1.436 + return false; 1.437 + } 1.438 + 1.439 + gc::AllocKind allocKind = JSFunction::FinalizeKind; 1.440 + if (uint16_t(flagsword) & JSFunction::EXTENDED) 1.441 + allocKind = JSFunction::ExtendedFinalizeKind; 1.442 + fun = NewFunctionWithProto(cx, NullPtr(), nullptr, 0, JSFunction::INTERPRETED, 1.443 + /* parent = */ NullPtr(), NullPtr(), proto, 1.444 + allocKind, TenuredObject); 1.445 + if (!fun) 1.446 + return false; 1.447 + script = nullptr; 1.448 + } 1.449 + 1.450 + if (firstword & IsLazy) { 1.451 + if (!XDRLazyScript(xdr, enclosingScope, enclosingScript, fun, &lazy)) 1.452 + return false; 1.453 + } else { 1.454 + if (!XDRScript(xdr, enclosingScope, enclosingScript, fun, &script)) 1.455 + return false; 1.456 + } 1.457 + 1.458 + if (mode == XDR_DECODE) { 1.459 + fun->setArgCount(flagsword >> 16); 1.460 + fun->setFlags(uint16_t(flagsword)); 1.461 + fun->initAtom(atom); 1.462 + if (firstword & IsLazy) { 1.463 + fun->initLazyScript(lazy); 1.464 + } else { 1.465 + fun->initScript(script); 1.466 + script->setFunction(fun); 1.467 + JS_ASSERT(fun->nargs() == script->bindings.numArgs()); 1.468 + } 1.469 + 1.470 + bool singleton = firstword & HasSingletonType; 1.471 + if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton)) 1.472 + return false; 1.473 + objp.set(fun); 1.474 + } 1.475 + 1.476 + return true; 1.477 +} 1.478 + 1.479 +template bool 1.480 +js::XDRInterpretedFunction(XDRState<XDR_ENCODE> *, HandleObject, HandleScript, MutableHandleObject); 1.481 + 1.482 +template bool 1.483 +js::XDRInterpretedFunction(XDRState<XDR_DECODE> *, HandleObject, HandleScript, MutableHandleObject); 1.484 + 1.485 +JSObject * 1.486 +js::CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFunction srcFun) 1.487 +{ 1.488 + /* NB: Keep this in sync with XDRInterpretedFunction. */ 1.489 + JSObject *cloneProto = nullptr; 1.490 + if (srcFun->isStarGenerator()) { 1.491 + cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global()); 1.492 + if (!cloneProto) 1.493 + return nullptr; 1.494 + } 1.495 + 1.496 + gc::AllocKind allocKind = JSFunction::FinalizeKind; 1.497 + if (srcFun->isExtended()) 1.498 + allocKind = JSFunction::ExtendedFinalizeKind; 1.499 + RootedFunction clone(cx, NewFunctionWithProto(cx, NullPtr(), nullptr, 0, 1.500 + JSFunction::INTERPRETED, NullPtr(), NullPtr(), 1.501 + cloneProto, allocKind, TenuredObject)); 1.502 + if (!clone) 1.503 + return nullptr; 1.504 + 1.505 + RootedScript srcScript(cx, srcFun->getOrCreateScript(cx)); 1.506 + if (!srcScript) 1.507 + return nullptr; 1.508 + RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript)); 1.509 + if (!clonedScript) 1.510 + return nullptr; 1.511 + 1.512 + clone->setArgCount(srcFun->nargs()); 1.513 + clone->setFlags(srcFun->flags()); 1.514 + clone->initAtom(srcFun->displayAtom()); 1.515 + clone->initScript(clonedScript); 1.516 + clonedScript->setFunction(clone); 1.517 + if (!JSFunction::setTypeForScriptedFunction(cx, clone)) 1.518 + return nullptr; 1.519 + 1.520 + RootedScript cloneScript(cx, clone->nonLazyScript()); 1.521 + CallNewScriptHook(cx, cloneScript, clone); 1.522 + return clone; 1.523 +} 1.524 + 1.525 +/* 1.526 + * [[HasInstance]] internal method for Function objects: fetch the .prototype 1.527 + * property of its 'this' parameter, and walks the prototype chain of v (only 1.528 + * if v is an object) returning true if .prototype is found. 1.529 + */ 1.530 +static bool 1.531 +fun_hasInstance(JSContext *cx, HandleObject objArg, MutableHandleValue v, bool *bp) 1.532 +{ 1.533 + RootedObject obj(cx, objArg); 1.534 + 1.535 + while (obj->is<JSFunction>() && obj->isBoundFunction()) 1.536 + obj = obj->as<JSFunction>().getBoundFunctionTarget(); 1.537 + 1.538 + RootedValue pval(cx); 1.539 + if (!JSObject::getProperty(cx, obj, obj, cx->names().prototype, &pval)) 1.540 + return false; 1.541 + 1.542 + if (pval.isPrimitive()) { 1.543 + /* 1.544 + * Throw a runtime error if instanceof is called on a function that 1.545 + * has a non-object as its .prototype value. 1.546 + */ 1.547 + RootedValue val(cx, ObjectValue(*obj)); 1.548 + js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, js::NullPtr()); 1.549 + return false; 1.550 + } 1.551 + 1.552 + RootedObject pobj(cx, &pval.toObject()); 1.553 + bool isDelegate; 1.554 + if (!IsDelegate(cx, pobj, v, &isDelegate)) 1.555 + return false; 1.556 + *bp = isDelegate; 1.557 + return true; 1.558 +} 1.559 + 1.560 +inline void 1.561 +JSFunction::trace(JSTracer *trc) 1.562 +{ 1.563 + if (isExtended()) { 1.564 + MarkValueRange(trc, ArrayLength(toExtended()->extendedSlots), 1.565 + toExtended()->extendedSlots, "nativeReserved"); 1.566 + } 1.567 + 1.568 + if (atom_) 1.569 + MarkString(trc, &atom_, "atom"); 1.570 + 1.571 + if (isInterpreted()) { 1.572 + // Functions can be be marked as interpreted despite having no script 1.573 + // yet at some points when parsing, and can be lazy with no lazy script 1.574 + // for self-hosted code. 1.575 + if (hasScript() && u.i.s.script_) { 1.576 + // Functions can be relazified under the following conditions: 1.577 + // - their compartment isn't currently executing scripts or being 1.578 + // debugged 1.579 + // - they are not in the self-hosting compartment 1.580 + // - they aren't generators 1.581 + // - they don't have JIT code attached 1.582 + // - they haven't ever been inlined 1.583 + // - they don't have child functions 1.584 + // - they have information for un-lazifying them again later 1.585 + // This information can either be a LazyScript, or the name of a 1.586 + // self-hosted function which can be cloned over again. The latter 1.587 + // is stored in the first extended slot. 1.588 + if (IS_GC_MARKING_TRACER(trc) && !compartment()->hasBeenEntered() && 1.589 + !compartment()->debugMode() && !compartment()->isSelfHosting && 1.590 + u.i.s.script_->isRelazifiable() && (!isSelfHostedBuiltin() || isExtended())) 1.591 + { 1.592 + relazify(trc); 1.593 + } else { 1.594 + MarkScriptUnbarriered(trc, &u.i.s.script_, "script"); 1.595 + } 1.596 + } else if (isInterpretedLazy() && u.i.s.lazy_) { 1.597 + MarkLazyScriptUnbarriered(trc, &u.i.s.lazy_, "lazyScript"); 1.598 + } 1.599 + if (u.i.env_) 1.600 + MarkObjectUnbarriered(trc, &u.i.env_, "fun_callscope"); 1.601 + } 1.602 +} 1.603 + 1.604 +static void 1.605 +fun_trace(JSTracer *trc, JSObject *obj) 1.606 +{ 1.607 + obj->as<JSFunction>().trace(trc); 1.608 +} 1.609 + 1.610 +const Class JSFunction::class_ = { 1.611 + js_Function_str, 1.612 + JSCLASS_NEW_RESOLVE | JSCLASS_IMPLEMENTS_BARRIERS | 1.613 + JSCLASS_HAS_CACHED_PROTO(JSProto_Function), 1.614 + JS_PropertyStub, /* addProperty */ 1.615 + JS_DeletePropertyStub, /* delProperty */ 1.616 + JS_PropertyStub, /* getProperty */ 1.617 + JS_StrictPropertyStub, /* setProperty */ 1.618 + fun_enumerate, 1.619 + (JSResolveOp)js::fun_resolve, 1.620 + JS_ConvertStub, 1.621 + nullptr, /* finalize */ 1.622 + nullptr, /* call */ 1.623 + fun_hasInstance, 1.624 + nullptr, /* construct */ 1.625 + fun_trace 1.626 +}; 1.627 + 1.628 +const Class* const js::FunctionClassPtr = &JSFunction::class_; 1.629 + 1.630 +/* Find the body of a function (not including braces). */ 1.631 +bool 1.632 +js::FindBody(JSContext *cx, HandleFunction fun, ConstTwoByteChars chars, size_t length, 1.633 + size_t *bodyStart, size_t *bodyEnd) 1.634 +{ 1.635 + // We don't need principals, since those are only used for error reporting. 1.636 + CompileOptions options(cx); 1.637 + options.setFileAndLine("internal-findBody", 0); 1.638 + 1.639 + // For asm.js modules, there's no script. 1.640 + if (fun->hasScript()) 1.641 + options.setVersion(fun->nonLazyScript()->getVersion()); 1.642 + 1.643 + AutoKeepAtoms keepAtoms(cx->perThreadData); 1.644 + TokenStream ts(cx, options, chars.get(), length, nullptr); 1.645 + int nest = 0; 1.646 + bool onward = true; 1.647 + // Skip arguments list. 1.648 + do { 1.649 + switch (ts.getToken()) { 1.650 + case TOK_NAME: 1.651 + case TOK_YIELD: 1.652 + if (nest == 0) 1.653 + onward = false; 1.654 + break; 1.655 + case TOK_LP: 1.656 + nest++; 1.657 + break; 1.658 + case TOK_RP: 1.659 + if (--nest == 0) 1.660 + onward = false; 1.661 + break; 1.662 + case TOK_ERROR: 1.663 + // Must be memory. 1.664 + return false; 1.665 + default: 1.666 + break; 1.667 + } 1.668 + } while (onward); 1.669 + TokenKind tt = ts.getToken(); 1.670 + if (tt == TOK_ARROW) 1.671 + tt = ts.getToken(); 1.672 + if (tt == TOK_ERROR) 1.673 + return false; 1.674 + bool braced = tt == TOK_LC; 1.675 + JS_ASSERT_IF(fun->isExprClosure(), !braced); 1.676 + *bodyStart = ts.currentToken().pos.begin; 1.677 + if (braced) 1.678 + *bodyStart += 1; 1.679 + ConstTwoByteChars end(chars.get() + length, chars.get(), length); 1.680 + if (end[-1] == '}') { 1.681 + end--; 1.682 + } else { 1.683 + JS_ASSERT(!braced); 1.684 + for (; unicode::IsSpaceOrBOM2(end[-1]); end--) 1.685 + ; 1.686 + } 1.687 + *bodyEnd = end - chars; 1.688 + JS_ASSERT(*bodyStart <= *bodyEnd); 1.689 + return true; 1.690 +} 1.691 + 1.692 +JSString * 1.693 +js::FunctionToString(JSContext *cx, HandleFunction fun, bool bodyOnly, bool lambdaParen) 1.694 +{ 1.695 + if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) 1.696 + return nullptr; 1.697 + 1.698 + if (IsAsmJSModule(fun)) 1.699 + return AsmJSModuleToString(cx, fun, !lambdaParen); 1.700 + if (IsAsmJSFunction(fun)) 1.701 + return AsmJSFunctionToString(cx, fun); 1.702 + 1.703 + StringBuffer out(cx); 1.704 + RootedScript script(cx); 1.705 + 1.706 + if (fun->hasScript()) { 1.707 + script = fun->nonLazyScript(); 1.708 + if (script->isGeneratorExp()) { 1.709 + if ((!bodyOnly && !out.append("function genexp() {")) || 1.710 + !out.append("\n [generator expression]\n") || 1.711 + (!bodyOnly && !out.append("}"))) 1.712 + { 1.713 + return nullptr; 1.714 + } 1.715 + return out.finishString(); 1.716 + } 1.717 + } 1.718 + if (!bodyOnly) { 1.719 + // If we're not in pretty mode, put parentheses around lambda functions. 1.720 + if (fun->isInterpreted() && !lambdaParen && fun->isLambda() && !fun->isArrow()) { 1.721 + if (!out.append("(")) 1.722 + return nullptr; 1.723 + } 1.724 + if (!fun->isArrow()) { 1.725 + if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function "))) 1.726 + return nullptr; 1.727 + } 1.728 + if (fun->atom()) { 1.729 + if (!out.append(fun->atom())) 1.730 + return nullptr; 1.731 + } 1.732 + } 1.733 + bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); 1.734 + if (haveSource && !script->scriptSource()->hasSourceData() && 1.735 + !JSScript::loadSource(cx, script->scriptSource(), &haveSource)) 1.736 + { 1.737 + return nullptr; 1.738 + } 1.739 + if (haveSource) { 1.740 + RootedString srcStr(cx, script->sourceData(cx)); 1.741 + if (!srcStr) 1.742 + return nullptr; 1.743 + Rooted<JSFlatString *> src(cx, srcStr->ensureFlat(cx)); 1.744 + if (!src) 1.745 + return nullptr; 1.746 + 1.747 + ConstTwoByteChars chars(src->chars(), src->length()); 1.748 + bool exprBody = fun->isExprClosure(); 1.749 + 1.750 + // The source data for functions created by calling the Function 1.751 + // constructor is only the function's body. This depends on the fact, 1.752 + // asserted below, that in Function("function f() {}"), the inner 1.753 + // function's sourceStart points to the '(', not the 'f'. 1.754 + bool funCon = !fun->isArrow() && 1.755 + script->sourceStart() == 0 && 1.756 + script->sourceEnd() == script->scriptSource()->length() && 1.757 + script->scriptSource()->argumentsNotIncluded(); 1.758 + 1.759 + // Functions created with the constructor can't be arrow functions or 1.760 + // expression closures. 1.761 + JS_ASSERT_IF(funCon, !fun->isArrow()); 1.762 + JS_ASSERT_IF(funCon, !exprBody); 1.763 + JS_ASSERT_IF(!funCon && !fun->isArrow(), src->length() > 0 && chars[0] == '('); 1.764 + 1.765 + // If a function inherits strict mode by having scopes above it that 1.766 + // have "use strict", we insert "use strict" into the body of the 1.767 + // function. This ensures that if the result of toString is evaled, the 1.768 + // resulting function will have the same semantics. 1.769 + bool addUseStrict = script->strict() && !script->explicitUseStrict() && !fun->isArrow(); 1.770 + 1.771 + bool buildBody = funCon && !bodyOnly; 1.772 + if (buildBody) { 1.773 + // This function was created with the Function constructor. We don't 1.774 + // have source for the arguments, so we have to generate that. Part 1.775 + // of bug 755821 should be cobbling the arguments passed into the 1.776 + // Function constructor into the source string. 1.777 + if (!out.append("(")) 1.778 + return nullptr; 1.779 + 1.780 + // Fish out the argument names. 1.781 + BindingVector *localNames = cx->new_<BindingVector>(cx); 1.782 + ScopedJSDeletePtr<BindingVector> freeNames(localNames); 1.783 + if (!FillBindingVector(script, localNames)) 1.784 + return nullptr; 1.785 + for (unsigned i = 0; i < fun->nargs(); i++) { 1.786 + if ((i && !out.append(", ")) || 1.787 + (i == unsigned(fun->nargs() - 1) && fun->hasRest() && !out.append("...")) || 1.788 + !out.append((*localNames)[i].name())) { 1.789 + return nullptr; 1.790 + } 1.791 + } 1.792 + if (!out.append(") {\n")) 1.793 + return nullptr; 1.794 + } 1.795 + if ((bodyOnly && !funCon) || addUseStrict) { 1.796 + // We need to get at the body either because we're only supposed to 1.797 + // return the body or we need to insert "use strict" into the body. 1.798 + size_t bodyStart = 0, bodyEnd; 1.799 + 1.800 + // If the function is defined in the Function constructor, we 1.801 + // already have a body. 1.802 + if (!funCon) { 1.803 + JS_ASSERT(!buildBody); 1.804 + if (!FindBody(cx, fun, chars, src->length(), &bodyStart, &bodyEnd)) 1.805 + return nullptr; 1.806 + } else { 1.807 + bodyEnd = src->length(); 1.808 + } 1.809 + 1.810 + if (addUseStrict) { 1.811 + // Output source up to beginning of body. 1.812 + if (!out.append(chars, bodyStart)) 1.813 + return nullptr; 1.814 + if (exprBody) { 1.815 + // We can't insert a statement into a function with an 1.816 + // expression body. Do what the decompiler did, and insert a 1.817 + // comment. 1.818 + if (!out.append("/* use strict */ ")) 1.819 + return nullptr; 1.820 + } else { 1.821 + if (!out.append("\n\"use strict\";\n")) 1.822 + return nullptr; 1.823 + } 1.824 + } 1.825 + 1.826 + // Output just the body (for bodyOnly) or the body and possibly 1.827 + // closing braces (for addUseStrict). 1.828 + size_t dependentEnd = bodyOnly ? bodyEnd : src->length(); 1.829 + if (!out.append(chars + bodyStart, dependentEnd - bodyStart)) 1.830 + return nullptr; 1.831 + } else { 1.832 + if (!out.append(src)) 1.833 + return nullptr; 1.834 + } 1.835 + if (buildBody) { 1.836 + if (!out.append("\n}")) 1.837 + return nullptr; 1.838 + } 1.839 + if (bodyOnly) { 1.840 + // Slap a semicolon on the end of functions with an expression body. 1.841 + if (exprBody && !out.append(";")) 1.842 + return nullptr; 1.843 + } else if (!lambdaParen && fun->isLambda() && !fun->isArrow()) { 1.844 + if (!out.append(")")) 1.845 + return nullptr; 1.846 + } 1.847 + } else if (fun->isInterpreted() && !fun->isSelfHostedBuiltin()) { 1.848 + if ((!bodyOnly && !out.append("() {\n ")) || 1.849 + !out.append("[sourceless code]") || 1.850 + (!bodyOnly && !out.append("\n}"))) 1.851 + return nullptr; 1.852 + if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")")) 1.853 + return nullptr; 1.854 + } else { 1.855 + JS_ASSERT(!fun->isExprClosure()); 1.856 + 1.857 + if ((!bodyOnly && !out.append("() {\n ")) 1.858 + || !out.append("[native code]") 1.859 + || (!bodyOnly && !out.append("\n}"))) 1.860 + { 1.861 + return nullptr; 1.862 + } 1.863 + } 1.864 + return out.finishString(); 1.865 +} 1.866 + 1.867 +JSString * 1.868 +fun_toStringHelper(JSContext *cx, HandleObject obj, unsigned indent) 1.869 +{ 1.870 + if (!obj->is<JSFunction>()) { 1.871 + if (obj->is<ProxyObject>()) 1.872 + return Proxy::fun_toString(cx, obj, indent); 1.873 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.874 + JSMSG_INCOMPATIBLE_PROTO, 1.875 + js_Function_str, js_toString_str, 1.876 + "object"); 1.877 + return nullptr; 1.878 + } 1.879 + 1.880 + RootedFunction fun(cx, &obj->as<JSFunction>()); 1.881 + return FunctionToString(cx, fun, false, indent != JS_DONT_PRETTY_PRINT); 1.882 +} 1.883 + 1.884 +static bool 1.885 +fun_toString(JSContext *cx, unsigned argc, Value *vp) 1.886 +{ 1.887 + CallArgs args = CallArgsFromVp(argc, vp); 1.888 + JS_ASSERT(IsFunctionObject(args.calleev())); 1.889 + 1.890 + uint32_t indent = 0; 1.891 + 1.892 + if (args.length() != 0 && !ToUint32(cx, args[0], &indent)) 1.893 + return false; 1.894 + 1.895 + RootedObject obj(cx, ToObject(cx, args.thisv())); 1.896 + if (!obj) 1.897 + return false; 1.898 + 1.899 + RootedString str(cx, fun_toStringHelper(cx, obj, indent)); 1.900 + if (!str) 1.901 + return false; 1.902 + 1.903 + args.rval().setString(str); 1.904 + return true; 1.905 +} 1.906 + 1.907 +#if JS_HAS_TOSOURCE 1.908 +static bool 1.909 +fun_toSource(JSContext *cx, unsigned argc, Value *vp) 1.910 +{ 1.911 + CallArgs args = CallArgsFromVp(argc, vp); 1.912 + JS_ASSERT(IsFunctionObject(args.calleev())); 1.913 + 1.914 + RootedObject obj(cx, ToObject(cx, args.thisv())); 1.915 + if (!obj) 1.916 + return false; 1.917 + 1.918 + RootedString str(cx); 1.919 + if (obj->isCallable()) 1.920 + str = fun_toStringHelper(cx, obj, JS_DONT_PRETTY_PRINT); 1.921 + else 1.922 + str = ObjectToSource(cx, obj); 1.923 + 1.924 + if (!str) 1.925 + return false; 1.926 + args.rval().setString(str); 1.927 + return true; 1.928 +} 1.929 +#endif 1.930 + 1.931 +bool 1.932 +js_fun_call(JSContext *cx, unsigned argc, Value *vp) 1.933 +{ 1.934 + CallArgs args = CallArgsFromVp(argc, vp); 1.935 + 1.936 + HandleValue fval = args.thisv(); 1.937 + if (!js_IsCallable(fval)) { 1.938 + ReportIncompatibleMethod(cx, args, &JSFunction::class_); 1.939 + return false; 1.940 + } 1.941 + 1.942 + args.setCallee(fval); 1.943 + args.setThis(args.get(0)); 1.944 + 1.945 + if (args.length() > 0) { 1.946 + for (size_t i = 0; i < args.length() - 1; i++) 1.947 + args[i].set(args[i + 1]); 1.948 + args = CallArgsFromVp(args.length() - 1, vp); 1.949 + } 1.950 + 1.951 + return Invoke(cx, args); 1.952 +} 1.953 + 1.954 +// ES5 15.3.4.3 1.955 +bool 1.956 +js_fun_apply(JSContext *cx, unsigned argc, Value *vp) 1.957 +{ 1.958 + CallArgs args = CallArgsFromVp(argc, vp); 1.959 + 1.960 + // Step 1. 1.961 + HandleValue fval = args.thisv(); 1.962 + if (!js_IsCallable(fval)) { 1.963 + ReportIncompatibleMethod(cx, args, &JSFunction::class_); 1.964 + return false; 1.965 + } 1.966 + 1.967 + // Step 2. 1.968 + if (args.length() < 2 || args[1].isNullOrUndefined()) 1.969 + return js_fun_call(cx, (args.length() > 0) ? 1 : 0, vp); 1.970 + 1.971 + InvokeArgs args2(cx); 1.972 + 1.973 + // A JS_OPTIMIZED_ARGUMENTS magic value means that 'arguments' flows into 1.974 + // this apply call from a scripted caller and, as an optimization, we've 1.975 + // avoided creating it since apply can simply pull the argument values from 1.976 + // the calling frame (which we must do now). 1.977 + if (args[1].isMagic(JS_OPTIMIZED_ARGUMENTS)) { 1.978 + // Step 3-6. 1.979 + ScriptFrameIter iter(cx); 1.980 + JS_ASSERT(iter.numActualArgs() <= ARGS_LENGTH_MAX); 1.981 + if (!args2.init(iter.numActualArgs())) 1.982 + return false; 1.983 + 1.984 + args2.setCallee(fval); 1.985 + args2.setThis(args[0]); 1.986 + 1.987 + // Steps 7-8. 1.988 + iter.unaliasedForEachActual(cx, CopyTo(args2.array())); 1.989 + } else { 1.990 + // Step 3. 1.991 + if (!args[1].isObject()) { 1.992 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, 1.993 + JSMSG_BAD_APPLY_ARGS, js_apply_str); 1.994 + return false; 1.995 + } 1.996 + 1.997 + // Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in 1.998 + // original version of ES5). 1.999 + RootedObject aobj(cx, &args[1].toObject()); 1.1000 + uint32_t length; 1.1001 + if (!GetLengthProperty(cx, aobj, &length)) 1.1002 + return false; 1.1003 + 1.1004 + // Step 6. 1.1005 + if (length > ARGS_LENGTH_MAX) { 1.1006 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_TOO_MANY_FUN_APPLY_ARGS); 1.1007 + return false; 1.1008 + } 1.1009 + 1.1010 + if (!args2.init(length)) 1.1011 + return false; 1.1012 + 1.1013 + // Push fval, obj, and aobj's elements as args. 1.1014 + args2.setCallee(fval); 1.1015 + args2.setThis(args[0]); 1.1016 + 1.1017 + // Steps 7-8. 1.1018 + if (!GetElements(cx, aobj, length, args2.array())) 1.1019 + return false; 1.1020 + } 1.1021 + 1.1022 + // Step 9. 1.1023 + if (!Invoke(cx, args2)) 1.1024 + return false; 1.1025 + 1.1026 + args.rval().set(args2.rval()); 1.1027 + return true; 1.1028 +} 1.1029 + 1.1030 +static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 0; 1.1031 +static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 1; 1.1032 + 1.1033 +static const uint32_t BOUND_FUNCTION_RESERVED_SLOTS = 2; 1.1034 + 1.1035 +inline bool 1.1036 +JSFunction::initBoundFunction(JSContext *cx, HandleValue thisArg, 1.1037 + const Value *args, unsigned argslen) 1.1038 +{ 1.1039 + RootedFunction self(cx, this); 1.1040 + 1.1041 + /* 1.1042 + * Convert to a dictionary to set the BOUND_FUNCTION flag and increase 1.1043 + * the slot span to cover the arguments and additional slots for the 'this' 1.1044 + * value and arguments count. 1.1045 + */ 1.1046 + if (!self->toDictionaryMode(cx)) 1.1047 + return false; 1.1048 + 1.1049 + if (!self->setFlag(cx, BaseShape::BOUND_FUNCTION)) 1.1050 + return false; 1.1051 + 1.1052 + if (!JSObject::setSlotSpan(cx, self, BOUND_FUNCTION_RESERVED_SLOTS + argslen)) 1.1053 + return false; 1.1054 + 1.1055 + self->setSlot(JSSLOT_BOUND_FUNCTION_THIS, thisArg); 1.1056 + self->setSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT, PrivateUint32Value(argslen)); 1.1057 + 1.1058 + self->initSlotRange(BOUND_FUNCTION_RESERVED_SLOTS, args, argslen); 1.1059 + 1.1060 + return true; 1.1061 +} 1.1062 + 1.1063 +const js::Value & 1.1064 +JSFunction::getBoundFunctionThis() const 1.1065 +{ 1.1066 + JS_ASSERT(isBoundFunction()); 1.1067 + 1.1068 + return getSlot(JSSLOT_BOUND_FUNCTION_THIS); 1.1069 +} 1.1070 + 1.1071 +const js::Value & 1.1072 +JSFunction::getBoundFunctionArgument(unsigned which) const 1.1073 +{ 1.1074 + JS_ASSERT(isBoundFunction()); 1.1075 + JS_ASSERT(which < getBoundFunctionArgumentCount()); 1.1076 + 1.1077 + return getSlot(BOUND_FUNCTION_RESERVED_SLOTS + which); 1.1078 +} 1.1079 + 1.1080 +size_t 1.1081 +JSFunction::getBoundFunctionArgumentCount() const 1.1082 +{ 1.1083 + JS_ASSERT(isBoundFunction()); 1.1084 + 1.1085 + return getSlot(JSSLOT_BOUND_FUNCTION_ARGS_COUNT).toPrivateUint32(); 1.1086 +} 1.1087 + 1.1088 +/* static */ bool 1.1089 +JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFunction fun) 1.1090 +{ 1.1091 + JS_ASSERT(fun->isInterpretedLazy()); 1.1092 + 1.1093 + Rooted<LazyScript*> lazy(cx, fun->lazyScriptOrNull()); 1.1094 + if (lazy) { 1.1095 + // Trigger a pre barrier on the lazy script being overwritten. 1.1096 + if (cx->zone()->needsBarrier()) 1.1097 + LazyScript::writeBarrierPre(lazy); 1.1098 + 1.1099 + // Suppress GC for now although we should be able to remove this by 1.1100 + // making 'lazy' a Rooted<LazyScript*> (which requires adding a 1.1101 + // THING_ROOT_LAZY_SCRIPT). 1.1102 + AutoSuppressGC suppressGC(cx); 1.1103 + 1.1104 + RootedScript script(cx, lazy->maybeScript()); 1.1105 + 1.1106 + if (script) { 1.1107 + fun->setUnlazifiedScript(script); 1.1108 + // Remember the lazy script on the compiled script, so it can be 1.1109 + // stored on the function again in case of re-lazification. 1.1110 + // Only functions without inner functions are re-lazified. 1.1111 + if (!lazy->numInnerFunctions()) 1.1112 + script->setLazyScript(lazy); 1.1113 + return true; 1.1114 + } 1.1115 + 1.1116 + if (fun != lazy->functionNonDelazifying()) { 1.1117 + if (!lazy->functionDelazifying(cx)) 1.1118 + return false; 1.1119 + script = lazy->functionNonDelazifying()->nonLazyScript(); 1.1120 + if (!script) 1.1121 + return false; 1.1122 + 1.1123 + fun->setUnlazifiedScript(script); 1.1124 + return true; 1.1125 + } 1.1126 + 1.1127 + // Lazy script caching is only supported for leaf functions. If a 1.1128 + // script with inner functions was returned by the cache, those inner 1.1129 + // functions would be delazified when deep cloning the script, even if 1.1130 + // they have never executed. 1.1131 + // 1.1132 + // Additionally, the lazy script cache is not used during incremental 1.1133 + // GCs, to avoid resurrecting dead scripts after incremental sweeping 1.1134 + // has started. 1.1135 + if (!lazy->numInnerFunctions() && !JS::IsIncrementalGCInProgress(cx->runtime())) { 1.1136 + LazyScriptCache::Lookup lookup(cx, lazy); 1.1137 + cx->runtime()->lazyScriptCache.lookup(lookup, script.address()); 1.1138 + } 1.1139 + 1.1140 + if (script) { 1.1141 + RootedObject enclosingScope(cx, lazy->enclosingScope()); 1.1142 + RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script)); 1.1143 + if (!clonedScript) 1.1144 + return false; 1.1145 + 1.1146 + clonedScript->setSourceObject(lazy->sourceObject()); 1.1147 + 1.1148 + fun->initAtom(script->functionNonDelazifying()->displayAtom()); 1.1149 + clonedScript->setFunction(fun); 1.1150 + 1.1151 + fun->setUnlazifiedScript(clonedScript); 1.1152 + 1.1153 + CallNewScriptHook(cx, clonedScript, fun); 1.1154 + 1.1155 + if (!lazy->maybeScript()) 1.1156 + lazy->initScript(clonedScript); 1.1157 + return true; 1.1158 + } 1.1159 + 1.1160 + JS_ASSERT(lazy->source()->hasSourceData()); 1.1161 + 1.1162 + // Parse and compile the script from source. 1.1163 + SourceDataCache::AutoHoldEntry holder; 1.1164 + const jschar *chars = lazy->source()->chars(cx, holder); 1.1165 + if (!chars) 1.1166 + return false; 1.1167 + 1.1168 + const jschar *lazyStart = chars + lazy->begin(); 1.1169 + size_t lazyLength = lazy->end() - lazy->begin(); 1.1170 + 1.1171 + if (!frontend::CompileLazyFunction(cx, lazy, lazyStart, lazyLength)) 1.1172 + return false; 1.1173 + 1.1174 + script = fun->nonLazyScript(); 1.1175 + 1.1176 + // Remember the compiled script on the lazy script itself, in case 1.1177 + // there are clones of the function still pointing to the lazy script. 1.1178 + if (!lazy->maybeScript()) 1.1179 + lazy->initScript(script); 1.1180 + 1.1181 + // Try to insert the newly compiled script into the lazy script cache. 1.1182 + if (!lazy->numInnerFunctions()) { 1.1183 + // A script's starting column isn't set by the bytecode emitter, so 1.1184 + // specify this from the lazy script so that if an identical lazy 1.1185 + // script is encountered later a match can be determined. 1.1186 + script->setColumn(lazy->column()); 1.1187 + 1.1188 + LazyScriptCache::Lookup lookup(cx, lazy); 1.1189 + cx->runtime()->lazyScriptCache.insert(lookup, script); 1.1190 + 1.1191 + // Remember the lazy script on the compiled script, so it can be 1.1192 + // stored on the function again in case of re-lazification. 1.1193 + // Only functions without inner functions are re-lazified. 1.1194 + script->setLazyScript(lazy); 1.1195 + } 1.1196 + return true; 1.1197 + } 1.1198 + 1.1199 + /* Lazily cloned self-hosted script. */ 1.1200 + JS_ASSERT(fun->isSelfHostedBuiltin()); 1.1201 + RootedAtom funAtom(cx, &fun->getExtendedSlot(0).toString()->asAtom()); 1.1202 + if (!funAtom) 1.1203 + return false; 1.1204 + Rooted<PropertyName *> funName(cx, funAtom->asPropertyName()); 1.1205 + return cx->runtime()->cloneSelfHostedFunctionScript(cx, funName, fun); 1.1206 +} 1.1207 + 1.1208 +void 1.1209 +JSFunction::relazify(JSTracer *trc) 1.1210 +{ 1.1211 + JSScript *script = nonLazyScript(); 1.1212 + JS_ASSERT(script->isRelazifiable()); 1.1213 + JS_ASSERT(!compartment()->hasBeenEntered()); 1.1214 + JS_ASSERT(!compartment()->debugMode()); 1.1215 + 1.1216 + // If the script's canonical function isn't lazy, we have to mark the 1.1217 + // script. Otherwise, the following scenario would leave it unmarked 1.1218 + // and cause it to be swept while a function is still expecting it to be 1.1219 + // valid: 1.1220 + // 1. an incremental GC slice causes the canonical function to relazify 1.1221 + // 2. a clone is used and delazifies the canonical function 1.1222 + // 3. another GC slice causes the clone to relazify 1.1223 + // The result is that no function marks the script, but the canonical 1.1224 + // function expects it to be valid. 1.1225 + if (script->functionNonDelazifying()->hasScript()) 1.1226 + MarkScriptUnbarriered(trc, &u.i.s.script_, "script"); 1.1227 + 1.1228 + flags_ &= ~INTERPRETED; 1.1229 + flags_ |= INTERPRETED_LAZY; 1.1230 + LazyScript *lazy = script->maybeLazyScript(); 1.1231 + u.i.s.lazy_ = lazy; 1.1232 + if (lazy) { 1.1233 + JS_ASSERT(!isSelfHostedBuiltin()); 1.1234 + // If this is the script stored in the lazy script to be cloned 1.1235 + // for un-lazifying other functions, reset it so the script can 1.1236 + // be freed. 1.1237 + if (lazy->maybeScript() == script) 1.1238 + lazy->resetScript(); 1.1239 + MarkLazyScriptUnbarriered(trc, &u.i.s.lazy_, "lazyScript"); 1.1240 + } else { 1.1241 + JS_ASSERT(isSelfHostedBuiltin()); 1.1242 + JS_ASSERT(isExtended()); 1.1243 + JS_ASSERT(getExtendedSlot(0).toString()->isAtom()); 1.1244 + } 1.1245 +} 1.1246 + 1.1247 +/* ES5 15.3.4.5.1 and 15.3.4.5.2. */ 1.1248 +bool 1.1249 +js::CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp) 1.1250 +{ 1.1251 + CallArgs args = CallArgsFromVp(argc, vp); 1.1252 + RootedFunction fun(cx, &args.callee().as<JSFunction>()); 1.1253 + JS_ASSERT(fun->isBoundFunction()); 1.1254 + 1.1255 + /* 15.3.4.5.1 step 1, 15.3.4.5.2 step 3. */ 1.1256 + unsigned argslen = fun->getBoundFunctionArgumentCount(); 1.1257 + 1.1258 + if (args.length() + argslen > ARGS_LENGTH_MAX) { 1.1259 + js_ReportAllocationOverflow(cx); 1.1260 + return false; 1.1261 + } 1.1262 + 1.1263 + /* 15.3.4.5.1 step 3, 15.3.4.5.2 step 1. */ 1.1264 + RootedObject target(cx, fun->getBoundFunctionTarget()); 1.1265 + 1.1266 + /* 15.3.4.5.1 step 2. */ 1.1267 + const Value &boundThis = fun->getBoundFunctionThis(); 1.1268 + 1.1269 + InvokeArgs invokeArgs(cx); 1.1270 + if (!invokeArgs.init(args.length() + argslen)) 1.1271 + return false; 1.1272 + 1.1273 + /* 15.3.4.5.1, 15.3.4.5.2 step 4. */ 1.1274 + for (unsigned i = 0; i < argslen; i++) 1.1275 + invokeArgs[i].set(fun->getBoundFunctionArgument(i)); 1.1276 + PodCopy(invokeArgs.array() + argslen, vp + 2, args.length()); 1.1277 + 1.1278 + /* 15.3.4.5.1, 15.3.4.5.2 step 5. */ 1.1279 + invokeArgs.setCallee(ObjectValue(*target)); 1.1280 + 1.1281 + bool constructing = args.isConstructing(); 1.1282 + if (!constructing) 1.1283 + invokeArgs.setThis(boundThis); 1.1284 + 1.1285 + if (constructing ? !InvokeConstructor(cx, invokeArgs) : !Invoke(cx, invokeArgs)) 1.1286 + return false; 1.1287 + 1.1288 + args.rval().set(invokeArgs.rval()); 1.1289 + return true; 1.1290 +} 1.1291 + 1.1292 +static bool 1.1293 +fun_isGenerator(JSContext *cx, unsigned argc, Value *vp) 1.1294 +{ 1.1295 + CallArgs args = CallArgsFromVp(argc, vp); 1.1296 + JSFunction *fun; 1.1297 + if (!IsFunctionObject(args.thisv(), &fun)) { 1.1298 + args.rval().setBoolean(false); 1.1299 + return true; 1.1300 + } 1.1301 + 1.1302 + args.rval().setBoolean(fun->isGenerator()); 1.1303 + return true; 1.1304 +} 1.1305 + 1.1306 +/* ES5 15.3.4.5. */ 1.1307 +static bool 1.1308 +fun_bind(JSContext *cx, unsigned argc, Value *vp) 1.1309 +{ 1.1310 + CallArgs args = CallArgsFromVp(argc, vp); 1.1311 + 1.1312 + /* Step 1. */ 1.1313 + Value thisv = args.thisv(); 1.1314 + 1.1315 + /* Step 2. */ 1.1316 + if (!js_IsCallable(thisv)) { 1.1317 + ReportIncompatibleMethod(cx, args, &JSFunction::class_); 1.1318 + return false; 1.1319 + } 1.1320 + 1.1321 + /* Step 3. */ 1.1322 + Value *boundArgs = nullptr; 1.1323 + unsigned argslen = 0; 1.1324 + if (args.length() > 1) { 1.1325 + boundArgs = args.array() + 1; 1.1326 + argslen = args.length() - 1; 1.1327 + } 1.1328 + 1.1329 + /* Steps 7-9. */ 1.1330 + RootedValue thisArg(cx, args.length() >= 1 ? args[0] : UndefinedValue()); 1.1331 + RootedObject target(cx, &thisv.toObject()); 1.1332 + JSObject *boundFunction = js_fun_bind(cx, target, thisArg, boundArgs, argslen); 1.1333 + if (!boundFunction) 1.1334 + return false; 1.1335 + 1.1336 + /* Step 22. */ 1.1337 + args.rval().setObject(*boundFunction); 1.1338 + return true; 1.1339 +} 1.1340 + 1.1341 +JSObject* 1.1342 +js_fun_bind(JSContext *cx, HandleObject target, HandleValue thisArg, 1.1343 + Value *boundArgs, unsigned argslen) 1.1344 +{ 1.1345 + /* Steps 15-16. */ 1.1346 + unsigned length = 0; 1.1347 + if (target->is<JSFunction>()) { 1.1348 + unsigned nargs = target->as<JSFunction>().nargs(); 1.1349 + if (nargs > argslen) 1.1350 + length = nargs - argslen; 1.1351 + } 1.1352 + 1.1353 + /* Step 4-6, 10-11. */ 1.1354 + RootedAtom name(cx, target->is<JSFunction>() ? target->as<JSFunction>().atom() : nullptr); 1.1355 + 1.1356 + RootedObject funobj(cx, NewFunction(cx, js::NullPtr(), CallOrConstructBoundFunction, length, 1.1357 + JSFunction::NATIVE_CTOR, target, name)); 1.1358 + if (!funobj) 1.1359 + return nullptr; 1.1360 + 1.1361 + /* NB: Bound functions abuse |parent| to store their target. */ 1.1362 + if (!JSObject::setParent(cx, funobj, target)) 1.1363 + return nullptr; 1.1364 + 1.1365 + if (!funobj->as<JSFunction>().initBoundFunction(cx, thisArg, boundArgs, argslen)) 1.1366 + return nullptr; 1.1367 + 1.1368 + /* Steps 17, 19-21 are handled by fun_resolve. */ 1.1369 + /* Step 18 is the default for new functions. */ 1.1370 + return funobj; 1.1371 +} 1.1372 + 1.1373 +/* 1.1374 + * Report "malformed formal parameter" iff no illegal char or similar scanner 1.1375 + * error was already reported. 1.1376 + */ 1.1377 +static bool 1.1378 +OnBadFormal(JSContext *cx, TokenKind tt) 1.1379 +{ 1.1380 + if (tt != TOK_ERROR) 1.1381 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_FORMAL); 1.1382 + else 1.1383 + JS_ASSERT(cx->isExceptionPending()); 1.1384 + return false; 1.1385 +} 1.1386 + 1.1387 +const JSFunctionSpec js::function_methods[] = { 1.1388 +#if JS_HAS_TOSOURCE 1.1389 + JS_FN(js_toSource_str, fun_toSource, 0,0), 1.1390 +#endif 1.1391 + JS_FN(js_toString_str, fun_toString, 0,0), 1.1392 + JS_FN(js_apply_str, js_fun_apply, 2,0), 1.1393 + JS_FN(js_call_str, js_fun_call, 1,0), 1.1394 + JS_FN("bind", fun_bind, 1,0), 1.1395 + JS_FN("isGenerator", fun_isGenerator,0,0), 1.1396 + JS_FS_END 1.1397 +}; 1.1398 + 1.1399 +static bool 1.1400 +FunctionConstructor(JSContext *cx, unsigned argc, Value *vp, GeneratorKind generatorKind) 1.1401 +{ 1.1402 + CallArgs args = CallArgsFromVp(argc, vp); 1.1403 + RootedString arg(cx); // used multiple times below 1.1404 + 1.1405 + /* Block this call if security callbacks forbid it. */ 1.1406 + Rooted<GlobalObject*> global(cx, &args.callee().global()); 1.1407 + if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) { 1.1408 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION); 1.1409 + return false; 1.1410 + } 1.1411 + 1.1412 + AutoKeepAtoms keepAtoms(cx->perThreadData); 1.1413 + AutoNameVector formals(cx); 1.1414 + 1.1415 + bool hasRest = false; 1.1416 + 1.1417 + bool isStarGenerator = generatorKind == StarGenerator; 1.1418 + JS_ASSERT(generatorKind != LegacyGenerator); 1.1419 + 1.1420 + RootedScript maybeScript(cx); 1.1421 + const char *filename; 1.1422 + unsigned lineno; 1.1423 + JSPrincipals *originPrincipals; 1.1424 + uint32_t pcOffset; 1.1425 + DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, &pcOffset, 1.1426 + &originPrincipals); 1.1427 + 1.1428 + const char *introductionType = "Function"; 1.1429 + if (generatorKind != NotGenerator) 1.1430 + introductionType = "GeneratorFunction"; 1.1431 + 1.1432 + const char *introducerFilename = filename; 1.1433 + if (maybeScript && maybeScript->scriptSource()->introducerFilename()) 1.1434 + introducerFilename = maybeScript->scriptSource()->introducerFilename(); 1.1435 + 1.1436 + CompileOptions options(cx); 1.1437 + options.setOriginPrincipals(originPrincipals) 1.1438 + .setFileAndLine(filename, 1) 1.1439 + .setNoScriptRval(false) 1.1440 + .setCompileAndGo(true) 1.1441 + .setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset); 1.1442 + 1.1443 + unsigned n = args.length() ? args.length() - 1 : 0; 1.1444 + if (n > 0) { 1.1445 + /* 1.1446 + * Collect the function-argument arguments into one string, separated 1.1447 + * by commas, then make a tokenstream from that string, and scan it to 1.1448 + * get the arguments. We need to throw the full scanner at the 1.1449 + * problem, because the argument string can legitimately contain 1.1450 + * comments and linefeeds. XXX It might be better to concatenate 1.1451 + * everything up into a function definition and pass it to the 1.1452 + * compiler, but doing it this way is less of a delta from the old 1.1453 + * code. See ECMA 15.3.2.1. 1.1454 + */ 1.1455 + size_t args_length = 0; 1.1456 + for (unsigned i = 0; i < n; i++) { 1.1457 + /* Collect the lengths for all the function-argument arguments. */ 1.1458 + arg = ToString<CanGC>(cx, args[i]); 1.1459 + if (!arg) 1.1460 + return false; 1.1461 + args[i].setString(arg); 1.1462 + 1.1463 + /* 1.1464 + * Check for overflow. The < test works because the maximum 1.1465 + * JSString length fits in 2 fewer bits than size_t has. 1.1466 + */ 1.1467 + size_t old_args_length = args_length; 1.1468 + args_length = old_args_length + arg->length(); 1.1469 + if (args_length < old_args_length) { 1.1470 + js_ReportAllocationOverflow(cx); 1.1471 + return false; 1.1472 + } 1.1473 + } 1.1474 + 1.1475 + /* Add 1 for each joining comma and check for overflow (two ways). */ 1.1476 + size_t old_args_length = args_length; 1.1477 + args_length = old_args_length + n - 1; 1.1478 + if (args_length < old_args_length || 1.1479 + args_length >= ~(size_t)0 / sizeof(jschar)) { 1.1480 + js_ReportAllocationOverflow(cx); 1.1481 + return false; 1.1482 + } 1.1483 + 1.1484 + /* 1.1485 + * Allocate a string to hold the concatenated arguments, including room 1.1486 + * for a terminating 0. Mark cx->tempLifeAlloc for later release, to 1.1487 + * free collected_args and its tokenstream in one swoop. 1.1488 + */ 1.1489 + LifoAllocScope las(&cx->tempLifoAlloc()); 1.1490 + jschar *cp = cx->tempLifoAlloc().newArray<jschar>(args_length + 1); 1.1491 + if (!cp) { 1.1492 + js_ReportOutOfMemory(cx); 1.1493 + return false; 1.1494 + } 1.1495 + ConstTwoByteChars collected_args(cp, args_length + 1); 1.1496 + 1.1497 + /* 1.1498 + * Concatenate the arguments into the new string, separated by commas. 1.1499 + */ 1.1500 + for (unsigned i = 0; i < n; i++) { 1.1501 + arg = args[i].toString(); 1.1502 + size_t arg_length = arg->length(); 1.1503 + const jschar *arg_chars = arg->getChars(cx); 1.1504 + if (!arg_chars) 1.1505 + return false; 1.1506 + (void) js_strncpy(cp, arg_chars, arg_length); 1.1507 + cp += arg_length; 1.1508 + 1.1509 + /* Add separating comma or terminating 0. */ 1.1510 + *cp++ = (i + 1 < n) ? ',' : 0; 1.1511 + } 1.1512 + 1.1513 + /* 1.1514 + * Initialize a tokenstream that reads from the given string. No 1.1515 + * StrictModeGetter is needed because this TokenStream won't report any 1.1516 + * strict mode errors. Any strict mode errors which might be reported 1.1517 + * here (duplicate argument names, etc.) will be detected when we 1.1518 + * compile the function body. 1.1519 + */ 1.1520 + TokenStream ts(cx, options, collected_args.get(), args_length, 1.1521 + /* strictModeGetter = */ nullptr); 1.1522 + bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator; 1.1523 + 1.1524 + /* The argument string may be empty or contain no tokens. */ 1.1525 + TokenKind tt = ts.getToken(); 1.1526 + if (tt != TOK_EOF) { 1.1527 + for (;;) { 1.1528 + /* 1.1529 + * Check that it's a name. This also implicitly guards against 1.1530 + * TOK_ERROR, which was already reported. 1.1531 + */ 1.1532 + if (hasRest) { 1.1533 + ts.reportError(JSMSG_PARAMETER_AFTER_REST); 1.1534 + return false; 1.1535 + } 1.1536 + 1.1537 + if (tt == TOK_YIELD && yieldIsValidName) 1.1538 + tt = TOK_NAME; 1.1539 + 1.1540 + if (tt != TOK_NAME) { 1.1541 + if (tt == TOK_TRIPLEDOT) { 1.1542 + hasRest = true; 1.1543 + tt = ts.getToken(); 1.1544 + if (tt == TOK_YIELD && yieldIsValidName) 1.1545 + tt = TOK_NAME; 1.1546 + if (tt != TOK_NAME) { 1.1547 + if (tt != TOK_ERROR) 1.1548 + ts.reportError(JSMSG_NO_REST_NAME); 1.1549 + return false; 1.1550 + } 1.1551 + } else { 1.1552 + return OnBadFormal(cx, tt); 1.1553 + } 1.1554 + } 1.1555 + 1.1556 + if (!formals.append(ts.currentName())) 1.1557 + return false; 1.1558 + 1.1559 + /* 1.1560 + * Get the next token. Stop on end of stream. Otherwise 1.1561 + * insist on a comma, get another name, and iterate. 1.1562 + */ 1.1563 + tt = ts.getToken(); 1.1564 + if (tt == TOK_EOF) 1.1565 + break; 1.1566 + if (tt != TOK_COMMA) 1.1567 + return OnBadFormal(cx, tt); 1.1568 + tt = ts.getToken(); 1.1569 + } 1.1570 + } 1.1571 + } 1.1572 + 1.1573 +#ifdef DEBUG 1.1574 + for (unsigned i = 0; i < formals.length(); ++i) { 1.1575 + JSString *str = formals[i]; 1.1576 + JS_ASSERT(str->asAtom().asPropertyName() == formals[i]); 1.1577 + } 1.1578 +#endif 1.1579 + 1.1580 + RootedString str(cx); 1.1581 + if (!args.length()) 1.1582 + str = cx->runtime()->emptyString; 1.1583 + else 1.1584 + str = ToString<CanGC>(cx, args[args.length() - 1]); 1.1585 + if (!str) 1.1586 + return false; 1.1587 + JSLinearString *linear = str->ensureLinear(cx); 1.1588 + if (!linear) 1.1589 + return false; 1.1590 + 1.1591 + JS::Anchor<JSString *> strAnchor(str); 1.1592 + const jschar *chars = linear->chars(); 1.1593 + size_t length = linear->length(); 1.1594 + 1.1595 + /* 1.1596 + * NB: (new Function) is not lexically closed by its caller, it's just an 1.1597 + * anonymous function in the top-level scope that its constructor inhabits. 1.1598 + * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42, 1.1599 + * and so would a call to f from another top-level's script or function. 1.1600 + */ 1.1601 + RootedAtom anonymousAtom(cx, cx->names().anonymous); 1.1602 + JSObject *proto = nullptr; 1.1603 + if (isStarGenerator) { 1.1604 + proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global); 1.1605 + if (!proto) 1.1606 + return false; 1.1607 + } 1.1608 + RootedFunction fun(cx, NewFunctionWithProto(cx, js::NullPtr(), nullptr, 0, 1.1609 + JSFunction::INTERPRETED_LAMBDA, global, 1.1610 + anonymousAtom, proto, 1.1611 + JSFunction::FinalizeKind, TenuredObject)); 1.1612 + if (!fun) 1.1613 + return false; 1.1614 + 1.1615 + if (!JSFunction::setTypeForScriptedFunction(cx, fun)) 1.1616 + return false; 1.1617 + 1.1618 + if (hasRest) 1.1619 + fun->setHasRest(); 1.1620 + 1.1621 + bool ok; 1.1622 + SourceBufferHolder srcBuf(chars, length, SourceBufferHolder::NoOwnership); 1.1623 + if (isStarGenerator) 1.1624 + ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf); 1.1625 + else 1.1626 + ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf); 1.1627 + args.rval().setObject(*fun); 1.1628 + return ok; 1.1629 +} 1.1630 + 1.1631 +bool 1.1632 +js::Function(JSContext *cx, unsigned argc, Value *vp) 1.1633 +{ 1.1634 + return FunctionConstructor(cx, argc, vp, NotGenerator); 1.1635 +} 1.1636 + 1.1637 +bool 1.1638 +js::Generator(JSContext *cx, unsigned argc, Value *vp) 1.1639 +{ 1.1640 + return FunctionConstructor(cx, argc, vp, StarGenerator); 1.1641 +} 1.1642 + 1.1643 +bool 1.1644 +JSFunction::isBuiltinFunctionConstructor() 1.1645 +{ 1.1646 + return maybeNative() == Function || maybeNative() == Generator; 1.1647 +} 1.1648 + 1.1649 +JSFunction * 1.1650 +js::NewFunction(ExclusiveContext *cx, HandleObject funobjArg, Native native, unsigned nargs, 1.1651 + JSFunction::Flags flags, HandleObject parent, HandleAtom atom, 1.1652 + gc::AllocKind allocKind /* = JSFunction::FinalizeKind */, 1.1653 + NewObjectKind newKind /* = GenericObject */) 1.1654 +{ 1.1655 + return NewFunctionWithProto(cx, funobjArg, native, nargs, flags, parent, atom, nullptr, 1.1656 + allocKind, newKind); 1.1657 +} 1.1658 + 1.1659 +JSFunction * 1.1660 +js::NewFunctionWithProto(ExclusiveContext *cx, HandleObject funobjArg, Native native, 1.1661 + unsigned nargs, JSFunction::Flags flags, HandleObject parent, 1.1662 + HandleAtom atom, JSObject *proto, 1.1663 + gc::AllocKind allocKind /* = JSFunction::FinalizeKind */, 1.1664 + NewObjectKind newKind /* = GenericObject */) 1.1665 +{ 1.1666 + JS_ASSERT(allocKind == JSFunction::FinalizeKind || allocKind == JSFunction::ExtendedFinalizeKind); 1.1667 + JS_ASSERT(sizeof(JSFunction) <= gc::Arena::thingSize(JSFunction::FinalizeKind)); 1.1668 + JS_ASSERT(sizeof(FunctionExtended) <= gc::Arena::thingSize(JSFunction::ExtendedFinalizeKind)); 1.1669 + 1.1670 + RootedObject funobj(cx, funobjArg); 1.1671 + if (funobj) { 1.1672 + JS_ASSERT(funobj->is<JSFunction>()); 1.1673 + JS_ASSERT(funobj->getParent() == parent); 1.1674 + JS_ASSERT_IF(native, funobj->hasSingletonType()); 1.1675 + } else { 1.1676 + // Don't give asm.js module functions a singleton type since they 1.1677 + // are cloned (via CloneFunctionObjectIfNotSingleton) which assumes 1.1678 + // that hasSingletonType implies isInterpreted. 1.1679 + if (native && !IsAsmJSModuleNative(native)) 1.1680 + newKind = SingletonObject; 1.1681 + funobj = NewObjectWithClassProto(cx, &JSFunction::class_, proto, 1.1682 + SkipScopeParent(parent), allocKind, newKind); 1.1683 + if (!funobj) 1.1684 + return nullptr; 1.1685 + } 1.1686 + RootedFunction fun(cx, &funobj->as<JSFunction>()); 1.1687 + 1.1688 + if (allocKind == JSFunction::ExtendedFinalizeKind) 1.1689 + flags = JSFunction::Flags(flags | JSFunction::EXTENDED); 1.1690 + 1.1691 + /* Initialize all function members. */ 1.1692 + fun->setArgCount(uint16_t(nargs)); 1.1693 + fun->setFlags(flags); 1.1694 + if (fun->isInterpreted()) { 1.1695 + JS_ASSERT(!native); 1.1696 + fun->mutableScript().init(nullptr); 1.1697 + fun->initEnvironment(parent); 1.1698 + } else { 1.1699 + JS_ASSERT(fun->isNative()); 1.1700 + JS_ASSERT(native); 1.1701 + fun->initNative(native, nullptr); 1.1702 + } 1.1703 + if (allocKind == JSFunction::ExtendedFinalizeKind) 1.1704 + fun->initializeExtended(); 1.1705 + fun->initAtom(atom); 1.1706 + 1.1707 + return fun; 1.1708 +} 1.1709 + 1.1710 +JSFunction * 1.1711 +js::CloneFunctionObject(JSContext *cx, HandleFunction fun, HandleObject parent, gc::AllocKind allocKind, 1.1712 + NewObjectKind newKindArg /* = GenericObject */) 1.1713 +{ 1.1714 + JS_ASSERT(parent); 1.1715 + JS_ASSERT(!fun->isBoundFunction()); 1.1716 + 1.1717 + bool useSameScript = cx->compartment() == fun->compartment() && 1.1718 + !fun->hasSingletonType() && 1.1719 + !types::UseNewTypeForClone(fun); 1.1720 + 1.1721 + if (!useSameScript && fun->isInterpretedLazy() && !fun->getOrCreateScript(cx)) 1.1722 + return nullptr; 1.1723 + 1.1724 + NewObjectKind newKind = useSameScript ? newKindArg : SingletonObject; 1.1725 + JSObject *cloneProto = nullptr; 1.1726 + if (fun->isStarGenerator()) { 1.1727 + cloneProto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, cx->global()); 1.1728 + if (!cloneProto) 1.1729 + return nullptr; 1.1730 + } 1.1731 + JSObject *cloneobj = NewObjectWithClassProto(cx, &JSFunction::class_, cloneProto, 1.1732 + SkipScopeParent(parent), allocKind, newKind); 1.1733 + if (!cloneobj) 1.1734 + return nullptr; 1.1735 + RootedFunction clone(cx, &cloneobj->as<JSFunction>()); 1.1736 + 1.1737 + uint16_t flags = fun->flags() & ~JSFunction::EXTENDED; 1.1738 + if (allocKind == JSFunction::ExtendedFinalizeKind) 1.1739 + flags |= JSFunction::EXTENDED; 1.1740 + 1.1741 + clone->setArgCount(fun->nargs()); 1.1742 + clone->setFlags(flags); 1.1743 + if (fun->hasScript()) { 1.1744 + clone->initScript(fun->nonLazyScript()); 1.1745 + clone->initEnvironment(parent); 1.1746 + } else if (fun->isInterpretedLazy()) { 1.1747 + LazyScript *lazy = fun->lazyScriptOrNull(); 1.1748 + clone->initLazyScript(lazy); 1.1749 + clone->initEnvironment(parent); 1.1750 + } else { 1.1751 + clone->initNative(fun->native(), fun->jitInfo()); 1.1752 + } 1.1753 + clone->initAtom(fun->displayAtom()); 1.1754 + 1.1755 + if (allocKind == JSFunction::ExtendedFinalizeKind) { 1.1756 + if (fun->isExtended() && fun->compartment() == cx->compartment()) { 1.1757 + for (unsigned i = 0; i < FunctionExtended::NUM_EXTENDED_SLOTS; i++) 1.1758 + clone->initExtendedSlot(i, fun->getExtendedSlot(i)); 1.1759 + } else { 1.1760 + clone->initializeExtended(); 1.1761 + } 1.1762 + } 1.1763 + 1.1764 + if (useSameScript) { 1.1765 + /* 1.1766 + * Clone the function, reusing its script. We can use the same type as 1.1767 + * the original function provided that its prototype is correct. 1.1768 + */ 1.1769 + if (fun->getProto() == clone->getProto()) 1.1770 + clone->setType(fun->type()); 1.1771 + return clone; 1.1772 + } 1.1773 + 1.1774 + RootedFunction cloneRoot(cx, clone); 1.1775 + 1.1776 + /* 1.1777 + * Across compartments we have to clone the script for interpreted 1.1778 + * functions. Cross-compartment cloning only happens via JSAPI 1.1779 + * (JS_CloneFunctionObject) which dynamically ensures that 'script' has 1.1780 + * no enclosing lexical scope (only the global scope). 1.1781 + */ 1.1782 + if (cloneRoot->isInterpreted() && !CloneFunctionScript(cx, fun, cloneRoot, newKindArg)) 1.1783 + return nullptr; 1.1784 + 1.1785 + return cloneRoot; 1.1786 +} 1.1787 + 1.1788 +JSFunction * 1.1789 +js::DefineFunction(JSContext *cx, HandleObject obj, HandleId id, Native native, 1.1790 + unsigned nargs, unsigned flags, AllocKind allocKind /* = FinalizeKind */, 1.1791 + NewObjectKind newKind /* = GenericObject */) 1.1792 +{ 1.1793 + PropertyOp gop; 1.1794 + StrictPropertyOp sop; 1.1795 + 1.1796 + RootedFunction fun(cx); 1.1797 + 1.1798 + if (flags & JSFUN_STUB_GSOPS) { 1.1799 + /* 1.1800 + * JSFUN_STUB_GSOPS is a request flag only, not stored in fun->flags or 1.1801 + * the defined property's attributes. This allows us to encode another, 1.1802 + * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h 1.1803 + * for more on this. 1.1804 + */ 1.1805 + flags &= ~JSFUN_STUB_GSOPS; 1.1806 + gop = JS_PropertyStub; 1.1807 + sop = JS_StrictPropertyStub; 1.1808 + } else { 1.1809 + gop = nullptr; 1.1810 + sop = nullptr; 1.1811 + } 1.1812 + 1.1813 + JSFunction::Flags funFlags; 1.1814 + if (!native) 1.1815 + funFlags = JSFunction::INTERPRETED_LAZY; 1.1816 + else 1.1817 + funFlags = JSAPIToJSFunctionFlags(flags); 1.1818 + RootedAtom atom(cx, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : nullptr); 1.1819 + fun = NewFunction(cx, NullPtr(), native, nargs, funFlags, obj, atom, allocKind, newKind); 1.1820 + if (!fun) 1.1821 + return nullptr; 1.1822 + 1.1823 + RootedValue funVal(cx, ObjectValue(*fun)); 1.1824 + if (!JSObject::defineGeneric(cx, obj, id, funVal, gop, sop, flags & ~JSFUN_FLAGS_MASK)) 1.1825 + return nullptr; 1.1826 + 1.1827 + return fun; 1.1828 +} 1.1829 + 1.1830 +bool 1.1831 +js::IsConstructor(const Value &v) 1.1832 +{ 1.1833 + // Step 2. 1.1834 + if (!v.isObject()) 1.1835 + return false; 1.1836 + 1.1837 + // Step 3-4, a bit complex for us, since we have several flavors of 1.1838 + // [[Construct]] internal method. 1.1839 + JSObject &obj = v.toObject(); 1.1840 + if (obj.is<JSFunction>()) { 1.1841 + JSFunction &fun = obj.as<JSFunction>(); 1.1842 + return fun.isNativeConstructor() || fun.isInterpretedConstructor(); 1.1843 + } 1.1844 + return obj.getClass()->construct != nullptr; 1.1845 +} 1.1846 + 1.1847 +void 1.1848 +js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, const Class *clasp) 1.1849 +{ 1.1850 + RootedValue thisv(cx, call.thisv()); 1.1851 + 1.1852 +#ifdef DEBUG 1.1853 + if (thisv.isObject()) { 1.1854 + JS_ASSERT(thisv.toObject().getClass() != clasp || 1.1855 + !thisv.toObject().isNative() || 1.1856 + !thisv.toObject().getProto() || 1.1857 + thisv.toObject().getProto()->getClass() != clasp); 1.1858 + } else if (thisv.isString()) { 1.1859 + JS_ASSERT(clasp != &StringObject::class_); 1.1860 + } else if (thisv.isNumber()) { 1.1861 + JS_ASSERT(clasp != &NumberObject::class_); 1.1862 + } else if (thisv.isBoolean()) { 1.1863 + JS_ASSERT(clasp != &BooleanObject::class_); 1.1864 + } else { 1.1865 + JS_ASSERT(thisv.isUndefined() || thisv.isNull()); 1.1866 + } 1.1867 +#endif 1.1868 + 1.1869 + if (JSFunction *fun = ReportIfNotFunction(cx, call.calleev())) { 1.1870 + JSAutoByteString funNameBytes; 1.1871 + if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) { 1.1872 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, 1.1873 + clasp->name, funName, InformalValueTypeName(thisv)); 1.1874 + } 1.1875 + } 1.1876 +} 1.1877 + 1.1878 +void 1.1879 +js::ReportIncompatible(JSContext *cx, CallReceiver call) 1.1880 +{ 1.1881 + if (JSFunction *fun = ReportIfNotFunction(cx, call.calleev())) { 1.1882 + JSAutoByteString funNameBytes; 1.1883 + if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) { 1.1884 + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_METHOD, 1.1885 + funName, "method", InformalValueTypeName(call.thisv())); 1.1886 + } 1.1887 + } 1.1888 +} 1.1889 + 1.1890 +bool 1.1891 +JSObject::hasIdempotentProtoChain() const 1.1892 +{ 1.1893 + // Return false if obj (or an object on its proto chain) is non-native or 1.1894 + // has a resolve or lookup hook. 1.1895 + JSObject *obj = const_cast<JSObject *>(this); 1.1896 + while (true) { 1.1897 + if (!obj->isNative()) 1.1898 + return false; 1.1899 + 1.1900 + JSResolveOp resolve = obj->getClass()->resolve; 1.1901 + if (resolve != JS_ResolveStub && resolve != (JSResolveOp) js::fun_resolve) 1.1902 + return false; 1.1903 + 1.1904 + if (obj->getOps()->lookupProperty || obj->getOps()->lookupGeneric || obj->getOps()->lookupElement) 1.1905 + return false; 1.1906 + 1.1907 + obj = obj->getProto(); 1.1908 + if (!obj) 1.1909 + return true; 1.1910 + } 1.1911 + 1.1912 + MOZ_ASSUME_UNREACHABLE("Should not get here"); 1.1913 +} 1.1914 + 1.1915 +namespace JS { 1.1916 +namespace detail { 1.1917 + 1.1918 +JS_PUBLIC_API(void) 1.1919 +CheckIsValidConstructible(Value calleev) 1.1920 +{ 1.1921 + JSObject *callee = &calleev.toObject(); 1.1922 + if (callee->is<JSFunction>()) 1.1923 + JS_ASSERT(callee->as<JSFunction>().isNativeConstructor()); 1.1924 + else 1.1925 + JS_ASSERT(callee->getClass()->construct != nullptr); 1.1926 +} 1.1927 + 1.1928 +} // namespace detail 1.1929 +} // namespace JS