Diff
Modified: trunk/JSTests/ChakraCore/test/Error/validate_line_column.baseline-jsc (275438 => 275439)
--- trunk/JSTests/ChakraCore/test/Error/validate_line_column.baseline-jsc 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/JSTests/ChakraCore/test/Error/validate_line_column.baseline-jsc 2021-04-02 21:20:45 UTC (rev 275439)
@@ -4,7 +4,7 @@
@validate_line_column.js:21:11
foo@validate_line_column.js:10:17
global code@validate_line_column.js:20:4
-@validate_line_column.js:26:7
+@validate_line_column.js:26:23
foo@validate_line_column.js:10:17
global code@validate_line_column.js:24:4
@validate_line_column.js:30:14
Modified: trunk/JSTests/ChangeLog (275438 => 275439)
--- trunk/JSTests/ChangeLog 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/JSTests/ChangeLog 2021-04-02 21:20:45 UTC (rev 275439)
@@ -1,3 +1,12 @@
+2021-04-02 Alexey Shvayka <[email protected]>
+
+ Reduce bytecode instruction count emitted for `class extends`
+ https://bugs.webkit.org/show_bug.cgi?id=223884
+
+ Reviewed by Yusuke Suzuki.
+
+ * ChakraCore/test/Error/validate_line_column.baseline-jsc:
+
2021-04-02 Jessica Tallon <[email protected]>
Add tests for the new type method on certain JS-API wasm objects.
Modified: trunk/Source/_javascript_Core/ChangeLog (275438 => 275439)
--- trunk/Source/_javascript_Core/ChangeLog 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-04-02 21:20:45 UTC (rev 275439)
@@ -1,3 +1,52 @@
+2021-04-02 Alexey Shvayka <[email protected]>
+
+ Reduce bytecode instruction count emitted for `class extends`
+ https://bugs.webkit.org/show_bug.cgi?id=223884
+
+ Reviewed by Yusuke Suzuki.
+
+ This patch adds a variant of globalFuncSetPrototypeDirect() that throws on
+ invalid [[Prototype]] values (instead of ignoring them) and utilizes it in
+ ClassExprNode::emitBytecode(), removing equivalent checks.
+
+ Throwing for invalid `superclass.prototype` value after setting the [[Prototype]]
+ of `constructor` is unobservable because it's a newly created extensible object
+ and `superclass` is a proven object.
+
+ The fact that [[Prototype]] set can throw only in case of `superclass.prototype`
+ allows keeping descriptive error message via custom appender. To find "extends"
+ in a source code, ClassExprNode is made an instance of ThrowableExpressionData.
+
+ This change reduces the number of emitted bytecodes by 4, and fixes IsConstructor's
+ error [1] to point to correct source code location.
+
+ [1]: https://tc39.es/ecma262/#sec-runtime-semantics-classdefinitionevaluation (step 5.f)
+
+ * builtins/BuiltinNames.h:
+ * bytecode/LinkTimeConstant.h:
+ * bytecompiler/BytecodeGenerator.cpp:
+ (JSC::BytecodeGenerator::emitDirectSetPrototypeOf):
+ * bytecompiler/BytecodeGenerator.h:
+ * bytecompiler/NodesCodegen.cpp:
+ (JSC::PropertyListNode::emitPutConstantProperty):
+ (JSC::ClassExprNode::emitBytecode):
+ * parser/ASTBuilder.h:
+ (JSC::ASTBuilder::createClassExpr):
+ * parser/Nodes.h:
+ * parser/Parser.cpp:
+ (JSC::Parser<LexerType>::parseClass):
+ * parser/SyntaxChecker.h:
+ (JSC::SyntaxChecker::createClassExpr):
+ * runtime/ExceptionHelpers.cpp:
+ (JSC::invalidPrototypeSourceAppender):
+ (JSC::createInvalidPrototypeError):
+ * runtime/ExceptionHelpers.h:
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+ * runtime/JSGlobalObjectFunctions.cpp:
+ (JSC::JSC_DEFINE_HOST_FUNCTION):
+ * runtime/JSGlobalObjectFunctions.h:
+
2021-04-02 Jessica Tallon <[email protected]>
Add type method to WebAssembly.Memory, WebAssembly.Table & WebAssembly.Global objects
Modified: trunk/Source/_javascript_Core/builtins/BuiltinNames.h (275438 => 275439)
--- trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/builtins/BuiltinNames.h 2021-04-02 21:20:45 UTC (rev 275439)
@@ -144,6 +144,7 @@
macro(setBucketNext) \
macro(setBucketKey) \
macro(setPrototypeDirect) \
+ macro(setPrototypeDirectOrThrow) \
macro(regExpBuiltinExec) \
macro(regExpMatchFast) \
macro(regExpProtoFlagsGetter) \
Modified: trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h (275438 => 275439)
--- trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/bytecode/LinkTimeConstant.h 2021-04-02 21:20:45 UTC (rev 275439)
@@ -44,6 +44,7 @@
v(setBucketNext, nullptr) \
v(setBucketKey, nullptr) \
v(setPrototypeDirect, nullptr) \
+ v(setPrototypeDirectOrThrow, nullptr) \
v(copyDataProperties, nullptr) \
v(enqueueJob, nullptr) \
v(makeTypeError, nullptr) \
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (275438 => 275439)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp 2021-04-02 21:20:45 UTC (rev 275439)
@@ -2706,16 +2706,16 @@
return dst;
}
-RegisterID* BytecodeGenerator::emitDirectSetPrototypeOf(RegisterID* base, RegisterID* prototype)
+template<InvalidPrototypeMode mode>
+RegisterID* BytecodeGenerator::emitDirectSetPrototypeOf(RegisterID* base, RegisterID* prototype, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
{
- RefPtr<RegisterID> setPrototypeDirect = moveLinkTimeConstant(nullptr, LinkTimeConstant::setPrototypeDirect);
+ RefPtr<RegisterID> setPrototypeDirect = moveLinkTimeConstant(nullptr, mode == InvalidPrototypeMode::Throw ? LinkTimeConstant::setPrototypeDirectOrThrow : LinkTimeConstant::setPrototypeDirect);
CallArguments args(*this, nullptr, 1);
move(args.thisRegister(), base);
move(args.argumentRegister(0), prototype);
- JSTextPosition position;
- emitCall(newTemporary(), setPrototypeDirect.get(), NoExpectedFunction, args, position, position, position, DebuggableCall::No);
+ emitCall(newTemporary(), setPrototypeDirect.get(), NoExpectedFunction, args, divot, divotStart, divotEnd, DebuggableCall::No);
return base;
}
Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (275438 => 275439)
--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h 2021-04-02 21:20:45 UTC (rev 275439)
@@ -74,6 +74,7 @@
enum class DebuggableCall { Yes, No };
enum class ThisResolutionType { Local, Scoped };
+ enum class InvalidPrototypeMode : uint8_t { Throw, Ignore };
enum class LinkTimeConstant : int32_t;
class CallArguments {
@@ -814,7 +815,9 @@
RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property);
RegisterID* emitGetPrototypeOf(RegisterID* dst, RegisterID* value);
- RegisterID* emitDirectSetPrototypeOf(RegisterID* base, RegisterID* prototype);
+
+ template<InvalidPrototypeMode>
+ RegisterID* emitDirectSetPrototypeOf(RegisterID* base, RegisterID* prototype, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
RegisterID* emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value);
RegisterID* emitDirectPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (275438 => 275439)
--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp 2021-04-02 21:20:45 UTC (rev 275439)
@@ -817,7 +817,7 @@
if (PropertyNode::isUnderscoreProtoSetter(generator.vm(), node)) {
RefPtr<RegisterID> prototype = generator.emitNode(node.m_assign);
- generator.emitDirectSetPrototypeOf(newObj, prototype.get());
+ generator.emitDirectSetPrototypeOf<InvalidPrototypeMode::Ignore>(newObj, prototype.get(), m_position, m_position, m_position);
return;
}
@@ -5211,19 +5211,14 @@
Ref<Label> superclassIsConstructorLabel = generator.newLabel();
generator.emitJumpIfTrue(generator.emitIsConstructor(generator.newTemporary(), superclass.get()), superclassIsConstructorLabel.get());
+ generator.emitExpressionInfo(divot(), divotStart(), divotEnd());
generator.emitThrowTypeError("The superclass is not a constructor."_s);
generator.emitLabel(superclassIsConstructorLabel.get());
generator.emitGetById(protoParent.get(), superclass.get(), generator.propertyNames().prototype);
- Ref<Label> protoParentIsObjectOrNullLabel = generator.newLabel();
- generator.emitJumpIfTrue(generator.emitIsObject(generator.newTemporary(), protoParent.get()), protoParentIsObjectOrNullLabel.get());
- generator.emitJumpIfTrue(generator.emitIsNull(generator.newTemporary(), protoParent.get()), protoParentIsObjectOrNullLabel.get());
- generator.emitThrowTypeError("The value of the superclass's prototype property is not an object or null."_s);
- generator.emitLabel(protoParentIsObjectOrNullLabel.get());
-
- generator.emitDirectSetPrototypeOf(constructor.get(), superclass.get());
+ generator.emitDirectSetPrototypeOf<InvalidPrototypeMode::Throw>(constructor.get(), superclass.get(), m_position, m_position, m_position); // never actually throws
generator.emitLabel(superclassIsNullLabel.get());
- generator.emitDirectSetPrototypeOf(prototype.get(), protoParent.get());
+ generator.emitDirectSetPrototypeOf<InvalidPrototypeMode::Throw>(prototype.get(), protoParent.get(), divot(), divotStart(), divotEnd());
}
if (needsHomeObject)
Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (275438 => 275439)
--- trunk/Source/_javascript_Core/parser/ASTBuilder.h 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h 2021-04-02 21:20:45 UTC (rev 275439)
@@ -412,10 +412,12 @@
}
ClassExprNode* createClassExpr(const JSTokenLocation& location, const ParserClassInfo<ASTBuilder>& classInfo, VariableEnvironment& classEnvironment, ExpressionNode* constructor,
- ExpressionNode* parentClass, PropertyListNode* classElements)
+ ExpressionNode* parentClass, PropertyListNode* classElements, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
{
SourceCode source = m_sourceCode->subExpression(classInfo.startOffset, classInfo.endOffset, classInfo.startLine, classInfo.startColumn);
- return new (m_parserArena) ClassExprNode(location, *classInfo.className, source, classEnvironment, constructor, parentClass, classElements);
+ ClassExprNode* node = new (m_parserArena) ClassExprNode(location, *classInfo.className, source, classEnvironment, constructor, parentClass, classElements);
+ setExceptionLocation(node, start, divot, end);
+ return node;
}
ExpressionNode* createFunctionExpr(const JSTokenLocation& location, const ParserFunctionInfo<ASTBuilder>& functionInfo)
Modified: trunk/Source/_javascript_Core/parser/Nodes.h (275438 => 275439)
--- trunk/Source/_javascript_Core/parser/Nodes.h 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/parser/Nodes.h 2021-04-02 21:20:45 UTC (rev 275439)
@@ -2356,7 +2356,7 @@
Type m_type;
};
- class ClassExprNode final : public ExpressionNode, public VariableEnvironmentNode {
+ class ClassExprNode final : public ExpressionNode, public ThrowableExpressionData, public VariableEnvironmentNode {
JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ClassExprNode);
public:
ClassExprNode(const JSTokenLocation&, const Identifier&, const SourceCode& classSource,
Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (275438 => 275439)
--- trunk/Source/_javascript_Core/parser/Parser.cpp 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp 2021-04-02 21:20:45 UTC (rev 275439)
@@ -2886,6 +2886,7 @@
template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(TreeBuilder& context, FunctionNameRequirements requirements, ParserClassInfo<TreeBuilder>& info)
{
ASSERT(match(CLASSTOKEN));
+ JSTextPosition start = tokenStartPosition();
JSTokenLocation location(tokenLocation());
info.startLine = location.line;
info.startColumn = tokenColumn();
@@ -2915,8 +2916,10 @@
}
ASSERT(info.className);
+ JSTextPosition divot = start;
TreeExpression parentClass = 0;
if (consume(EXTENDS)) {
+ divot = tokenStartPosition();
parentClass = parseMemberExpression(context);
failIfFalse(parentClass, "Cannot parse the parent class name");
}
@@ -2923,6 +2926,7 @@
classScope->setIsClassScope();
const ConstructorKind constructorKind = parentClass ? ConstructorKind::Extends : ConstructorKind::Base;
+ JSTextPosition classHeadEnd = lastTokenEndPosition();
consumeOrFail(OPENBRACE, "Expected opening '{' at the start of a class body");
TreeExpression constructor = 0;
@@ -3170,7 +3174,7 @@
semanticFailIfFalse(copyUndeclaredPrivateNamesToOuterScope(), "Cannot reference undeclared private names");
}
- auto classExpression = context.createClassExpr(location, info, classScope->finalizeLexicalEnvironment(), constructor, parentClass, classElements);
+ auto classExpression = context.createClassExpr(location, info, classScope->finalizeLexicalEnvironment(), constructor, parentClass, classElements, start, divot, classHeadEnd);
popScope(classScope, TreeBuilder::NeedsFreeVariableInfo);
return classExpression;
}
Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (275438 => 275439)
--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h 2021-04-02 21:20:45 UTC (rev 275439)
@@ -191,7 +191,7 @@
ExpressionType createYield(const JSTokenLocation&) { return YieldExpr; }
ExpressionType createYield(const JSTokenLocation&, ExpressionType, bool, int, int, int) { return YieldExpr; }
ExpressionType createAwait(const JSTokenLocation&, ExpressionType, int, int, int) { return AwaitExpr; }
- ClassExpression createClassExpr(const JSTokenLocation&, const ParserClassInfo<SyntaxChecker>&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList) { return ClassExpr; }
+ ClassExpression createClassExpr(const JSTokenLocation&, const ParserClassInfo<SyntaxChecker>&, VariableEnvironment&, ExpressionType, ExpressionType, PropertyList, int, int, int) { return ClassExpr; }
ExpressionType createFunctionExpr(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
ExpressionType createGeneratorFunctionBody(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&, const Identifier&) { return FunctionExpr; }
ExpressionType createAsyncFunctionBody(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return FunctionExpr; }
Modified: trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp (275438 => 275439)
--- trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/runtime/ExceptionHelpers.cpp 2021-04-02 21:20:45 UTC (rev 275439)
@@ -262,6 +262,18 @@
return invalidParameterInstanceofSourceAppender("[Symbol.hasInstance] is not a function, undefined, or null"_s, originalMessage, sourceText, runtimeType, occurrence);
}
+static String invalidPrototypeSourceAppender(const String& originalMessage, const String& sourceText, RuntimeType, ErrorInstance::SourceTextWhereErrorOccurred occurrence)
+{
+ if (occurrence == ErrorInstance::FoundApproximateSource)
+ return defaultApproximateSourceError(originalMessage, sourceText);
+
+ auto extendsIndex = sourceText.reverseFind("extends");
+ if (extendsIndex == notFound || sourceText.find("extends") != extendsIndex)
+ return makeString(originalMessage, " (evaluating '", sourceText, "')");
+
+ return "The value of the superclass's prototype property is not an object or null."_s;
+}
+
JSObject* createError(JSGlobalObject* globalObject, JSValue value, const String& message, ErrorInstance::SourceAppender appender)
{
VM& vm = globalObject->vm();
@@ -321,6 +333,11 @@
return createError(globalObject, value, "is not an object"_s, defaultSourceAppender);
}
+JSObject* createInvalidPrototypeError(JSGlobalObject* globalObject, JSValue value)
+{
+ return createError(globalObject, value, "is not an object or null"_s, invalidPrototypeSourceAppender);
+}
+
JSObject* createErrorForInvalidGlobalAssignment(JSGlobalObject* globalObject, const String& propertyName)
{
return createReferenceError(globalObject, makeString("Strict mode forbids implicit creation of global property '", propertyName, '\''));
Modified: trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h (275438 => 275439)
--- trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/runtime/ExceptionHelpers.h 2021-04-02 21:20:45 UTC (rev 275439)
@@ -52,6 +52,7 @@
JSObject* createInvalidInstanceofParameterErrorHasInstanceValueNotFunction(JSGlobalObject*, JSValue);
JSObject* createNotAConstructorError(JSGlobalObject*, JSValue);
JSObject* createNotAFunctionError(JSGlobalObject*, JSValue);
+JSObject* createInvalidPrototypeError(JSGlobalObject*, JSValue);
JSObject* createErrorForInvalidGlobalAssignment(JSGlobalObject*, const String&);
JSObject* createInvalidPrivateNameError(JSGlobalObject*);
JSObject* createRedefinedPrivateNameError(JSGlobalObject*);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (275438 => 275439)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp 2021-04-02 21:20:45 UTC (rev 275439)
@@ -1299,6 +1299,9 @@
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::setPrototypeDirect)].initLater([] (const Initializer<JSCell>& init) {
init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), globalFuncSetPrototypeDirect));
});
+ m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::setPrototypeDirectOrThrow)].initLater([] (const Initializer<JSCell>& init) {
+ init.set(JSFunction::create(init.vm, jsCast<JSGlobalObject*>(init.owner), 2, String(), globalFuncSetPrototypeDirectOrThrow));
+ });
// RegExp.prototype helpers.
m_linkTimeConstants[static_cast<unsigned>(LinkTimeConstant::regExpCreate)].initLater([] (const Initializer<JSCell>& init) {
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (275438 => 275439)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp 2021-04-02 21:20:45 UTC (rev 275439)
@@ -734,7 +734,6 @@
JSC_DEFINE_HOST_FUNCTION(globalFuncSetPrototypeDirect, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
VM& vm = globalObject->vm();
- auto scope = DECLARE_THROW_SCOPE(vm);
JSValue value = callFrame->uncheckedArgument(0);
if (value.isObject() || value.isNull()) {
@@ -742,10 +741,24 @@
object->setPrototypeDirect(vm, value);
}
- scope.assertNoException();
- return { };
+ return JSValue::encode(jsUndefined());
}
+JSC_DEFINE_HOST_FUNCTION(globalFuncSetPrototypeDirectOrThrow, (JSGlobalObject* globalObject, CallFrame* callFrame))
+{
+ VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ JSValue value = callFrame->uncheckedArgument(0);
+ if (!value.isObject() && !value.isNull())
+ return throwVMError(globalObject, scope, createInvalidPrototypeError(globalObject, value));
+
+ JSObject* object = asObject(callFrame->thisValue());
+ object->setPrototypeDirect(vm, value);
+
+ return JSValue::encode(jsUndefined());
+}
+
JSC_DEFINE_HOST_FUNCTION(globalFuncHostPromiseRejectionTracker, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
VM& vm = globalObject->vm();
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h (275438 => 275439)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h 2021-04-02 21:10:28 UTC (rev 275438)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h 2021-04-02 21:20:45 UTC (rev 275439)
@@ -52,6 +52,7 @@
JSC_DECLARE_HOST_FUNCTION(globalFuncProtoGetter);
JSC_DECLARE_HOST_FUNCTION(globalFuncProtoSetter);
JSC_DECLARE_HOST_FUNCTION(globalFuncSetPrototypeDirect);
+JSC_DECLARE_HOST_FUNCTION(globalFuncSetPrototypeDirectOrThrow);
JSC_DECLARE_HOST_FUNCTION(globalFuncHostPromiseRejectionTracker);
JSC_DECLARE_HOST_FUNCTION(globalFuncBuiltinLog);
JSC_DECLARE_HOST_FUNCTION(globalFuncBuiltinDescribe);