diff options
author | Steve Block <steveblock@google.com> | 2011-05-24 12:43:12 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-24 13:42:09 +0100 |
commit | 1e0659c275bb392c045087af4f6b0d7565cb3d77 (patch) | |
tree | 09febd313ccef178417974f7b7098e89e20bfd93 /src/messages.js | |
parent | b8e0da25ee8efac3bb05cd6b2730aafbd96119f4 (diff) | |
download | android_external_v8-1e0659c275bb392c045087af4f6b0d7565cb3d77.tar.gz android_external_v8-1e0659c275bb392c045087af4f6b0d7565cb3d77.tar.bz2 android_external_v8-1e0659c275bb392c045087af4f6b0d7565cb3d77.zip |
Update V8 to r6768 as required by WebKit r78450
Change-Id: Ib8868ff7147a76547a8d1d85f257ebe8546a3d3f
Diffstat (limited to 'src/messages.js')
-rw-r--r-- | src/messages.js | 343 |
1 files changed, 192 insertions, 151 deletions
diff --git a/src/messages.js b/src/messages.js index a30ef8a9..1e41b178 100644 --- a/src/messages.js +++ b/src/messages.js @@ -38,10 +38,6 @@ var COMPILATION_TYPE_HOST = 0; var COMPILATION_TYPE_EVAL = 1; var COMPILATION_TYPE_JSON = 2; -// Lazily initialized. -var kVowelSounds = 0; -var kCapitalVowelSounds = 0; - // Matches Messages::kNoLineNumberInfo from v8.h var kNoLineNumberInfo = 0; @@ -50,61 +46,70 @@ var kNoLineNumberInfo = 0; // message on access. var kAddMessageAccessorsMarker = { }; +var kMessages = 0; -function GetInstanceName(cons) { - if (cons.length == 0) { - return ""; - } - var first = %StringToLowerCase(StringCharAt.call(cons, 0)); - if (kVowelSounds === 0) { - kVowelSounds = {a: true, e: true, i: true, o: true, u: true, y: true}; - kCapitalVowelSounds = {a: true, e: true, i: true, o: true, u: true, h: true, - f: true, l: true, m: true, n: true, r: true, s: true, x: true, y: true}; - } - var vowel_mapping = kVowelSounds; - if (cons.length > 1 && (StringCharAt.call(cons, 0) != first)) { - // First char is upper case - var second = %StringToLowerCase(StringCharAt.call(cons, 1)); - // Second char is upper case - if (StringCharAt.call(cons, 1) != second) { - vowel_mapping = kCapitalVowelSounds; +var kReplacementMarkers = [ "%0", "%1", "%2", "%3" ]; + +function FormatString(format, message) { + var args = %MessageGetArguments(message); + var result = ""; + var arg_num = 0; + for (var i = 0; i < format.length; i++) { + var str = format[i]; + for (arg_num = 0; arg_num < kReplacementMarkers.length; arg_num++) { + if (format[i] !== kReplacementMarkers[arg_num]) continue; + try { + str = ToDetailString(args[arg_num]); + } catch (e) { + str = "#<error>"; + } } + result += str; } - var s = vowel_mapping[first] ? "an " : "a "; - return s + cons; + return result; } -var kMessages = 0; +// To check if something is a native error we need to check the +// concrete native error types. It is not enough to check "obj +// instanceof $Error" because user code can replace +// NativeError.prototype.__proto__. User code cannot replace +// NativeError.prototype though and therefore this is a safe test. +function IsNativeErrorObject(obj) { + return (obj instanceof $Error) || + (obj instanceof $EvalError) || + (obj instanceof $RangeError) || + (obj instanceof $ReferenceError) || + (obj instanceof $SyntaxError) || + (obj instanceof $TypeError) || + (obj instanceof $URIError); +} -function FormatString(format, args) { - var result = format; - for (var i = 0; i < args.length; i++) { - var str; - try { str = ToDetailString(args[i]); } - catch (e) { str = "#<error>"; } - result = ArrayJoin.call(StringSplit.call(result, "%" + i), str); +// When formatting internally created error messages, do not +// invoke overwritten error toString methods but explicitly use +// the error to string method. This is to avoid leaking error +// objects between script tags in a browser setting. +function ToStringCheckErrorObject(obj) { + if (IsNativeErrorObject(obj)) { + return %_CallFunction(obj, errorToString); + } else { + return ToString(obj); } - return result; } function ToDetailString(obj) { if (obj != null && IS_OBJECT(obj) && obj.toString === $Object.prototype.toString) { var constructor = obj.constructor; - if (!constructor) return ToString(obj); + if (!constructor) return ToStringCheckErrorObject(obj); var constructorName = constructor.name; - if (!constructorName) return ToString(obj); - return "#<" + GetInstanceName(constructorName) + ">"; - } else if (obj instanceof $Error) { - // When formatting internally created error messages, do not - // invoke overwritten error toString methods but explicitly use - // the error to string method. This is to avoid leaking error - // objects between script tags in a browser setting. - return %_CallFunction(obj, errorToString); + if (!constructorName || !IS_STRING(constructorName)) { + return ToStringCheckErrorObject(obj); + } + return "#<" + constructorName + ">"; } else { - return ToString(obj); + return ToStringCheckErrorObject(obj); } } @@ -136,84 +141,103 @@ function FormatMessage(message) { if (kMessages === 0) { kMessages = { // Error - cyclic_proto: "Cyclic __proto__ value", + cyclic_proto: ["Cyclic __proto__ value"], // TypeError - unexpected_token: "Unexpected token %0", - unexpected_token_number: "Unexpected number", - unexpected_token_string: "Unexpected string", - unexpected_token_identifier: "Unexpected identifier", - unexpected_eos: "Unexpected end of input", - malformed_regexp: "Invalid regular expression: /%0/: %1", - unterminated_regexp: "Invalid regular expression: missing /", - regexp_flags: "Cannot supply flags when constructing one RegExp from another", - incompatible_method_receiver: "Method %0 called on incompatible receiver %1", - invalid_lhs_in_assignment: "Invalid left-hand side in assignment", - invalid_lhs_in_for_in: "Invalid left-hand side in for-in", - invalid_lhs_in_postfix_op: "Invalid left-hand side expression in postfix operation", - invalid_lhs_in_prefix_op: "Invalid left-hand side expression in prefix operation", - multiple_defaults_in_switch: "More than one default clause in switch statement", - newline_after_throw: "Illegal newline after throw", - redeclaration: "%0 '%1' has already been declared", - no_catch_or_finally: "Missing catch or finally after try", - unknown_label: "Undefined label '%0'", - uncaught_exception: "Uncaught %0", - stack_trace: "Stack Trace:\n%0", - called_non_callable: "%0 is not a function", - undefined_method: "Object %1 has no method '%0'", - property_not_function: "Property '%0' of object %1 is not a function", - cannot_convert_to_primitive: "Cannot convert object to primitive value", - not_constructor: "%0 is not a constructor", - not_defined: "%0 is not defined", - non_object_property_load: "Cannot read property '%0' of %1", - non_object_property_store: "Cannot set property '%0' of %1", - non_object_property_call: "Cannot call method '%0' of %1", - with_expression: "%0 has no properties", - illegal_invocation: "Illegal invocation", - no_setter_in_callback: "Cannot set property %0 of %1 which has only a getter", - apply_non_function: "Function.prototype.apply was called on %0, which is a %1 and not a function", - apply_wrong_args: "Function.prototype.apply: Arguments list has wrong type", - invalid_in_operator_use: "Cannot use 'in' operator to search for '%0' in %1", - instanceof_function_expected: "Expecting a function in instanceof check, but got %0", - instanceof_nonobject_proto: "Function has non-object prototype '%0' in instanceof check", - null_to_object: "Cannot convert null to object", - reduce_no_initial: "Reduce of empty array with no initial value", - getter_must_be_callable: "Getter must be a function: %0", - setter_must_be_callable: "Setter must be a function: %0", - value_and_accessor: "Invalid property. A property cannot both have accessors and be writable or have a value: %0", - proto_object_or_null: "Object prototype may only be an Object or null", - property_desc_object: "Property description must be an object: %0", - redefine_disallowed: "Cannot redefine property: %0", - define_disallowed: "Cannot define property, object is not extensible: %0", + unexpected_token: ["Unexpected token ", "%0"], + unexpected_token_number: ["Unexpected number"], + unexpected_token_string: ["Unexpected string"], + unexpected_token_identifier: ["Unexpected identifier"], + unexpected_strict_reserved: ["Unexpected strict mode reserved word"], + unexpected_eos: ["Unexpected end of input"], + malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"], + unterminated_regexp: ["Invalid regular expression: missing /"], + regexp_flags: ["Cannot supply flags when constructing one RegExp from another"], + incompatible_method_receiver: ["Method ", "%0", " called on incompatible receiver ", "%1"], + invalid_lhs_in_assignment: ["Invalid left-hand side in assignment"], + invalid_lhs_in_for_in: ["Invalid left-hand side in for-in"], + invalid_lhs_in_postfix_op: ["Invalid left-hand side expression in postfix operation"], + invalid_lhs_in_prefix_op: ["Invalid left-hand side expression in prefix operation"], + multiple_defaults_in_switch: ["More than one default clause in switch statement"], + newline_after_throw: ["Illegal newline after throw"], + redeclaration: ["%0", " '", "%1", "' has already been declared"], + no_catch_or_finally: ["Missing catch or finally after try"], + unknown_label: ["Undefined label '", "%0", "'"], + uncaught_exception: ["Uncaught ", "%0"], + stack_trace: ["Stack Trace:\n", "%0"], + called_non_callable: ["%0", " is not a function"], + undefined_method: ["Object ", "%1", " has no method '", "%0", "'"], + property_not_function: ["Property '", "%0", "' of object ", "%1", " is not a function"], + cannot_convert_to_primitive: ["Cannot convert object to primitive value"], + not_constructor: ["%0", " is not a constructor"], + not_defined: ["%0", " is not defined"], + non_object_property_load: ["Cannot read property '", "%0", "' of ", "%1"], + non_object_property_store: ["Cannot set property '", "%0", "' of ", "%1"], + non_object_property_call: ["Cannot call method '", "%0", "' of ", "%1"], + with_expression: ["%0", " has no properties"], + illegal_invocation: ["Illegal invocation"], + no_setter_in_callback: ["Cannot set property ", "%0", " of ", "%1", " which has only a getter"], + apply_non_function: ["Function.prototype.apply was called on ", "%0", ", which is a ", "%1", " and not a function"], + apply_wrong_args: ["Function.prototype.apply: Arguments list has wrong type"], + invalid_in_operator_use: ["Cannot use 'in' operator to search for '", "%0", "' in ", "%1"], + instanceof_function_expected: ["Expecting a function in instanceof check, but got ", "%0"], + instanceof_nonobject_proto: ["Function has non-object prototype '", "%0", "' in instanceof check"], + null_to_object: ["Cannot convert null to object"], + reduce_no_initial: ["Reduce of empty array with no initial value"], + getter_must_be_callable: ["Getter must be a function: ", "%0"], + setter_must_be_callable: ["Setter must be a function: ", "%0"], + value_and_accessor: ["Invalid property. A property cannot both have accessors and be writable or have a value: ", "%0"], + proto_object_or_null: ["Object prototype may only be an Object or null"], + property_desc_object: ["Property description must be an object: ", "%0"], + redefine_disallowed: ["Cannot redefine property: ", "%0"], + define_disallowed: ["Cannot define property, object is not extensible: ", "%0"], // RangeError - invalid_array_length: "Invalid array length", - stack_overflow: "Maximum call stack size exceeded", + invalid_array_length: ["Invalid array length"], + stack_overflow: ["Maximum call stack size exceeded"], // SyntaxError - unable_to_parse: "Parse error", - duplicate_regexp_flag: "Duplicate RegExp flag %0", - invalid_regexp: "Invalid RegExp pattern /%0/", - illegal_break: "Illegal break statement", - illegal_continue: "Illegal continue statement", - illegal_return: "Illegal return statement", - error_loading_debugger: "Error loading debugger", - no_input_to_regexp: "No input to %0", - invalid_json: "String '%0' is not valid JSON", - circular_structure: "Converting circular structure to JSON", - obj_ctor_property_non_object: "Object.%0 called on non-object", - array_indexof_not_defined: "Array.getIndexOf: Argument undefined", - object_not_extensible: "Can't add property %0, object is not extensible", - illegal_access: "Illegal access", - invalid_preparser_data: "Invalid preparser data for function %0" + unable_to_parse: ["Parse error"], + duplicate_regexp_flag: ["Duplicate RegExp flag ", "%0"], + invalid_regexp: ["Invalid RegExp pattern /", "%0", "/"], + illegal_break: ["Illegal break statement"], + illegal_continue: ["Illegal continue statement"], + illegal_return: ["Illegal return statement"], + error_loading_debugger: ["Error loading debugger"], + no_input_to_regexp: ["No input to ", "%0"], + invalid_json: ["String '", "%0", "' is not valid JSON"], + circular_structure: ["Converting circular structure to JSON"], + obj_ctor_property_non_object: ["Object.", "%0", " called on non-object"], + array_indexof_not_defined: ["Array.getIndexOf: Argument undefined"], + object_not_extensible: ["Can't add property ", "%0", ", object is not extensible"], + illegal_access: ["Illegal access"], + invalid_preparser_data: ["Invalid preparser data for function ", "%0"], + strict_mode_with: ["Strict mode code may not include a with statement"], + strict_catch_variable: ["Catch variable may not be eval or arguments in strict mode"], + too_many_parameters: ["Too many parameters in function definition"], + strict_param_name: ["Parameter name eval or arguments is not allowed in strict mode"], + strict_param_dupe: ["Strict mode function may not have duplicate parameter names"], + strict_var_name: ["Variable name may not be eval or arguments in strict mode"], + strict_function_name: ["Function name may not be eval or arguments in strict mode"], + strict_octal_literal: ["Octal literals are not allowed in strict mode."], + strict_duplicate_property: ["Duplicate data property in object literal not allowed in strict mode"], + accessor_data_property: ["Object literal may not have data and accessor property with the same name"], + accessor_get_set: ["Object literal may not have multiple get/set accessors with the same name"], + strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"], + strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"], + strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"], + strict_reserved_word: ["Use of future reserved word in strict mode"], }; } - var format = kMessages[message.type]; - if (!format) return "<unknown message " + message.type + ">"; - return FormatString(format, message.args); + var message_type = %MessageGetType(message); + var format = kMessages[message_type]; + if (!format) return "<unknown message " + message_type + ">"; + return FormatString(format, message); } function GetLineNumber(message) { - if (message.startPos == -1) return kNoLineNumberInfo; - var location = message.script.locationFromPosition(message.startPos, true); + var start_position = %MessageGetStartPosition(message); + if (start_position == -1) return kNoLineNumberInfo; + var script = %MessageGetScript(message); + var location = script.locationFromPosition(start_position, true); if (location == null) return kNoLineNumberInfo; return location.line + 1; } @@ -222,7 +246,9 @@ function GetLineNumber(message) { // Returns the source code line containing the given source // position, or the empty string if the position is invalid. function GetSourceLine(message) { - var location = message.script.locationFromPosition(message.startPos, true); + var script = %MessageGetScript(message); + var start_position = %MessageGetStartPosition(message); + var location = script.locationFromPosition(start_position, true); if (location == null) return ""; location.restrict(); return location.sourceText(); @@ -291,6 +317,7 @@ Script.prototype.lineFromPosition = function(position) { return i; } } + return -1; } @@ -311,7 +338,7 @@ Script.prototype.locationFromPosition = function (position, var line_ends = this.line_ends; var start = line == 0 ? 0 : line_ends[line - 1] + 1; var end = line_ends[line]; - if (end > 0 && StringCharAt.call(this.source, end - 1) == '\r') end--; + if (end > 0 && %_CallFunction(this.source, end - 1, StringCharAt) == '\r') end--; var column = position - start; // Adjust according to the offset within the resource. @@ -426,7 +453,7 @@ Script.prototype.sourceLine = function (opt_line) { var line_ends = this.line_ends; var start = line == 0 ? 0 : line_ends[line - 1] + 1; var end = line_ends[line]; - return StringSubstring.call(this.source, start, end); + return %_CallFunction(this.source, start, end, StringSubstring); } @@ -554,7 +581,7 @@ SourceLocation.prototype.restrict = function (opt_limit, opt_before) { * Source text for this location. */ SourceLocation.prototype.sourceText = function () { - return StringSubstring.call(this.script.source, this.start, this.end); + return %_CallFunction(this.script.source, this.start, this.end, StringSubstring); }; @@ -591,36 +618,22 @@ function SourceSlice(script, from_line, to_line, from_position, to_position) { * the line terminating characters (if any) */ SourceSlice.prototype.sourceText = function () { - return StringSubstring.call(this.script.source, this.from_position, this.to_position); + return %_CallFunction(this.script.source, + this.from_position, + this.to_position, + StringSubstring); }; // Returns the offset of the given position within the containing // line. function GetPositionInLine(message) { - var location = message.script.locationFromPosition(message.startPos, false); + var script = %MessageGetScript(message); + var start_position = %MessageGetStartPosition(message); + var location = script.locationFromPosition(start_position, false); if (location == null) return -1; location.restrict(); - return message.startPos - location.start; -} - - -function ErrorMessage(type, args, startPos, endPos, script, stackTrace, - stackFrames) { - this.startPos = startPos; - this.endPos = endPos; - this.type = type; - this.args = args; - this.script = script; - this.stackTrace = stackTrace; - this.stackFrames = stackFrames; -} - - -function MakeMessage(type, args, startPos, endPos, script, stackTrace, - stackFrames) { - return new ErrorMessage(type, args, startPos, endPos, script, stackTrace, - stackFrames); + return start_position - location.start; } @@ -666,10 +679,10 @@ CallSite.prototype.getThis = function () { CallSite.prototype.getTypeName = function () { var constructor = this.receiver.constructor; if (!constructor) - return $Object.prototype.toString.call(this.receiver); + return %_CallFunction(this.receiver, ObjectToString); var constructorName = constructor.name; if (!constructorName) - return $Object.prototype.toString.call(this.receiver); + return %_CallFunction(this.receiver, ObjectToString); return constructorName; }; @@ -718,8 +731,8 @@ CallSite.prototype.getMethodName = function () { // this function. var ownName = this.fun.name; if (ownName && this.receiver && - (ObjectLookupGetter.call(this.receiver, ownName) === this.fun || - ObjectLookupSetter.call(this.receiver, ownName) === this.fun || + (%_CallFunction(this.receiver, ownName, ObjectLookupGetter) === this.fun || + %_CallFunction(this.receiver, ownName, ObjectLookupSetter) === this.fun || this.receiver[ownName] === this.fun)) { // To handle DontEnum properties we guess that the method has // the same name as the function. @@ -967,7 +980,7 @@ function DefineError(f) { // DefineOneShotAccessor always inserts a message property and // ignores setters. DefineOneShotAccessor(this, 'message', function (obj) { - return FormatMessage({type: obj.type, args: obj.arguments}); + return FormatMessage(%NewMessageObject(obj.type, obj.arguments)); }); } else if (!IS_UNDEFINED(m)) { %IgnoreAttributesAndSetProperty(this, 'message', ToString(m)); @@ -981,11 +994,12 @@ function DefineError(f) { function captureStackTrace(obj, cons_opt) { var stackTraceLimit = $Error.stackTraceLimit; - if (!stackTraceLimit) return; + if (!stackTraceLimit || !IS_NUMBER(stackTraceLimit)) return; if (stackTraceLimit < 0 || stackTraceLimit > 10000) stackTraceLimit = 10000; - var raw_stack = %CollectStackTrace(cons_opt ? cons_opt : captureStackTrace, - stackTraceLimit); + var raw_stack = %CollectStackTrace(cons_opt + ? cons_opt + : captureStackTrace, stackTraceLimit); DefineOneShotAccessor(obj, 'stack', function (obj) { return FormatRawStackTrace(obj, raw_stack); }); @@ -1006,19 +1020,46 @@ $Error.captureStackTrace = captureStackTrace; // Setup extra properties of the Error.prototype object. $Error.prototype.message = ''; +// Global list of error objects visited during errorToString. This is +// used to detect cycles in error toString formatting. +var visited_errors = new $Array(); +var cyclic_error_marker = new $Object(); + +function errorToStringDetectCycle() { + if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker; + try { + var type = this.type; + if (type && !%_CallFunction(this, "message", ObjectHasOwnProperty)) { + var formatted = FormatMessage(%NewMessageObject(type, this.arguments)); + return this.name + ": " + formatted; + } + var message = %_CallFunction(this, "message", ObjectHasOwnProperty) + ? (": " + this.message) + : ""; + return this.name + message; + } finally { + visited_errors.length = visited_errors.length - 1; + } +} + function errorToString() { - var type = this.type; - if (type && !this.hasOwnProperty("message")) { - return this.name + ": " + FormatMessage({ type: type, args: this.arguments }); + // This helper function is needed because access to properties on + // the builtins object do not work inside of a catch clause. + function isCyclicErrorMarker(o) { return o === cyclic_error_marker; } + + try { + return %_CallFunction(this, errorToStringDetectCycle); + } catch(e) { + // If this error message was encountered already return the empty + // string for it instead of recursively formatting it. + if (isCyclicErrorMarker(e)) return ''; + else throw e; } - var message = this.hasOwnProperty("message") ? (": " + this.message) : ""; - return this.name + message; } %FunctionSetName(errorToString, 'toString'); %SetProperty($Error.prototype, 'toString', errorToString, DONT_ENUM); - // Boilerplate for exceptions for stack overflows. Used from // Top::StackOverflow(). const kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []); |