Separate JSON parsing from the JavaScript parser.

Switch JSON parsing to creating the value directly instead of createing
code to create the value.

Review URL: http://codereview.chromium.org/4135004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5715 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
lrn@chromium.org 2010-10-27 09:19:43 +00:00
parent a8f2714425
commit 938d88e193
13 changed files with 209 additions and 250 deletions

View File

@ -152,10 +152,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
script->set_context_data((*i::Top::global_context())->data());
#ifdef ENABLE_DEBUGGER_SUPPORT
if (info->is_eval() || info->is_json()) {
Script::CompilationType compilation_type = info->is_json()
? Script::COMPILATION_TYPE_JSON
: Script::COMPILATION_TYPE_EVAL;
if (info->is_eval()) {
Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
script->set_compilation_type(Smi::FromInt(compilation_type));
// For eval scripts add information on the function from which eval was
// called.
@ -323,13 +321,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
Handle<Context> context,
bool is_global,
ValidationState validate) {
// Note that if validation is required then no path through this function
// is allowed to return a value without validating that the input is legal
// json.
bool is_json = (validate == VALIDATE_JSON);
bool is_global) {
int source_length = source->length();
Counters::total_eval_size.Increment(source_length);
Counters::total_compile_size.Increment(source_length);
@ -338,13 +330,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
VMState state(COMPILER);
// Do a lookup in the compilation cache; if the entry is not there, invoke
// the compiler and add the result to the cache. If we're evaluating json
// we bypass the cache since we can't be sure a potential value in the
// cache has been validated.
// the compiler and add the result to the cache.
Handle<SharedFunctionInfo> result;
if (!is_json) {
result = CompilationCache::LookupEval(source, context, is_global);
}
result = CompilationCache::LookupEval(source, context, is_global);
if (result.is_null()) {
// Create a script object describing the script to be compiled.
@ -352,12 +340,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
CompilationInfo info(script);
info.MarkAsEval();
if (is_global) info.MarkAsGlobal();
if (is_json) info.MarkAsJson();
info.SetCallingContext(context);
result = MakeFunctionInfo(&info);
if (!result.is_null() && !is_json) {
// For json it's unlikely that we'll ever see exactly the same string
// again so we don't use the compilation cache.
if (!result.is_null()) {
CompilationCache::PutEval(source, context, is_global, result);
}
}

View File

@ -49,7 +49,6 @@ class CompilationInfo BASE_EMBEDDED {
bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
bool is_json() const { return (flags_ & IsJson::mask()) != 0; }
bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
@ -69,10 +68,6 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(!is_lazy());
flags_ |= IsGlobal::encode(true);
}
void MarkAsJson() {
ASSERT(!is_lazy());
flags_ |= IsJson::encode(true);
}
void MarkAsInLoop() {
ASSERT(is_lazy());
flags_ |= IsInLoop::encode(true);
@ -108,16 +103,15 @@ class CompilationInfo BASE_EMBEDDED {
// Flags that can be set for eager compilation.
class IsEval: public BitField<bool, 1, 1> {};
class IsGlobal: public BitField<bool, 2, 1> {};
class IsJson: public BitField<bool, 3, 1> {};
// Flags that can be set for lazy compilation.
class IsInLoop: public BitField<bool, 4, 1> {};
class IsInLoop: public BitField<bool, 3, 1> {};
unsigned flags_;
// Fields filled in by the compilation pipeline.
// AST filled in by the parser.
FunctionLiteral* function_;
// The scope of the function literal as a convenience. Set to indidicate
// The scope of the function literal as a convenience. Set to indicate
// that scopes have been analyzed.
Scope* scope_;
// The compiled code.
@ -153,8 +147,6 @@ class CompilationInfo BASE_EMBEDDED {
class Compiler : public AllStatic {
public:
enum ValidationState { DONT_VALIDATE_JSON, VALIDATE_JSON };
// All routines return a JSFunction.
// If an error occurs an exception is raised and
// the return handle contains NULL.
@ -172,8 +164,7 @@ class Compiler : public AllStatic {
// Compile a String source within a context for Eval.
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
Handle<Context> context,
bool is_global,
ValidationState validation);
bool is_global);
// Compile from function info (used for lazy compilation). Returns true on
// success and false if the compilation resulted in a stack overflow.

View File

@ -1301,7 +1301,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
try {
try {
// Convert the JSON string to an object.
request = %CompileString('(' + json_request + ')', false)();
request = %CompileString('(' + json_request + ')')();
// Create an initial response.
response = this.createResponse(request);

View File

@ -29,8 +29,7 @@ var $JSON = global.JSON;
function ParseJSONUnfiltered(text) {
var s = $String(text);
var f = %CompileString(s, true);
return f();
return %ParseJson(s);
}
function Revive(holder, name, reviver) {

View File

@ -3409,8 +3409,7 @@ class Script: public Struct {
// Script compilation types.
enum CompilationType {
COMPILATION_TYPE_HOST = 0,
COMPILATION_TYPE_EVAL = 1,
COMPILATION_TYPE_JSON = 2
COMPILATION_TYPE_EVAL = 1
};
// [source]: the script source.

View File

@ -1382,56 +1382,6 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) {
}
FunctionLiteral* Parser::ParseJson(Handle<String> source) {
CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
HistogramTimerScope timer(&Counters::parse);
Counters::total_parse_size.Increment(source->length());
// Initialize parser state.
source->TryFlatten(TENURED);
scanner_.Initialize(source, JSON);
ASSERT(target_stack_ == NULL);
FunctionLiteral* result = NULL;
Handle<String> no_name = factory()->EmptySymbol();
{
Scope* scope = factory()->NewScope(top_scope_, Scope::GLOBAL_SCOPE, false);
LexicalScope lexical_scope(this, scope);
TemporaryScope temp_scope(this);
bool ok = true;
Expression* expression = ParseJson(&ok);
if (ok) {
ZoneListWrapper<Statement> statement = factory()->NewList<Statement>(1);
statement.Add(new ExpressionStatement(expression));
result = NEW(FunctionLiteral(
no_name,
top_scope_,
statement.elements(),
temp_scope.materialized_literal_count(),
temp_scope.expected_property_count(),
temp_scope.only_simple_this_property_assignments(),
temp_scope.this_property_assignments(),
0,
0,
source->length(),
false,
temp_scope.ContainsLoops()));
} else if (scanner().stack_overflow()) {
Top::StackOverflow();
}
}
// Make sure the target stack is empty.
ASSERT(target_stack_ == NULL);
// If there was a syntax error we have to get rid of the AST
// and it is not safe to do so before the scope has been deleted.
if (result == NULL) zone_scope.DeleteOnExit();
return result;
}
void Parser::ReportMessage(const char* type, Vector<const char*> args) {
Scanner::Location source_location = scanner_.location();
ReportMessageAt(source_location, type, args);
@ -4281,145 +4231,165 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
// ----------------------------------------------------------------------------
// JSON
Expression* Parser::ParseJson(bool* ok) {
Expression* result = ParseJsonValue(CHECK_OK);
Expect(Token::EOS, CHECK_OK);
Handle<Object> JsonParser::ParseJson(Handle<String> source) {
source->TryFlatten();
scanner_.Initialize(source, JSON);
Handle<Object> result = ParseJsonValue();
if (result.is_null() || scanner_.Next() != Token::EOS) {
if (scanner_.stack_overflow()) {
// Scanner failed.
Top::StackOverflow();
} else {
// Parse failed. Scanner's current token is the unexpected token.
Token::Value token = scanner_.current_token();
const char* message;
const char* name_opt = NULL;
switch (token) {
case Token::EOS:
message = "unexpected_eos";
break;
case Token::NUMBER:
message = "unexpected_token_number";
break;
case Token::STRING:
message = "unexpected_token_string";
break;
case Token::IDENTIFIER:
message = "unexpected_token_identifier";
break;
default:
message = "unexpected_token";
name_opt = Token::String(token);
ASSERT(name_opt != NULL);
break;
}
Scanner::Location source_location = scanner_.location();
MessageLocation location(Factory::NewScript(source),
source_location.beg_pos,
source_location.end_pos);
int argc = (name_opt == NULL) ? 0 : 1;
Handle<JSArray> array = Factory::NewJSArray(argc);
if (name_opt != NULL) {
SetElement(array,
0,
Factory::NewStringFromUtf8(CStrVector(name_opt)));
}
Handle<Object> result = Factory::NewSyntaxError(message, array);
Top::Throw(*result, &location);
return Handle<Object>::null();
}
}
return result;
}
Handle<String> JsonParser::GetString() {
int literal_length = scanner_.literal_length();
if (literal_length == 0) {
return Factory::empty_string();
}
const char* literal_string = scanner_.literal_string();
Vector<const char> literal(literal_string, literal_length);
return Factory::NewStringFromUtf8(literal);
}
// Parse any JSON value.
Expression* Parser::ParseJsonValue(bool* ok) {
Token::Value token = peek();
Handle<Object> JsonParser::ParseJsonValue() {
Token::Value token = scanner_.Next();
switch (token) {
case Token::STRING: {
Consume(Token::STRING);
int literal_length = scanner_.literal_length();
const char* literal_string = scanner_.literal_string();
if (literal_length == 0) {
return NEW(Literal(Factory::empty_string()));
}
Vector<const char> literal(literal_string, literal_length);
return NEW(Literal(Factory::NewStringFromUtf8(literal, TENURED)));
return GetString();
}
case Token::NUMBER: {
Consume(Token::NUMBER);
ASSERT(scanner_.literal_length() > 0);
double value = StringToDouble(scanner_.literal(),
NO_FLAGS, // Hex, octal or trailing junk.
OS::nan_value());
return NewNumberLiteral(value);
return Factory::NewNumber(value);
}
case Token::FALSE_LITERAL:
Consume(Token::FALSE_LITERAL);
return NEW(Literal(Factory::false_value()));
return Factory::false_value();
case Token::TRUE_LITERAL:
Consume(Token::TRUE_LITERAL);
return NEW(Literal(Factory::true_value()));
return Factory::true_value();
case Token::NULL_LITERAL:
Consume(Token::NULL_LITERAL);
return NEW(Literal(Factory::null_value()));
case Token::LBRACE: {
Expression* result = ParseJsonObject(CHECK_OK);
return result;
}
case Token::LBRACK: {
Expression* result = ParseJsonArray(CHECK_OK);
return result;
}
return Factory::null_value();
case Token::LBRACE:
return ParseJsonObject();
case Token::LBRACK:
return ParseJsonArray();
default:
*ok = false;
ReportUnexpectedToken(token);
return NULL;
return ReportUnexpectedToken();
}
}
// Parse a JSON object. Scanner must be right after '{' token.
Expression* Parser::ParseJsonObject(bool* ok) {
Consume(Token::LBRACE);
ZoneListWrapper<ObjectLiteral::Property> properties =
factory()->NewList<ObjectLiteral::Property>(4);
int boilerplate_properties = 0;
if (peek() != Token::RBRACE) {
Handle<Object> JsonParser::ParseJsonObject() {
Handle<JSFunction> object_constructor(
Top::global_context()->object_function());
Handle<JSObject> json_object = Factory::NewJSObject(object_constructor);
if (scanner_.peek() == Token::RBRACE) {
scanner_.Next();
} else {
do {
Expect(Token::STRING, CHECK_OK);
Handle<String> key = GetSymbol(CHECK_OK);
Expect(Token::COLON, CHECK_OK);
Expression* value = ParseJsonValue(CHECK_OK);
Literal* key_literal;
if (scanner_.Next() != Token::STRING) {
return ReportUnexpectedToken();
}
Handle<String> key = GetString();
if (scanner_.Next() != Token::COLON) {
return ReportUnexpectedToken();
}
Handle<Object> value = ParseJsonValue();
if (value.is_null()) return Handle<Object>::null();
uint32_t index;
if (key->AsArrayIndex(&index)) {
key_literal = NewNumberLiteral(index);
SetElement(json_object, index, value);
} else {
key_literal = NEW(Literal(key));
SetProperty(json_object, key, value, NONE);
}
ObjectLiteral::Property* property =
NEW(ObjectLiteral::Property(key_literal, value));
properties.Add(property);
if (IsBoilerplateProperty(property)) {
boilerplate_properties++;
}
} while (Check(Token::COMMA));
} while (scanner_.Next() == Token::COMMA);
if (scanner_.current_token() != Token::RBRACE) {
return ReportUnexpectedToken();
}
}
Expect(Token::RBRACE, CHECK_OK);
int literal_index = temp_scope_->NextMaterializedLiteralIndex();
if (is_pre_parsing_) return NULL;
Handle<FixedArray> constant_properties =
Factory::NewFixedArray(boilerplate_properties * 2, TENURED);
bool is_simple = true;
bool fast_elements = true;
int depth = 1;
BuildObjectLiteralConstantProperties(properties.elements(),
constant_properties,
&is_simple,
&fast_elements,
&depth);
return new ObjectLiteral(constant_properties,
properties.elements(),
literal_index,
is_simple,
fast_elements,
depth);
return json_object;
}
// Parse a JSON array. Scanner must be right after '[' token.
Expression* Parser::ParseJsonArray(bool* ok) {
Consume(Token::LBRACK);
Handle<Object> JsonParser::ParseJsonArray() {
ZoneScope zone_scope(DELETE_ON_EXIT);
ZoneList<Handle<Object> > elements(4);
ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4);
if (peek() != Token::RBRACK) {
Token::Value token = scanner_.peek();
if (token == Token::RBRACK) {
scanner_.Next();
} else {
do {
Expression* exp = ParseJsonValue(CHECK_OK);
values.Add(exp);
} while (Check(Token::COMMA));
Handle<Object> element = ParseJsonValue();
if (element.is_null()) return Handle<Object>::null();
elements.Add(element);
token = scanner_.Next();
} while (token == Token::COMMA);
if (token != Token::RBRACK) {
return ReportUnexpectedToken();
}
}
Expect(Token::RBRACK, CHECK_OK);
// Update the scope information before the pre-parsing bailout.
int literal_index = temp_scope_->NextMaterializedLiteralIndex();
// Allocate a fixed array with all the elements.
Handle<FixedArray> fast_elements =
Factory::NewFixedArray(elements.length());
if (is_pre_parsing_) return NULL;
for (int i = 0, n = elements.length(); i < n; i++) {
fast_elements->set(i, *elements[i]);
}
// Allocate a fixed array with all the literals.
Handle<FixedArray> literals =
Factory::NewFixedArray(values.length(), TENURED);
bool is_simple;
int depth;
BuildArrayLiteralBoilerplateLiterals(values.elements(),
literals,
&is_simple,
&depth);
return NEW(ArrayLiteral(literals, values.elements(),
literal_index, is_simple, depth));
return Factory::NewJSArrayWithElements(fast_elements);
}
// ----------------------------------------------------------------------------
// Regular expressions
@ -5368,11 +5338,7 @@ bool Parser::Parse(CompilationInfo* info) {
ASSERT(Top::has_pending_exception());
} else {
Handle<String> source = Handle<String>(String::cast(script->source()));
// JSON is always global.
ASSERT(!info->is_json() || info->is_global());
result = info->is_json()
? parser.ParseJson(source)
: parser.ParseProgram(source, info->is_global());
result = parser.ParseProgram(source, info->is_global());
}
}

View File

@ -218,7 +218,6 @@ class Parser {
FunctionLiteral* ParseProgram(Handle<String> source,
bool in_global_context);
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info);
FunctionLiteral* ParseJson(Handle<String> source);
// The minimum number of contiguous assignment that will
// be treated as an initialization block. Benchmarks show that
@ -411,29 +410,6 @@ class Parser {
Handle<String> type,
Vector< Handle<Object> > arguments);
// JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5
// specification section 15.12.1 (and appendix A.8).
// The grammar is given section 15.12.1.2 (and appendix A.8.2).
// Parse JSON input as a single JSON value.
Expression* ParseJson(bool* ok);
// Parse a single JSON value from input (grammar production JSONValue).
// A JSON value is either a (double-quoted) string literal, a number literal,
// one of "true", "false", or "null", or an object or array literal.
Expression* ParseJsonValue(bool* ok);
// Parse a JSON object literal (grammar production JSONObject).
// An object literal is a squiggly-braced and comma separated sequence
// (possibly empty) of key/value pairs, where the key is a JSON string
// literal, the value is a JSON value, and the two are spearated by a colon.
// A JavaScript object also allows numbers and identifiers as keys.
Expression* ParseJsonObject(bool* ok);
// Parses a JSON array literal (grammar production JSONArray). An array
// literal is a square-bracketed and comma separated sequence (possibly empty)
// of JSON values.
// A JavaScript array allows leaving out values from the sequence.
Expression* ParseJsonArray(bool* ok);
friend class Target;
friend class TargetScope;
friend class LexicalScope;
@ -472,6 +448,49 @@ class CompileTimeValue: public AllStatic {
};
// JSON is a subset of JavaScript, as specified in, e.g., the ECMAScript 5
// specification section 15.12.1 (and appendix A.8).
// The grammar is given section 15.12.1.2 (and appendix A.8.2).
class JsonParser BASE_EMBEDDED {
public:
// Parse JSON input as a single JSON value.
// Returns null handle and sets exception if parsing failed.
static Handle<Object> Parse(Handle<String> source) {
return JsonParser().ParseJson(source);
}
private:
JsonParser() { }
~JsonParser() { }
// Parse a string containing a single JSON value.
Handle<Object> ParseJson(Handle<String>);
// Parse a single JSON value from input (grammar production JSONValue).
// A JSON value is either a (double-quoted) string literal, a number literal,
// one of "true", "false", or "null", or an object or array literal.
Handle<Object> ParseJsonValue();
// Parse a JSON object literal (grammar production JSONObject).
// An object literal is a squiggly-braced and comma separated sequence
// (possibly empty) of key/value pairs, where the key is a JSON string
// literal, the value is a JSON value, and the two are separated by a colon.
// A JSON array dosn't allow numbers and identifiers as keys, like a
// JavaScript array.
Handle<Object> ParseJsonObject();
// Parses a JSON array literal (grammar production JSONArray). An array
// literal is a square-bracketed and comma separated sequence (possibly empty)
// of JSON values.
// A JSON array doesn't allow leaving out values from the sequence, nor does
// it allow a terminal comma, like a JavaScript array does.
Handle<Object> ParseJsonArray();
// Mark that a parsing error has happened at the current token, and
// return a null handle. Primarily for readability.
Handle<Object> ReportUnexpectedToken() { return Handle<Object>::null(); }
// Converts the currently parsed literal to a JavaScript String.
Handle<String> GetString();
Scanner scanner_;
};
} } // namespace v8::internal
#endif // V8_PARSER_H_

View File

@ -7129,20 +7129,31 @@ static MaybeObject* Runtime_GlobalReceiver(Arguments args) {
}
static MaybeObject* Runtime_ParseJson(Arguments args) {
HandleScope scope;
ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0);
Handle<Object> result = JsonParser::Parse(source);
if (result.is_null()) {
// Syntax error or stack overflow in scanner.
ASSERT(Top::has_pending_exception());
return Failure::Exception();
}
return *result;
}
static MaybeObject* Runtime_CompileString(Arguments args) {
HandleScope scope;
ASSERT_EQ(2, args.length());
ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0);
CONVERT_ARG_CHECKED(Oddball, is_json, 1)
// Compile source string in the global context.
Handle<Context> context(Top::context()->global_context());
Compiler::ValidationState validate = (is_json->IsTrue())
? Compiler::VALIDATE_JSON : Compiler::DONT_VALIDATE_JSON;
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
context,
true,
validate);
true);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> fun =
Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
@ -7157,8 +7168,7 @@ static ObjectPair CompileGlobalEval(Handle<String> source,
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
source,
Handle<Context>(Top::context()),
Top::context()->IsGlobalContext(),
Compiler::DONT_VALIDATE_JSON);
Top::context()->IsGlobalContext());
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
shared,
@ -9370,8 +9380,7 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
Handle<SharedFunctionInfo> shared =
Compiler::CompileEval(function_source,
context,
context->IsGlobalContext(),
Compiler::DONT_VALIDATE_JSON);
context->IsGlobalContext());
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
Factory::NewFunctionFromSharedFunctionInfo(shared, context);
@ -9442,8 +9451,7 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
Handle<SharedFunctionInfo> shared =
Compiler::CompileEval(source,
context,
true,
Compiler::DONT_VALIDATE_JSON);
true);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,

View File

@ -164,6 +164,9 @@ namespace internal {
F(RegExpConstructResult, 3, 1) \
F(RegExpCloneResult, 1, 1) \
\
/* JSON */ \
F(ParseJson, 1, 1) \
\
/* Strings */ \
F(StringCharCodeAt, 2, 1) \
F(StringIndexOf, 3, 1) \
@ -222,7 +225,7 @@ namespace internal {
/* Numbers */ \
\
/* Globals */ \
F(CompileString, 2, 1) \
F(CompileString, 1, 1) \
F(GlobalPrint, 1, 1) \
\
/* Eval */ \

View File

@ -296,6 +296,9 @@ class Scanner {
// Returns the next token.
Token::Value Next();
// Returns the current token again.
Token::Value current_token() { return current_.token; }
// One token look-ahead (past the token returned by Next()).
Token::Value peek() const { return next_.token; }

View File

@ -140,7 +140,7 @@ function GlobalEval(x) {
'be the global object from which eval originated');
}
var f = %CompileString(x, false);
var f = %CompileString(x);
if (!IS_FUNCTION(f)) return f;
return f.call(this);
@ -151,7 +151,7 @@ function GlobalEval(x) {
function GlobalExecScript(expr, lang) {
// NOTE: We don't care about the character casing.
if (!lang || /javascript/i.test(lang)) {
var f = %CompileString(ToString(expr), false);
var f = %CompileString(ToString(expr));
f.call(%GlobalReceiver(global));
}
return null;
@ -1177,7 +1177,7 @@ function NewFunction(arg1) { // length == 1
// The call to SetNewFunctionAttributes will ensure the prototype
// property of the resulting function is enumerable (ECMA262, 15.3.5.2).
var f = %CompileString(source, false)();
var f = %CompileString(source)();
%FunctionSetName(f, "anonymous");
return %SetNewFunctionAttributes(f);
}

View File

@ -36,7 +36,6 @@ var current_source = ''; // Current source being compiled.
var source_count = 0; // Total number of scources compiled.
var host_compilations = 0; // Number of scources compiled through the API.
var eval_compilations = 0; // Number of scources compiled through eval.
var json_compilations = 0; // Number of scources compiled through JSON.parse.
function compileSource(source) {
@ -62,9 +61,6 @@ function listener(event, exec_state, event_data, data) {
case Debug.ScriptCompilationType.Eval:
eval_compilations++;
break;
case Debug.ScriptCompilationType.JSON:
json_compilations++;
break;
}
}
@ -74,13 +70,6 @@ function listener(event, exec_state, event_data, data) {
// For source with 'eval' there will be compile events with substrings
// as well as with with the exact source.
assertTrue(current_source.indexOf(event_data.script().source()) >= 0);
} else if (current_source.indexOf('JSON.parse') == 0) {
// For JSON the JSON source will be in parentheses.
var s = event_data.script().source();
if (s[0] == '(') {
s = s.substring(1, s.length - 2);
}
assertTrue(current_source.indexOf(s) >= 0);
} else {
// For source without 'eval' there will be a compile events with the
// exact source.
@ -113,7 +102,7 @@ source_count++; // Using eval causes additional compilation event.
compileSource('eval("eval(\'(function(){return a;})\')")');
source_count += 2; // Using eval causes additional compilation event.
compileSource('JSON.parse(\'{"a":1,"b":2}\')');
source_count++; // Using JSON.parse causes additional compilation event.
// Using JSON.parse does not causes additional compilation events.
compileSource('x=1; //@ sourceURL=myscript.js');
// Make sure that the debug event listener was invoked.
@ -123,10 +112,9 @@ assertFalse(exception, "exception in listener")
assertEquals(before_compile_count, after_compile_count);
// Check the actual number of events (no compilation through the API as all
// source compiled through eval except for one JSON.parse call).
// source compiled through eval).
assertEquals(source_count, after_compile_count);
assertEquals(0, host_compilations);
assertEquals(source_count - 1, eval_compilations);
assertEquals(1, json_compilations);
assertEquals(source_count, eval_compilations);
Debug.setListener(null);

View File

@ -83,12 +83,10 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type,
// Test the script mirror for different functions.
testScriptMirror(function(){}, 'mirror-script.js', 100, 2, 0);
testScriptMirror(function(){}, 'mirror-script.js', 98, 2, 0);
testScriptMirror(Math.sin, 'native math.js', -1, 0, 0);
testScriptMirror(eval('(function(){})'), null, 1, 2, 1, '(function(){})', 87);
testScriptMirror(eval('(function(){\n })'), null, 2, 2, 1, '(function(){\n })', 88);
testScriptMirror(%CompileString('{"a":1,"b":2}', true), null, 1, 2, 2, '{"a":1,"b":2}');
testScriptMirror(%CompileString('{"a":1,\n "b":2}', true), null, 2, 2, 2, '{"a":1,\n "b":2}');
// Test taking slices of source.
var mirror = debug.MakeMirror(eval('(function(){\n 1;\n})')).script();