Commit 938d88e1 authored by lrn@chromium.org's avatar lrn@chromium.org

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
parent a8f27144
...@@ -152,10 +152,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) { ...@@ -152,10 +152,8 @@ static Handle<SharedFunctionInfo> MakeFunctionInfo(CompilationInfo* info) {
script->set_context_data((*i::Top::global_context())->data()); script->set_context_data((*i::Top::global_context())->data());
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
if (info->is_eval() || info->is_json()) { if (info->is_eval()) {
Script::CompilationType compilation_type = info->is_json() Script::CompilationType compilation_type = Script::COMPILATION_TYPE_EVAL;
? Script::COMPILATION_TYPE_JSON
: Script::COMPILATION_TYPE_EVAL;
script->set_compilation_type(Smi::FromInt(compilation_type)); script->set_compilation_type(Smi::FromInt(compilation_type));
// For eval scripts add information on the function from which eval was // For eval scripts add information on the function from which eval was
// called. // called.
...@@ -323,13 +321,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, ...@@ -323,13 +321,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source,
Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
Handle<Context> context, Handle<Context> context,
bool is_global, 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);
int source_length = source->length(); int source_length = source->length();
Counters::total_eval_size.Increment(source_length); Counters::total_eval_size.Increment(source_length);
Counters::total_compile_size.Increment(source_length); Counters::total_compile_size.Increment(source_length);
...@@ -338,13 +330,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, ...@@ -338,13 +330,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
VMState state(COMPILER); VMState state(COMPILER);
// Do a lookup in the compilation cache; if the entry is not there, invoke // 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 // the compiler and add the result to the cache.
// we bypass the cache since we can't be sure a potential value in the
// cache has been validated.
Handle<SharedFunctionInfo> result; Handle<SharedFunctionInfo> result;
if (!is_json) {
result = CompilationCache::LookupEval(source, context, is_global); result = CompilationCache::LookupEval(source, context, is_global);
}
if (result.is_null()) { if (result.is_null()) {
// Create a script object describing the script to be compiled. // Create a script object describing the script to be compiled.
...@@ -352,12 +340,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, ...@@ -352,12 +340,9 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
CompilationInfo info(script); CompilationInfo info(script);
info.MarkAsEval(); info.MarkAsEval();
if (is_global) info.MarkAsGlobal(); if (is_global) info.MarkAsGlobal();
if (is_json) info.MarkAsJson();
info.SetCallingContext(context); info.SetCallingContext(context);
result = MakeFunctionInfo(&info); result = MakeFunctionInfo(&info);
if (!result.is_null() && !is_json) { if (!result.is_null()) {
// For json it's unlikely that we'll ever see exactly the same string
// again so we don't use the compilation cache.
CompilationCache::PutEval(source, context, is_global, result); CompilationCache::PutEval(source, context, is_global, result);
} }
} }
......
...@@ -49,7 +49,6 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -49,7 +49,6 @@ class CompilationInfo BASE_EMBEDDED {
bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; } bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
bool is_eval() const { return (flags_ & IsEval::mask()) != 0; } bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
bool is_global() const { return (flags_ & IsGlobal::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; } bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
FunctionLiteral* function() const { return function_; } FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; } Scope* scope() const { return scope_; }
...@@ -69,10 +68,6 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -69,10 +68,6 @@ class CompilationInfo BASE_EMBEDDED {
ASSERT(!is_lazy()); ASSERT(!is_lazy());
flags_ |= IsGlobal::encode(true); flags_ |= IsGlobal::encode(true);
} }
void MarkAsJson() {
ASSERT(!is_lazy());
flags_ |= IsJson::encode(true);
}
void MarkAsInLoop() { void MarkAsInLoop() {
ASSERT(is_lazy()); ASSERT(is_lazy());
flags_ |= IsInLoop::encode(true); flags_ |= IsInLoop::encode(true);
...@@ -108,16 +103,15 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -108,16 +103,15 @@ class CompilationInfo BASE_EMBEDDED {
// Flags that can be set for eager compilation. // Flags that can be set for eager compilation.
class IsEval: public BitField<bool, 1, 1> {}; class IsEval: public BitField<bool, 1, 1> {};
class IsGlobal: public BitField<bool, 2, 1> {}; class IsGlobal: public BitField<bool, 2, 1> {};
class IsJson: public BitField<bool, 3, 1> {};
// Flags that can be set for lazy compilation. // Flags that can be set for lazy compilation.
class IsInLoop: public BitField<bool, 4, 1> {}; class IsInLoop: public BitField<bool, 3, 1> {};
unsigned flags_; unsigned flags_;
// Fields filled in by the compilation pipeline. // Fields filled in by the compilation pipeline.
// AST filled in by the parser. // AST filled in by the parser.
FunctionLiteral* function_; 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. // that scopes have been analyzed.
Scope* scope_; Scope* scope_;
// The compiled code. // The compiled code.
...@@ -153,8 +147,6 @@ class CompilationInfo BASE_EMBEDDED { ...@@ -153,8 +147,6 @@ class CompilationInfo BASE_EMBEDDED {
class Compiler : public AllStatic { class Compiler : public AllStatic {
public: public:
enum ValidationState { DONT_VALIDATE_JSON, VALIDATE_JSON };
// All routines return a JSFunction. // All routines return a JSFunction.
// If an error occurs an exception is raised and // If an error occurs an exception is raised and
// the return handle contains NULL. // the return handle contains NULL.
...@@ -172,8 +164,7 @@ class Compiler : public AllStatic { ...@@ -172,8 +164,7 @@ class Compiler : public AllStatic {
// Compile a String source within a context for Eval. // Compile a String source within a context for Eval.
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source, static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
Handle<Context> context, Handle<Context> context,
bool is_global, bool is_global);
ValidationState validation);
// Compile from function info (used for lazy compilation). Returns true on // Compile from function info (used for lazy compilation). Returns true on
// success and false if the compilation resulted in a stack overflow. // success and false if the compilation resulted in a stack overflow.
......
...@@ -1301,7 +1301,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request) ...@@ -1301,7 +1301,7 @@ DebugCommandProcessor.prototype.processDebugJSONRequest = function(json_request)
try { try {
try { try {
// Convert the JSON string to an object. // Convert the JSON string to an object.
request = %CompileString('(' + json_request + ')', false)(); request = %CompileString('(' + json_request + ')')();
// Create an initial response. // Create an initial response.
response = this.createResponse(request); response = this.createResponse(request);
......
...@@ -29,8 +29,7 @@ var $JSON = global.JSON; ...@@ -29,8 +29,7 @@ var $JSON = global.JSON;
function ParseJSONUnfiltered(text) { function ParseJSONUnfiltered(text) {
var s = $String(text); var s = $String(text);
var f = %CompileString(s, true); return %ParseJson(s);
return f();
} }
function Revive(holder, name, reviver) { function Revive(holder, name, reviver) {
......
...@@ -3409,8 +3409,7 @@ class Script: public Struct { ...@@ -3409,8 +3409,7 @@ class Script: public Struct {
// Script compilation types. // Script compilation types.
enum CompilationType { enum CompilationType {
COMPILATION_TYPE_HOST = 0, COMPILATION_TYPE_HOST = 0,
COMPILATION_TYPE_EVAL = 1, COMPILATION_TYPE_EVAL = 1
COMPILATION_TYPE_JSON = 2
}; };
// [source]: the script source. // [source]: the script source.
......
...@@ -1382,56 +1382,6 @@ FunctionLiteral* Parser::ParseLazy(Handle<SharedFunctionInfo> info) { ...@@ -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) { void Parser::ReportMessage(const char* type, Vector<const char*> args) {
Scanner::Location source_location = scanner_.location(); Scanner::Location source_location = scanner_.location();
ReportMessageAt(source_location, type, args); ReportMessageAt(source_location, type, args);
...@@ -4281,145 +4231,165 @@ Expression* Parser::NewThrowError(Handle<String> constructor, ...@@ -4281,145 +4231,165 @@ Expression* Parser::NewThrowError(Handle<String> constructor,
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// JSON // JSON
Expression* Parser::ParseJson(bool* ok) { Handle<Object> JsonParser::ParseJson(Handle<String> source) {
Expression* result = ParseJsonValue(CHECK_OK); source->TryFlatten();
Expect(Token::EOS, CHECK_OK); 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; return result;
} }
// Parse any JSON value. Handle<String> JsonParser::GetString() {
Expression* Parser::ParseJsonValue(bool* ok) {
Token::Value token = peek();
switch (token) {
case Token::STRING: {
Consume(Token::STRING);
int literal_length = scanner_.literal_length(); int literal_length = scanner_.literal_length();
const char* literal_string = scanner_.literal_string();
if (literal_length == 0) { if (literal_length == 0) {
return NEW(Literal(Factory::empty_string())); return Factory::empty_string();
} }
const char* literal_string = scanner_.literal_string();
Vector<const char> literal(literal_string, literal_length); Vector<const char> literal(literal_string, literal_length);
return NEW(Literal(Factory::NewStringFromUtf8(literal, TENURED))); return Factory::NewStringFromUtf8(literal);
}
// Parse any JSON value.
Handle<Object> JsonParser::ParseJsonValue() {
Token::Value token = scanner_.Next();
switch (token) {
case Token::STRING: {
return GetString();
} }
case Token::NUMBER: { case Token::NUMBER: {
Consume(Token::NUMBER);
ASSERT(scanner_.literal_length() > 0);
double value = StringToDouble(scanner_.literal(), double value = StringToDouble(scanner_.literal(),
NO_FLAGS, // Hex, octal or trailing junk. NO_FLAGS, // Hex, octal or trailing junk.
OS::nan_value()); OS::nan_value());
return NewNumberLiteral(value); return Factory::NewNumber(value);
} }
case Token::FALSE_LITERAL: case Token::FALSE_LITERAL:
Consume(Token::FALSE_LITERAL); return Factory::false_value();
return NEW(Literal(Factory::false_value()));
case Token::TRUE_LITERAL: case Token::TRUE_LITERAL:
Consume(Token::TRUE_LITERAL); return Factory::true_value();
return NEW(Literal(Factory::true_value()));
case Token::NULL_LITERAL: case Token::NULL_LITERAL:
Consume(Token::NULL_LITERAL); return Factory::null_value();
return NEW(Literal(Factory::null_value())); case Token::LBRACE:
case Token::LBRACE: { return ParseJsonObject();
Expression* result = ParseJsonObject(CHECK_OK); case Token::LBRACK:
return result; return ParseJsonArray();
}
case Token::LBRACK: {
Expression* result = ParseJsonArray(CHECK_OK);
return result;
}
default: default:
*ok = false; return ReportUnexpectedToken();
ReportUnexpectedToken(token);
return NULL;
} }
} }
// Parse a JSON object. Scanner must be right after '{' token. // Parse a JSON object. Scanner must be right after '{' token.
Expression* Parser::ParseJsonObject(bool* ok) { Handle<Object> JsonParser::ParseJsonObject() {
Consume(Token::LBRACE); Handle<JSFunction> object_constructor(
ZoneListWrapper<ObjectLiteral::Property> properties = Top::global_context()->object_function());
factory()->NewList<ObjectLiteral::Property>(4); Handle<JSObject> json_object = Factory::NewJSObject(object_constructor);
int boilerplate_properties = 0; if (scanner_.peek() == Token::RBRACE) {
if (peek() != Token::RBRACE) { scanner_.Next();
} else {
do { do {
Expect(Token::STRING, CHECK_OK); if (scanner_.Next() != Token::STRING) {
Handle<String> key = GetSymbol(CHECK_OK); return ReportUnexpectedToken();
Expect(Token::COLON, CHECK_OK); }
Expression* value = ParseJsonValue(CHECK_OK); Handle<String> key = GetString();
Literal* key_literal; if (scanner_.Next() != Token::COLON) {
return ReportUnexpectedToken();
}
Handle<Object> value = ParseJsonValue();
if (value.is_null()) return Handle<Object>::null();
uint32_t index; uint32_t index;
if (key->AsArrayIndex(&index)) { if (key->AsArrayIndex(&index)) {
key_literal = NewNumberLiteral(index); SetElement(json_object, index, value);
} else { } else {
key_literal = NEW(Literal(key)); SetProperty(json_object, key, value, NONE);
} }
ObjectLiteral::Property* property = } while (scanner_.Next() == Token::COMMA);
NEW(ObjectLiteral::Property(key_literal, value)); if (scanner_.current_token() != Token::RBRACE) {
properties.Add(property); return ReportUnexpectedToken();
if (IsBoilerplateProperty(property)) {
boilerplate_properties++;
} }
} while (Check(Token::COMMA));
} }
Expect(Token::RBRACE, CHECK_OK); return json_object;
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);
} }
// Parse a JSON array. Scanner must be right after '[' token. // Parse a JSON array. Scanner must be right after '[' token.
Expression* Parser::ParseJsonArray(bool* ok) { Handle<Object> JsonParser::ParseJsonArray() {
Consume(Token::LBRACK); ZoneScope zone_scope(DELETE_ON_EXIT);
ZoneList<Handle<Object> > elements(4);
ZoneListWrapper<Expression> values = factory()->NewList<Expression>(4); Token::Value token = scanner_.peek();
if (peek() != Token::RBRACK) { if (token == Token::RBRACK) {
scanner_.Next();
} else {
do { do {
Expression* exp = ParseJsonValue(CHECK_OK); Handle<Object> element = ParseJsonValue();
values.Add(exp); if (element.is_null()) return Handle<Object>::null();
} while (Check(Token::COMMA)); 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();
if (is_pre_parsing_) return NULL; // Allocate a fixed array with all the elements.
Handle<FixedArray> fast_elements =
Factory::NewFixedArray(elements.length());
// Allocate a fixed array with all the literals. for (int i = 0, n = elements.length(); i < n; i++) {
Handle<FixedArray> literals = fast_elements->set(i, *elements[i]);
Factory::NewFixedArray(values.length(), TENURED); }
bool is_simple; return Factory::NewJSArrayWithElements(fast_elements);
int depth;
BuildArrayLiteralBoilerplateLiterals(values.elements(),
literals,
&is_simple,
&depth);
return NEW(ArrayLiteral(literals, values.elements(),
literal_index, is_simple, depth));
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Regular expressions // Regular expressions
...@@ -5368,11 +5338,7 @@ bool Parser::Parse(CompilationInfo* info) { ...@@ -5368,11 +5338,7 @@ bool Parser::Parse(CompilationInfo* info) {
ASSERT(Top::has_pending_exception()); ASSERT(Top::has_pending_exception());
} else { } else {
Handle<String> source = Handle<String>(String::cast(script->source())); Handle<String> source = Handle<String>(String::cast(script->source()));
// JSON is always global. result = parser.ParseProgram(source, info->is_global());
ASSERT(!info->is_json() || info->is_global());
result = info->is_json()
? parser.ParseJson(source)
: parser.ParseProgram(source, info->is_global());
} }
} }
......
...@@ -218,7 +218,6 @@ class Parser { ...@@ -218,7 +218,6 @@ class Parser {
FunctionLiteral* ParseProgram(Handle<String> source, FunctionLiteral* ParseProgram(Handle<String> source,
bool in_global_context); bool in_global_context);
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info); FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info);
FunctionLiteral* ParseJson(Handle<String> source);
// The minimum number of contiguous assignment that will // The minimum number of contiguous assignment that will
// be treated as an initialization block. Benchmarks show that // be treated as an initialization block. Benchmarks show that
...@@ -411,29 +410,6 @@ class Parser { ...@@ -411,29 +410,6 @@ class Parser {
Handle<String> type, Handle<String> type,
Vector< Handle<Object> > arguments); 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 Target;
friend class TargetScope; friend class TargetScope;
friend class LexicalScope; friend class LexicalScope;
...@@ -472,6 +448,49 @@ class CompileTimeValue: public AllStatic { ...@@ -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 } } // namespace v8::internal
#endif // V8_PARSER_H_ #endif // V8_PARSER_H_
...@@ -7129,20 +7129,31 @@ static MaybeObject* Runtime_GlobalReceiver(Arguments args) { ...@@ -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) { static MaybeObject* Runtime_CompileString(Arguments args) {
HandleScope scope; HandleScope scope;
ASSERT_EQ(2, args.length()); ASSERT_EQ(1, args.length());
CONVERT_ARG_CHECKED(String, source, 0); CONVERT_ARG_CHECKED(String, source, 0);
CONVERT_ARG_CHECKED(Oddball, is_json, 1)
// Compile source string in the global context. // Compile source string in the global context.
Handle<Context> context(Top::context()->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, Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
context, context,
true, true);
validate);
if (shared.is_null()) return Failure::Exception(); if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> fun = Handle<JSFunction> fun =
Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED); Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
...@@ -7157,8 +7168,7 @@ static ObjectPair CompileGlobalEval(Handle<String> source, ...@@ -7157,8 +7168,7 @@ static ObjectPair CompileGlobalEval(Handle<String> source,
Handle<SharedFunctionInfo> shared = Compiler::CompileEval( Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
source, source,
Handle<Context>(Top::context()), Handle<Context>(Top::context()),
Top::context()->IsGlobalContext(), Top::context()->IsGlobalContext());
Compiler::DONT_VALIDATE_JSON);
if (shared.is_null()) return MakePair(Failure::Exception(), NULL); if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo( Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
shared, shared,
...@@ -9370,8 +9380,7 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) { ...@@ -9370,8 +9380,7 @@ static MaybeObject* Runtime_DebugEvaluate(Arguments args) {
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo> shared =
Compiler::CompileEval(function_source, Compiler::CompileEval(function_source,
context, context,
context->IsGlobalContext(), context->IsGlobalContext());
Compiler::DONT_VALIDATE_JSON);
if (shared.is_null()) return Failure::Exception(); if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function = Handle<JSFunction> compiled_function =
Factory::NewFunctionFromSharedFunctionInfo(shared, context); Factory::NewFunctionFromSharedFunctionInfo(shared, context);
...@@ -9442,8 +9451,7 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) { ...@@ -9442,8 +9451,7 @@ static MaybeObject* Runtime_DebugEvaluateGlobal(Arguments args) {
Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo> shared =
Compiler::CompileEval(source, Compiler::CompileEval(source,
context, context,
true, true);
Compiler::DONT_VALIDATE_JSON);
if (shared.is_null()) return Failure::Exception(); if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function = Handle<JSFunction> compiled_function =
Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared, Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
......
...@@ -164,6 +164,9 @@ namespace internal { ...@@ -164,6 +164,9 @@ namespace internal {
F(RegExpConstructResult, 3, 1) \ F(RegExpConstructResult, 3, 1) \
F(RegExpCloneResult, 1, 1) \ F(RegExpCloneResult, 1, 1) \
\ \
/* JSON */ \
F(ParseJson, 1, 1) \
\
/* Strings */ \ /* Strings */ \
F(StringCharCodeAt, 2, 1) \ F(StringCharCodeAt, 2, 1) \
F(StringIndexOf, 3, 1) \ F(StringIndexOf, 3, 1) \
...@@ -222,7 +225,7 @@ namespace internal { ...@@ -222,7 +225,7 @@ namespace internal {
/* Numbers */ \ /* Numbers */ \
\ \
/* Globals */ \ /* Globals */ \
F(CompileString, 2, 1) \ F(CompileString, 1, 1) \
F(GlobalPrint, 1, 1) \ F(GlobalPrint, 1, 1) \
\ \
/* Eval */ \ /* Eval */ \
......
...@@ -296,6 +296,9 @@ class Scanner { ...@@ -296,6 +296,9 @@ class Scanner {
// Returns the next token. // Returns the next token.
Token::Value Next(); 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()). // One token look-ahead (past the token returned by Next()).
Token::Value peek() const { return next_.token; } Token::Value peek() const { return next_.token; }
......
...@@ -140,7 +140,7 @@ function GlobalEval(x) { ...@@ -140,7 +140,7 @@ function GlobalEval(x) {
'be the global object from which eval originated'); 'be the global object from which eval originated');
} }
var f = %CompileString(x, false); var f = %CompileString(x);
if (!IS_FUNCTION(f)) return f; if (!IS_FUNCTION(f)) return f;
return f.call(this); return f.call(this);
...@@ -151,7 +151,7 @@ function GlobalEval(x) { ...@@ -151,7 +151,7 @@ function GlobalEval(x) {
function GlobalExecScript(expr, lang) { function GlobalExecScript(expr, lang) {
// NOTE: We don't care about the character casing. // NOTE: We don't care about the character casing.
if (!lang || /javascript/i.test(lang)) { if (!lang || /javascript/i.test(lang)) {
var f = %CompileString(ToString(expr), false); var f = %CompileString(ToString(expr));
f.call(%GlobalReceiver(global)); f.call(%GlobalReceiver(global));
} }
return null; return null;
...@@ -1177,7 +1177,7 @@ function NewFunction(arg1) { // length == 1 ...@@ -1177,7 +1177,7 @@ function NewFunction(arg1) { // length == 1
// The call to SetNewFunctionAttributes will ensure the prototype // The call to SetNewFunctionAttributes will ensure the prototype
// property of the resulting function is enumerable (ECMA262, 15.3.5.2). // property of the resulting function is enumerable (ECMA262, 15.3.5.2).
var f = %CompileString(source, false)(); var f = %CompileString(source)();
%FunctionSetName(f, "anonymous"); %FunctionSetName(f, "anonymous");
return %SetNewFunctionAttributes(f); return %SetNewFunctionAttributes(f);
} }
......
...@@ -36,7 +36,6 @@ var current_source = ''; // Current source being compiled. ...@@ -36,7 +36,6 @@ var current_source = ''; // Current source being compiled.
var source_count = 0; // Total number of scources compiled. var source_count = 0; // Total number of scources compiled.
var host_compilations = 0; // Number of scources compiled through the API. var host_compilations = 0; // Number of scources compiled through the API.
var eval_compilations = 0; // Number of scources compiled through eval. var eval_compilations = 0; // Number of scources compiled through eval.
var json_compilations = 0; // Number of scources compiled through JSON.parse.
function compileSource(source) { function compileSource(source) {
...@@ -62,9 +61,6 @@ function listener(event, exec_state, event_data, data) { ...@@ -62,9 +61,6 @@ function listener(event, exec_state, event_data, data) {
case Debug.ScriptCompilationType.Eval: case Debug.ScriptCompilationType.Eval:
eval_compilations++; eval_compilations++;
break; break;
case Debug.ScriptCompilationType.JSON:
json_compilations++;
break;
} }
} }
...@@ -74,13 +70,6 @@ function listener(event, exec_state, event_data, data) { ...@@ -74,13 +70,6 @@ function listener(event, exec_state, event_data, data) {
// For source with 'eval' there will be compile events with substrings // For source with 'eval' there will be compile events with substrings
// as well as with with the exact source. // as well as with with the exact source.
assertTrue(current_source.indexOf(event_data.script().source()) >= 0); 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 { } else {
// For source without 'eval' there will be a compile events with the // For source without 'eval' there will be a compile events with the
// exact source. // exact source.
...@@ -113,7 +102,7 @@ source_count++; // Using eval causes additional compilation event. ...@@ -113,7 +102,7 @@ source_count++; // Using eval causes additional compilation event.
compileSource('eval("eval(\'(function(){return a;})\')")'); compileSource('eval("eval(\'(function(){return a;})\')")');
source_count += 2; // Using eval causes additional compilation event. source_count += 2; // Using eval causes additional compilation event.
compileSource('JSON.parse(\'{"a":1,"b":2}\')'); 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'); compileSource('x=1; //@ sourceURL=myscript.js');
// Make sure that the debug event listener was invoked. // Make sure that the debug event listener was invoked.
...@@ -123,10 +112,9 @@ assertFalse(exception, "exception in listener") ...@@ -123,10 +112,9 @@ assertFalse(exception, "exception in listener")
assertEquals(before_compile_count, after_compile_count); assertEquals(before_compile_count, after_compile_count);
// Check the actual number of events (no compilation through the API as all // 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(source_count, after_compile_count);
assertEquals(0, host_compilations); assertEquals(0, host_compilations);
assertEquals(source_count - 1, eval_compilations); assertEquals(source_count, eval_compilations);
assertEquals(1, json_compilations);
Debug.setListener(null); Debug.setListener(null);
...@@ -83,12 +83,10 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type, ...@@ -83,12 +83,10 @@ function testScriptMirror(f, file_name, file_lines, type, compilation_type,
// Test the script mirror for different functions. // 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(Math.sin, 'native math.js', -1, 0, 0);
testScriptMirror(eval('(function(){})'), null, 1, 2, 1, '(function(){})', 87); testScriptMirror(eval('(function(){})'), null, 1, 2, 1, '(function(){})', 87);
testScriptMirror(eval('(function(){\n })'), null, 2, 2, 1, '(function(){\n })', 88); 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. // Test taking slices of source.
var mirror = debug.MakeMirror(eval('(function(){\n 1;\n})')).script(); var mirror = debug.MakeMirror(eval('(function(){\n 1;\n})')).script();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment