blob: 95a24f0ef2ef79ce3af505f3444d920267874fa0 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000046#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000047#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000048#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000049#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000050#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000055#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000057#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000058#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000059#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
kasperl@chromium.org71affb52009-05-26 05:44:31 +000061namespace v8 {
62namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64
ager@chromium.org3e875802009-06-29 08:26:34 +000065#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067
68// Cast the given object to a value of the specified type and store
69// it in a variable with the given name. If the object is not of the
70// expected type call IllegalOperation and return.
71#define CONVERT_CHECKED(Type, name, obj) \
72 RUNTIME_ASSERT(obj->Is##Type()); \
73 Type* name = Type::cast(obj);
74
75#define CONVERT_ARG_CHECKED(Type, name, index) \
76 RUNTIME_ASSERT(args[index]->Is##Type()); \
77 Handle<Type> name = args.at<Type>(index);
78
kasper.lundbd3ec4e2008-07-09 11:06:54 +000079// Cast the given object to a boolean and store it in a variable with
80// the given name. If the object is not a boolean call IllegalOperation
81// and return.
82#define CONVERT_BOOLEAN_CHECKED(name, obj) \
83 RUNTIME_ASSERT(obj->IsBoolean()); \
84 bool name = (obj)->IsTrue();
85
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000086// Cast the given argument to a Smi and store its value in an int variable
87// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000088// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000089#define CONVERT_SMI_ARG_CHECKED(name, index) \
90 RUNTIME_ASSERT(args[index]->IsSmi()); \
91 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000093// Cast the given argument to a double and store it in a variable with
94// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000096#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
97 RUNTIME_ASSERT(args[index]->IsNumber()); \
98 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099
100// Call the specified converter on the object *comand store the result in
101// a variable of the specified type with the given name. If the
102// object is not a Number call IllegalOperation and return.
103#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
104 RUNTIME_ASSERT(obj->IsNumber()); \
105 type name = NumberTo##Type(obj);
106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
109 JSObject* boilerplate) {
110 StackLimitCheck check(isolate);
111 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000116 if (!maybe_result->ToObject(&result)) return maybe_result;
117 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 JSObject* copy = JSObject::cast(result);
119
120 // Deep copy local properties.
121 if (copy->HasFastProperties()) {
122 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 for (int i = 0; i < properties->length(); i++) {
124 Object* value = properties->get(i);
125 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000128 if (!maybe_result->ToObject(&result)) return maybe_result;
129 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000130 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 }
132 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000133 int nof = copy->map()->inobject_properties();
134 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000135 Object* value = copy->InObjectPropertyAt(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
144 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 FixedArray* names = FixedArray::cast(result);
150 copy->GetLocalPropertyNames(names, 0);
151 for (int i = 0; i < names->length(); i++) {
152 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000155 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000156 // Only deep copy fields from the object literal expression.
157 // In particular, don't try to copy the length attribute of
158 // an array.
159 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160 Object* value =
161 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000164 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000165 if (!maybe_result->ToObject(&result)) return maybe_result;
166 }
167 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000168 // Creating object copy for literals. No strict mode needed.
169 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 }
175
176 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000178 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000179 switch (copy->GetElementsKind()) {
180 case JSObject::FAST_ELEMENTS: {
181 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 if (elements->map() == heap->fixed_cow_array_map()) {
183 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000184#ifdef DEBUG
185 for (int i = 0; i < elements->length(); i++) {
186 ASSERT(!elements->get(i)->IsJSObject());
187 }
188#endif
189 } else {
190 for (int i = 0; i < elements->length(); i++) {
191 Object* value = elements->get(i);
192 if (value->IsJSObject()) {
193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
195 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000198 elements->set(i, result);
199 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 case JSObject::DICTIONARY_ELEMENTS: {
205 NumberDictionary* element_dictionary = copy->element_dictionary();
206 int capacity = element_dictionary->Capacity();
207 for (int i = 0; i < capacity; i++) {
208 Object* k = element_dictionary->KeyAt(i);
209 if (element_dictionary->IsKey(k)) {
210 Object* value = element_dictionary->ValueAt(i);
211 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000212 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
214 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000215 if (!maybe_result->ToObject(&result)) return maybe_result;
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 element_dictionary->ValueAtPut(i, result);
218 }
219 }
220 }
221 break;
222 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000223 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
224 UNIMPLEMENTED();
225 break;
226 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
227 case JSObject::EXTERNAL_BYTE_ELEMENTS:
228 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
229 case JSObject::EXTERNAL_SHORT_ELEMENTS:
230 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
231 case JSObject::EXTERNAL_INT_ELEMENTS:
232 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
233 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
234 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
235 case JSObject::FAST_DOUBLE_ELEMENTS:
236 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
239 return copy;
240}
241
242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000243RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000244 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000246}
247
248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000249RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000251 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252}
253
254
ager@chromium.org236ad962008-09-25 09:45:57 +0000255static Handle<Map> ComputeObjectLiteralMap(
256 Handle<Context> context,
257 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000258 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000260 int properties_length = constant_properties->length();
261 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000262 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000263 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 for (int p = 0; p != properties_length; p += 2) {
266 Object* key = constant_properties->get(p);
267 uint32_t element_index = 0;
268 if (key->IsSymbol()) {
269 number_of_symbol_keys++;
270 } else if (key->ToArrayIndex(&element_index)) {
271 // An index key does not require space in the property backing store.
272 number_of_properties--;
273 } else {
274 // Bail out as a non-symbol non-index key makes caching impossible.
275 // ASSERT to make sure that the if condition after the loop is false.
276 ASSERT(number_of_symbol_keys != number_of_properties);
277 break;
278 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 // If we only have symbols and array indices among keys then we can
281 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 if ((number_of_symbol_keys == number_of_properties) &&
284 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 Handle<FixedArray> keys =
287 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000288 if (number_of_symbol_keys > 0) {
289 int index = 0;
290 for (int p = 0; p < properties_length; p += 2) {
291 Object* key = constant_properties->get(p);
292 if (key->IsSymbol()) {
293 keys->set(index++, key);
294 }
295 }
296 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
301 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000302 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000304 Handle<Map>(context->object_function()->initial_map()),
305 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000306}
307
308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000309static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000311 Handle<FixedArray> literals,
312 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314
315static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000317 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000318 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 bool should_have_fast_elements,
320 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321 // Get the global context from the literals array. This is the
322 // context in which the function was created and we use the object
323 // function from this context to create the object literal. We do
324 // not use the object function from the current global context
325 // because this might be the object function from another context
326 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000327 Handle<Context> context =
328 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // In case we have function literals, we want the object to be in
331 // slow properties mode for now. We don't go in the map cache because
332 // maps with constant functions can't be shared if the functions are
333 // not the same (which is the common case).
334 bool is_result_from_cache = false;
335 Handle<Map> map = has_function_literal
336 ? Handle<Map>(context->object_function()->initial_map())
337 : ComputeObjectLiteralMap(context,
338 constant_properties,
339 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000342
343 // Normalize the elements of the boilerplate to save space if needed.
344 if (!should_have_fast_elements) NormalizeElements(boilerplate);
345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 // Add the constant properties to the boilerplate.
347 int length = constant_properties->length();
348 bool should_transform =
349 !is_result_from_cache && boilerplate->HasFastProperties();
350 if (should_transform || has_function_literal) {
351 // Normalize the properties of object to avoid n^2 behavior
352 // when extending the object multiple properties. Indicate the number of
353 // properties to be added.
354 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
355 }
356
357 for (int index = 0; index < length; index +=2) {
358 Handle<Object> key(constant_properties->get(index+0), isolate);
359 Handle<Object> value(constant_properties->get(index+1), isolate);
360 if (value->IsFixedArray()) {
361 // The value contains the constant_properties of a
362 // simple object or array literal.
363 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
364 value = CreateLiteralBoilerplate(isolate, literals, array);
365 if (value.is_null()) return value;
366 }
367 Handle<Object> result;
368 uint32_t element_index = 0;
369 if (key->IsSymbol()) {
370 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
371 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000372 result = SetOwnElement(boilerplate,
373 element_index,
374 value,
375 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000376 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 Handle<String> name(String::cast(*key));
378 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000379 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
380 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 } else if (key->ToArrayIndex(&element_index)) {
383 // Array index (uint32).
384 result = SetOwnElement(boilerplate,
385 element_index,
386 value,
387 kNonStrictMode);
388 } else {
389 // Non-uint32 number.
390 ASSERT(key->IsNumber());
391 double num = key->Number();
392 char arr[100];
393 Vector<char> buffer(arr, ARRAY_SIZE(arr));
394 const char* str = DoubleToCString(num, buffer);
395 Handle<String> name =
396 isolate->factory()->NewStringFromAscii(CStrVector(str));
397 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
398 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 // If setting the property on the boilerplate throws an
401 // exception, the exception is converted to an empty handle in
402 // the handle based operations. In that case, we need to
403 // convert back to an exception.
404 if (result.is_null()) return result;
405 }
406
407 // Transform to fast properties if necessary. For object literals with
408 // containing function literals we defer this operation until after all
409 // computed properties have been assigned so that we can generate
410 // constant function properties.
411 if (should_transform && !has_function_literal) {
412 TransformToFastProperties(boilerplate,
413 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
415
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000416 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000417}
418
419
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000421 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000422 Handle<FixedArray> literals,
423 Handle<FixedArray> elements) {
424 // Create the JSArray.
425 Handle<JSFunction> constructor(
426 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 const bool is_cow =
430 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433
434 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (is_cow) {
436#ifdef DEBUG
437 // Copy-on-write arrays must be shallow (and simple).
438 for (int i = 0; i < content->length(); i++) {
439 ASSERT(!content->get(i)->IsFixedArray());
440 }
441#endif
442 } else {
443 for (int i = 0; i < content->length(); i++) {
444 if (content->get(i)->IsFixedArray()) {
445 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000447 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
448 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000450 if (result.is_null()) return result;
451 content->set(i, *result);
452 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 }
454 }
455
456 // Set the elements.
457 Handle<JSArray>::cast(object)->SetContent(*content);
458 return object;
459}
460
461
462static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000464 Handle<FixedArray> literals,
465 Handle<FixedArray> array) {
466 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000469 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 return CreateObjectLiteralBoilerplate(isolate,
471 literals,
472 elements,
473 true,
474 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000475 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000476 return CreateObjectLiteralBoilerplate(isolate,
477 literals,
478 elements,
479 false,
480 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 default:
484 UNREACHABLE();
485 return Handle<Object>::null();
486 }
487}
488
489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000490RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000491 // Takes a FixedArray of elements containing the literal elements of
492 // the array literal and produces JSArray with those elements.
493 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000494 // which contains the context from which to get the Array function
495 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000496 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000497 ASSERT(args.length() == 3);
498 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000499 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000500 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 Handle<Object> object =
503 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000504 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000506 // Update the functions literal and return the boilerplate.
507 literals->set(literals_index, *object);
508 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509}
510
511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000512RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000516 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000518 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
520 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521
522 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 Handle<Object> boilerplate(literals->get(literals_index), isolate);
524 if (*boilerplate == isolate->heap()->undefined_value()) {
525 boilerplate = CreateObjectLiteralBoilerplate(isolate,
526 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 should_have_fast_elements,
529 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 if (boilerplate.is_null()) return Failure::Exception();
531 // Update the functions literal and return the boilerplate.
532 literals->set(literals_index, *boilerplate);
533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000535}
536
537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000538RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000542 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000544 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
546 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547
548 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 Handle<Object> boilerplate(literals->get(literals_index), isolate);
550 if (*boilerplate == isolate->heap()->undefined_value()) {
551 boilerplate = CreateObjectLiteralBoilerplate(isolate,
552 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000553 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 should_have_fast_elements,
555 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556 if (boilerplate.is_null()) return Failure::Exception();
557 // Update the functions literal and return the boilerplate.
558 literals->set(literals_index, *boilerplate);
559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561}
562
563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000564RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566 ASSERT(args.length() == 3);
567 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000568 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
570
571 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 Handle<Object> boilerplate(literals->get(literals_index), isolate);
573 if (*boilerplate == isolate->heap()->undefined_value()) {
574 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 if (boilerplate.is_null()) return Failure::Exception();
576 // Update the functions literal and return the boilerplate.
577 literals->set(literals_index, *boilerplate);
578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580}
581
582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000583RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 ASSERT(args.length() == 3);
586 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000587 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
589
590 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 Handle<Object> boilerplate(literals->get(literals_index), isolate);
592 if (*boilerplate == isolate->heap()->undefined_value()) {
593 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594 if (boilerplate.is_null()) return Failure::Exception();
595 // Update the functions literal and return the boilerplate.
596 literals->set(literals_index, *boilerplate);
597 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000598 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000600 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603}
604
605
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000606RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
607 ASSERT(args.length() == 2);
608 Object* handler = args[0];
609 Object* prototype = args[1];
610 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000611 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000612 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
613}
614
615
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000616RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
617 ASSERT(args.length() == 1);
618 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000619 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000620}
621
622
623RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
624 ASSERT(args.length() == 1);
625 CONVERT_CHECKED(JSProxy, proxy, args[0]);
626 return proxy->handler();
627}
628
629
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000630RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
631 ASSERT(args.length() == 1);
632 CONVERT_CHECKED(JSProxy, proxy, args[0]);
633 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000634 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000635}
636
637
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
639 HandleScope scope(isolate);
640 ASSERT(args.length() == 1);
641 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
642 ASSERT(weakmap->map()->inobject_properties() == 0);
643 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
644 weakmap->set_table(*table);
645 weakmap->set_next(Smi::FromInt(0));
646 return *weakmap;
647}
648
649
650RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
651 NoHandleAllocation ha;
652 ASSERT(args.length() == 2);
653 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
654 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
655 // because they cannot be cast to JSObject to get an identity hash code.
656 CONVERT_ARG_CHECKED(JSObject, key, 1);
657 return weakmap->table()->Lookup(*key);
658}
659
660
661RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
662 HandleScope scope(isolate);
663 ASSERT(args.length() == 3);
664 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
665 // TODO(mstarzinger): See Runtime_WeakMapGet above.
666 CONVERT_ARG_CHECKED(JSObject, key, 1);
667 Handle<Object> value(args[2]);
668 Handle<ObjectHashTable> table(weakmap->table());
669 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
670 weakmap->set_table(*new_table);
671 return *value;
672}
673
674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000675RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676 NoHandleAllocation ha;
677 ASSERT(args.length() == 1);
678 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000679 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 return JSObject::cast(obj)->class_name();
681}
682
ager@chromium.org7c537e22008-10-16 08:43:32 +0000683
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000684RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
685 NoHandleAllocation ha;
686 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000687 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
688 Object* obj = input_obj;
689 // We don't expect access checks to be needed on JSProxy objects.
690 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000691 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000692 if (obj->IsAccessCheckNeeded() &&
693 !isolate->MayNamedAccess(JSObject::cast(obj),
694 isolate->heap()->Proto_symbol(),
695 v8::ACCESS_GET)) {
696 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
697 return isolate->heap()->undefined_value();
698 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000699 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000700 } while (obj->IsJSObject() &&
701 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000702 return obj;
703}
704
705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000706RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707 NoHandleAllocation ha;
708 ASSERT(args.length() == 2);
709 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
710 Object* O = args[0];
711 Object* V = args[1];
712 while (true) {
713 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000714 if (prototype->IsNull()) return isolate->heap()->false_value();
715 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000716 V = prototype;
717 }
718}
719
720
ager@chromium.org9085a012009-05-11 19:22:57 +0000721// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000723 NoHandleAllocation ha;
724 ASSERT(args.length() == 2);
725 CONVERT_CHECKED(JSObject, jsobject, args[0]);
726 CONVERT_CHECKED(JSObject, proto, args[1]);
727
728 // Sanity checks. The old prototype (that we are replacing) could
729 // theoretically be null, but if it is not null then check that we
730 // didn't already install a hidden prototype here.
731 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
732 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
733 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
734
735 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000736 Object* map_or_failure;
737 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
738 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
739 return maybe_map_or_failure;
740 }
741 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000742 Map* new_proto_map = Map::cast(map_or_failure);
743
lrn@chromium.org303ada72010-10-27 09:33:13 +0000744 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
745 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
746 return maybe_map_or_failure;
747 }
748 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000749 Map* new_map = Map::cast(map_or_failure);
750
751 // Set proto's prototype to be the old prototype of the object.
752 new_proto_map->set_prototype(jsobject->GetPrototype());
753 proto->set_map(new_proto_map);
754 new_proto_map->set_is_hidden_prototype();
755
756 // Set the object's prototype to proto.
757 new_map->set_prototype(proto);
758 jsobject->set_map(new_map);
759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000760 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000761}
762
763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000764RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000766 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000767 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000768 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769}
770
771
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000772// Recursively traverses hidden prototypes if property is not found
773static void GetOwnPropertyImplementation(JSObject* obj,
774 String* name,
775 LookupResult* result) {
776 obj->LocalLookupRealNamedProperty(name, result);
777
778 if (!result->IsProperty()) {
779 Object* proto = obj->GetPrototype();
780 if (proto->IsJSObject() &&
781 JSObject::cast(proto)->map()->is_hidden_prototype())
782 GetOwnPropertyImplementation(JSObject::cast(proto),
783 name, result);
784 }
785}
786
787
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000788static bool CheckAccessException(LookupResult* result,
789 v8::AccessType access_type) {
790 if (result->type() == CALLBACKS) {
791 Object* callback = result->GetCallbackObject();
792 if (callback->IsAccessorInfo()) {
793 AccessorInfo* info = AccessorInfo::cast(callback);
794 bool can_access =
795 (access_type == v8::ACCESS_HAS &&
796 (info->all_can_read() || info->all_can_write())) ||
797 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
798 (access_type == v8::ACCESS_SET && info->all_can_write());
799 return can_access;
800 }
801 }
802
803 return false;
804}
805
806
807static bool CheckAccess(JSObject* obj,
808 String* name,
809 LookupResult* result,
810 v8::AccessType access_type) {
811 ASSERT(result->IsProperty());
812
813 JSObject* holder = result->holder();
814 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000815 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000816 while (true) {
817 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000819 // Access check callback denied the access, but some properties
820 // can have a special permissions which override callbacks descision
821 // (currently see v8::AccessControl).
822 break;
823 }
824
825 if (current == holder) {
826 return true;
827 }
828
829 current = JSObject::cast(current->GetPrototype());
830 }
831
832 // API callbacks can have per callback access exceptions.
833 switch (result->type()) {
834 case CALLBACKS: {
835 if (CheckAccessException(result, access_type)) {
836 return true;
837 }
838 break;
839 }
840 case INTERCEPTOR: {
841 // If the object has an interceptor, try real named properties.
842 // Overwrite the result to fetch the correct property later.
843 holder->LookupRealNamedProperty(name, result);
844 if (result->IsProperty()) {
845 if (CheckAccessException(result, access_type)) {
846 return true;
847 }
848 }
849 break;
850 }
851 default:
852 break;
853 }
854
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000855 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 return false;
857}
858
859
860// TODO(1095): we should traverse hidden prototype hierachy as well.
861static bool CheckElementAccess(JSObject* obj,
862 uint32_t index,
863 v8::AccessType access_type) {
864 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000866 return false;
867 }
868
869 return true;
870}
871
872
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000873// Enumerator used as indices into the array returned from GetOwnProperty
874enum PropertyDescriptorIndices {
875 IS_ACCESSOR_INDEX,
876 VALUE_INDEX,
877 GETTER_INDEX,
878 SETTER_INDEX,
879 WRITABLE_INDEX,
880 ENUMERABLE_INDEX,
881 CONFIGURABLE_INDEX,
882 DESCRIPTOR_SIZE
883};
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885// Returns an array with the property description:
886// if args[1] is not a property on args[0]
887// returns undefined
888// if args[1] is a data property on args[0]
889// [false, value, Writeable, Enumerable, Configurable]
890// if args[1] is an accessor on args[0]
891// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000892RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000893 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 Heap* heap = isolate->heap();
895 HandleScope scope(isolate);
896 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
897 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000898 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000899 CONVERT_ARG_CHECKED(JSObject, obj, 0);
900 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000902 // This could be an element.
903 uint32_t index;
904 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000905 switch (obj->HasLocalElement(index)) {
906 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000908
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000909 case JSObject::STRING_CHARACTER_ELEMENT: {
910 // Special handling of string objects according to ECMAScript 5
911 // 15.5.5.2. Note that this might be a string object with elements
912 // other than the actual string value. This is covered by the
913 // subsequent cases.
914 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
915 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000916 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000919 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(WRITABLE_INDEX, heap->false_value());
921 elms->set(ENUMERABLE_INDEX, heap->false_value());
922 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000923 return *desc;
924 }
925
926 case JSObject::INTERCEPTED_ELEMENT:
927 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000929 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000931 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 elms->set(WRITABLE_INDEX, heap->true_value());
933 elms->set(ENUMERABLE_INDEX, heap->true_value());
934 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000935 return *desc;
936 }
937
938 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000939 Handle<JSObject> holder = obj;
940 if (obj->IsJSGlobalProxy()) {
941 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943 ASSERT(proto->IsJSGlobalObject());
944 holder = Handle<JSObject>(JSObject::cast(proto));
945 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000946 FixedArray* elements = FixedArray::cast(holder->elements());
947 NumberDictionary* dictionary = NULL;
948 if (elements->map() == heap->non_strict_arguments_elements_map()) {
949 dictionary = NumberDictionary::cast(elements->get(1));
950 } else {
951 dictionary = NumberDictionary::cast(elements);
952 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000953 int entry = dictionary->FindEntry(index);
954 ASSERT(entry != NumberDictionary::kNotFound);
955 PropertyDetails details = dictionary->DetailsAt(entry);
956 switch (details.type()) {
957 case CALLBACKS: {
958 // This is an accessor property with getter and/or setter.
959 FixedArray* callbacks =
960 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000962 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
963 elms->set(GETTER_INDEX, callbacks->get(0));
964 }
965 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
966 elms->set(SETTER_INDEX, callbacks->get(1));
967 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000968 break;
969 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000970 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000971 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000973 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000974 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000975 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000977 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000978 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000979 default:
980 UNREACHABLE();
981 break;
982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
984 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000985 return *desc;
986 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987 }
988 }
989
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000990 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000991 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000992
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000993 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000995 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000996
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000997 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000999 }
1000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1002 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001003
1004 bool is_js_accessor = (result.type() == CALLBACKS) &&
1005 (result.GetCallbackObject()->IsFixedArray());
1006
1007 if (is_js_accessor) {
1008 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001010
1011 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1012 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1013 elms->set(GETTER_INDEX, structure->get(0));
1014 }
1015 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1016 elms->set(SETTER_INDEX, structure->get(1));
1017 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001018 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001019 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1020 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001021
1022 PropertyAttributes attrs;
1023 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001024 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001025 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1026 if (!maybe_value->ToObject(&value)) return maybe_value;
1027 }
1028 elms->set(VALUE_INDEX, value);
1029 }
1030
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001031 return *desc;
1032}
1033
1034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001035RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001036 ASSERT(args.length() == 1);
1037 CONVERT_CHECKED(JSObject, obj, args[0]);
1038 return obj->PreventExtensions();
1039}
1040
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001042RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001043 ASSERT(args.length() == 1);
1044 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 obj = JSObject::cast(proto);
1050 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001051 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001052}
1053
1054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001055RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001058 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1059 CONVERT_ARG_CHECKED(String, pattern, 1);
1060 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001061 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1062 if (result.is_null()) return Failure::Exception();
1063 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064}
1065
1066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001067RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001070 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072}
1073
1074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001075RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 ASSERT(args.length() == 1);
1077 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001078 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080}
1081
1082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001083RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 ASSERT(args.length() == 2);
1085 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001087 int index = field->value();
1088 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1089 InstanceType type = templ->map()->instance_type();
1090 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1091 type == OBJECT_TEMPLATE_INFO_TYPE);
1092 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001093 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001094 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1095 } else {
1096 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1097 }
1098 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099}
1100
1101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001102RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001103 ASSERT(args.length() == 1);
1104 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001105 Map* old_map = object->map();
1106 bool needs_access_checks = old_map->is_access_check_needed();
1107 if (needs_access_checks) {
1108 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001109 Object* new_map;
1110 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1111 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1112 }
ager@chromium.org32912102009-01-16 10:38:43 +00001113
1114 Map::cast(new_map)->set_is_access_check_needed(false);
1115 object->set_map(Map::cast(new_map));
1116 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001117 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001118}
1119
1120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001121RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001122 ASSERT(args.length() == 1);
1123 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001124 Map* old_map = object->map();
1125 if (!old_map->is_access_check_needed()) {
1126 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001127 Object* new_map;
1128 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1129 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1130 }
ager@chromium.org32912102009-01-16 10:38:43 +00001131
1132 Map::cast(new_map)->set_is_access_check_needed(true);
1133 object->set_map(Map::cast(new_map));
1134 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001135 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001136}
1137
1138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001139static Failure* ThrowRedeclarationError(Isolate* isolate,
1140 const char* type,
1141 Handle<String> name) {
1142 HandleScope scope(isolate);
1143 Handle<Object> type_handle =
1144 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 Handle<Object> args[2] = { type_handle, name };
1146 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1148 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149}
1150
1151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001152RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001153 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001154 HandleScope scope(isolate);
1155 Handle<GlobalObject> global = Handle<GlobalObject>(
1156 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157
ager@chromium.org3811b432009-10-28 14:53:37 +00001158 Handle<Context> context = args.at<Context>(0);
1159 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001160 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162 // Traverse the name/value pairs and set the properties.
1163 int length = pairs->length();
1164 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168
1169 // We have to declare a global const property. To capture we only
1170 // assign to it when evaluating the assignment for "const x =
1171 // <expr>" the initial value is the hole.
1172 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001173 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 if (value->IsUndefined() || is_const_property) {
1175 // Lookup the property in the global object, and don't set the
1176 // value of the variable if the property is already there.
1177 LookupResult lookup;
1178 global->Lookup(*name, &lookup);
1179 if (lookup.IsProperty()) {
1180 // Determine if the property is local by comparing the holder
1181 // against the global object. The information will be used to
1182 // avoid throwing re-declaration errors when declaring
1183 // variables or constants that exist in the prototype chain.
1184 bool is_local = (*global == lookup.holder());
1185 // Get the property attributes and determine if the property is
1186 // read-only.
1187 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1188 bool is_read_only = (attributes & READ_ONLY) != 0;
1189 if (lookup.type() == INTERCEPTOR) {
1190 // If the interceptor says the property is there, we
1191 // just return undefined without overwriting the property.
1192 // Otherwise, we continue to setting the property.
1193 if (attributes != ABSENT) {
1194 // Check if the existing property conflicts with regards to const.
1195 if (is_local && (is_read_only || is_const_property)) {
1196 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001197 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 };
1199 // The property already exists without conflicting: Go to
1200 // the next declaration.
1201 continue;
1202 }
1203 // Fall-through and introduce the absent property by using
1204 // SetProperty.
1205 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001206 // For const properties, we treat a callback with this name
1207 // even in the prototype as a conflicting declaration.
1208 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001210 }
1211 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 if (is_local && (is_read_only || is_const_property)) {
1213 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001214 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 }
1216 // The property already exists without conflicting: Go to
1217 // the next declaration.
1218 continue;
1219 }
1220 }
1221 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001222 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001224 Handle<SharedFunctionInfo> shared =
1225 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001227 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1228 context,
1229 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 value = function;
1231 }
1232
1233 LookupResult lookup;
1234 global->LocalLookup(*name, &lookup);
1235
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001236 // There's a local property that we need to overwrite because
1237 // we're either declaring a function or there's an interceptor
1238 // that claims the property is absent.
1239 //
1240 // Check for conflicting re-declarations. We cannot have
1241 // conflicting types in case of intercepted properties because
1242 // they are absent.
1243 if (lookup.IsProperty() &&
1244 (lookup.type() != INTERCEPTOR) &&
1245 (lookup.IsReadOnly() || is_const_property)) {
1246 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001250 // Compute the property attributes. According to ECMA-262, section
1251 // 13, page 71, the property must be read-only and
1252 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1253 // property as read-only, so we don't either.
1254 int attr = NONE;
1255 if ((flags & kDeclareGlobalsEvalFlag) == 0) {
1256 attr |= DONT_DELETE;
1257 }
1258 bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
1259 if (is_const_property || (is_native && is_function_declaration)) {
1260 attr |= READ_ONLY;
1261 }
1262
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001263 // Safari does not allow the invocation of callback setters for
1264 // function declarations. To mimic this behavior, we do not allow
1265 // the invocation of setters for function values. This makes a
1266 // difference for global functions with the same names as event
1267 // handlers such as "function onload() {}". Firefox does call the
1268 // onload setter in those case and Safari does not. We follow
1269 // Safari for compatibility.
1270 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001271 // Do not change DONT_DELETE to false from true.
1272 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001274 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001275 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 RETURN_IF_EMPTY_HANDLE(isolate,
1278 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001279 name,
1280 value,
1281 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001283 StrictModeFlag strict_mode =
1284 ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
1285 : kNonStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001286 RETURN_IF_EMPTY_HANDLE(isolate,
1287 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001288 name,
1289 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001290 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001291 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 }
1293 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001295 ASSERT(!isolate->has_pending_exception());
1296 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297}
1298
1299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001300RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001302 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303
ager@chromium.org7c537e22008-10-16 08:43:32 +00001304 CONVERT_ARG_CHECKED(Context, context, 0);
1305 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001306 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001307 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001308 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001310 // Declarations are always done in a function or global context.
1311 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
1313 int index;
1314 PropertyAttributes attributes;
1315 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001316 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001317 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001318 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 if (attributes != ABSENT) {
1321 // The name was declared before; check for conflicting
1322 // re-declarations: This is similar to the code in parser.cc in
1323 // the AstBuildingParser::Declare function.
1324 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1325 // Functions are not read-only.
1326 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1327 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001328 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 }
1330
1331 // Initialize it if necessary.
1332 if (*initial_value != NULL) {
1333 if (index >= 0) {
1334 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001335 // the function context or the arguments object.
1336 if (holder->IsContext()) {
1337 ASSERT(holder.is_identical_to(context));
1338 if (((attributes & READ_ONLY) == 0) ||
1339 context->get(index)->IsTheHole()) {
1340 context->set(index, *initial_value);
1341 }
1342 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001343 // The holder is an arguments object.
1344 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001345 Handle<Object> result = SetElement(arguments, index, initial_value,
1346 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001347 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 }
1349 } else {
1350 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001351 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001352 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001354 SetProperty(context_ext, name, initial_value,
1355 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001360 // The property is not in the function context. It needs to be
1361 // "declared" in the function context's extension context, or in the
1362 // global context.
1363 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001364 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001366 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001367 } else {
1368 // The function context's extension context does not exists - allocate
1369 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 context_ext = isolate->factory()->NewJSObject(
1371 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001372 // And store it in the extension slot.
1373 context->set_extension(*context_ext);
1374 }
1375 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 // Declare the property by setting it to the initial value if provided,
1378 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1379 // constant declarations).
1380 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001382 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001383 // Declaring a const context slot is a conflicting declaration if
1384 // there is a callback with that name in a prototype. It is
1385 // allowed to introduce const variables in
1386 // JSContextExtensionObjects. They are treated specially in
1387 // SetProperty and no setters are invoked for those since they are
1388 // not real JSObjects.
1389 if (initial_value->IsTheHole() &&
1390 !context_ext->IsJSContextExtensionObject()) {
1391 LookupResult lookup;
1392 context_ext->Lookup(*name, &lookup);
1393 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001395 }
1396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 RETURN_IF_EMPTY_HANDLE(isolate,
1398 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001399 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001400 }
1401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403}
1404
1405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001406RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001408 // args[0] == name
1409 // args[1] == strict_mode
1410 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411
1412 // Determine if we need to assign to the variable if it already
1413 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1415 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416
1417 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001419 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001420 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001421 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422
1423 // According to ECMA-262, section 12.2, page 62, the property must
1424 // not be deletable.
1425 PropertyAttributes attributes = DONT_DELETE;
1426
1427 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001428 // there, there is a property with this name in the prototype chain.
1429 // We follow Safari and Firefox behavior and only set the property
1430 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001431 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001432 // Note that objects can have hidden prototypes, so we need to traverse
1433 // the whole chain of hidden prototypes to do a 'local' lookup.
1434 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001436 while (true) {
1437 real_holder->LocalLookup(*name, &lookup);
1438 if (lookup.IsProperty()) {
1439 // Determine if this is a redeclaration of something read-only.
1440 if (lookup.IsReadOnly()) {
1441 // If we found readonly property on one of hidden prototypes,
1442 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 if (real_holder != isolate->context()->global()) break;
1444 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001445 }
1446
1447 // Determine if this is a redeclaration of an intercepted read-only
1448 // property and figure out if the property exists at all.
1449 bool found = true;
1450 PropertyType type = lookup.type();
1451 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001453 Handle<JSObject> holder(real_holder);
1454 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1455 real_holder = *holder;
1456 if (intercepted == ABSENT) {
1457 // The interceptor claims the property isn't there. We need to
1458 // make sure to introduce it.
1459 found = false;
1460 } else if ((intercepted & READ_ONLY) != 0) {
1461 // The property is present, but read-only. Since we're trying to
1462 // overwrite it with a variable declaration we must throw a
1463 // re-declaration error. However if we found readonly property
1464 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 if (real_holder != isolate->context()->global()) break;
1466 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001467 }
1468 }
1469
1470 if (found && !assign) {
1471 // The global property is there and we're not assigning any value
1472 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001473 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001474 }
1475
1476 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 return real_holder->SetProperty(
1479 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001480 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001481
1482 Object* proto = real_holder->GetPrototype();
1483 if (!proto->IsJSObject())
1484 break;
1485
1486 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1487 break;
1488
1489 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 }
1491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001493 if (assign) {
1494 return global->SetProperty(*name, args[2], attributes, strict_mode);
1495 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001496 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497}
1498
1499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001500RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 // All constants are declared with an initial value. The name
1502 // of the constant is the first argument and the initial value
1503 // is the second.
1504 RUNTIME_ASSERT(args.length() == 2);
1505 CONVERT_ARG_CHECKED(String, name, 0);
1506 Handle<Object> value = args.at<Object>(1);
1507
1508 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510
1511 // According to ECMA-262, section 12.2, page 62, the property must
1512 // not be deletable. Since it's a const, it must be READ_ONLY too.
1513 PropertyAttributes attributes =
1514 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1515
1516 // Lookup the property locally in the global object. If it isn't
1517 // there, we add the property and take special precautions to always
1518 // add it as a local property even in case of callbacks in the
1519 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001520 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 LookupResult lookup;
1522 global->LocalLookup(*name, &lookup);
1523 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001524 return global->SetLocalPropertyIgnoreAttributes(*name,
1525 *value,
1526 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 }
1528
1529 // Determine if this is a redeclaration of something not
1530 // read-only. In case the result is hidden behind an interceptor we
1531 // need to ask it for the property attributes.
1532 if (!lookup.IsReadOnly()) {
1533 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 }
1536
1537 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1538
1539 // Throw re-declaration error if the intercepted property is present
1540 // but not read-only.
1541 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 }
1544
1545 // Restore global object from context (in case of GC) and continue
1546 // with setting the value because the property is either absent or
1547 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001548 HandleScope handle_scope(isolate);
1549 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001551 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552 // property through an interceptor and only do it if it's
1553 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001554 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001555 RETURN_IF_EMPTY_HANDLE(isolate,
1556 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001557 name,
1558 value,
1559 attributes,
1560 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 return *value;
1562 }
1563
1564 // Set the value, but only we're assigning the initial value to a
1565 // constant. For now, we determine this by checking if the
1566 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001567 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 PropertyType type = lookup.type();
1569 if (type == FIELD) {
1570 FixedArray* properties = global->properties();
1571 int index = lookup.GetFieldIndex();
1572 if (properties->get(index)->IsTheHole()) {
1573 properties->set(index, *value);
1574 }
1575 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001576 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1577 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 }
1579 } else {
1580 // Ignore re-initialization of constants that have already been
1581 // assigned a function value.
1582 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1583 }
1584
1585 // Use the set value as the result of the operation.
1586 return *value;
1587}
1588
1589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001590RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 ASSERT(args.length() == 3);
1593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 ASSERT(!value->IsTheHole());
1596 CONVERT_ARG_CHECKED(Context, context, 1);
1597 Handle<String> name(String::cast(args[2]));
1598
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001599 // Initializations are always done in a function or global context.
1600 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
1602 int index;
1603 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001604 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001605 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001606 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001607 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 // In most situations, the property introduced by the const
1610 // declaration should be present in the context extension object.
1611 // However, because declaration and initialization are separate, the
1612 // property might have been deleted (if it was introduced by eval)
1613 // before we reach the initialization point.
1614 //
1615 // Example:
1616 //
1617 // function f() { eval("delete x; const x;"); }
1618 //
1619 // In that case, the initialization behaves like a normal assignment
1620 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001622 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001623 // Property was found in a context. Perform the assignment if we
1624 // found some non-constant or an uninitialized constant.
1625 Handle<Context> context = Handle<Context>::cast(holder);
1626 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1627 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001628 }
1629 } else {
1630 // The holder is an arguments object.
1631 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001632 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001633 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001635 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 }
1637 return *value;
1638 }
1639
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 // The property could not be found, we introduce it in the global
1641 // context.
1642 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001643 Handle<JSObject> global = Handle<JSObject>(
1644 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001645 // Strict mode not needed (const disallowed in strict mode).
1646 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001647 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001648 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001649 return *value;
1650 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001652 // The property was present in a context extension object.
1653 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001655 if (*context_ext == context->extension()) {
1656 // This is the property that was introduced by the const
1657 // declaration. Set it if it hasn't been set before. NOTE: We
1658 // cannot use GetProperty() to get the current value as it
1659 // 'unholes' the value.
1660 LookupResult lookup;
1661 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1662 ASSERT(lookup.IsProperty()); // the property was declared
1663 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1664
1665 PropertyType type = lookup.type();
1666 if (type == FIELD) {
1667 FixedArray* properties = context_ext->properties();
1668 int index = lookup.GetFieldIndex();
1669 if (properties->get(index)->IsTheHole()) {
1670 properties->set(index, *value);
1671 }
1672 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001673 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1674 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001675 }
1676 } else {
1677 // We should not reach here. Any real, named property should be
1678 // either a field or a dictionary slot.
1679 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 }
1681 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682 // The property was found in a different context extension object.
1683 // Set it if it is not a read-only property.
1684 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001685 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001686 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001688 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 return *value;
1693}
1694
1695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001696RUNTIME_FUNCTION(MaybeObject*,
1697 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001699 ASSERT(args.length() == 2);
1700 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001701 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001702 if (object->HasFastProperties()) {
1703 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1704 }
1705 return *object;
1706}
1707
1708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001709RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001711 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001712 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1713 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001716 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001717 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001718 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001719 RUNTIME_ASSERT(index >= 0);
1720 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001722 Handle<Object> result = RegExpImpl::Exec(regexp,
1723 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001726 if (result.is_null()) return Failure::Exception();
1727 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728}
1729
1730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001731RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001732 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001733 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001734 if (elements_count < 0 ||
1735 elements_count > FixedArray::kMaxLength ||
1736 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001738 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739 Object* new_object;
1740 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001742 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1743 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1746 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1748 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001749 {
1750 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001752 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001753 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 }
1755 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 array->set_elements(elements);
1758 array->set_length(Smi::FromInt(elements_count));
1759 // Write in-object properties after the length of the array.
1760 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1761 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1762 return array;
1763}
1764
1765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001766RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767 AssertNoAllocation no_alloc;
1768 ASSERT(args.length() == 5);
1769 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1770 CONVERT_CHECKED(String, source, args[1]);
1771
1772 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001774
1775 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001776 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777
1778 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780
1781 Map* map = regexp->map();
1782 Object* constructor = map->constructor();
1783 if (constructor->IsJSFunction() &&
1784 JSFunction::cast(constructor)->initial_map() == map) {
1785 // If we still have the original map, set in-object properties directly.
1786 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1787 // TODO(lrn): Consider skipping write barrier on booleans as well.
1788 // Both true and false should be in oldspace at all times.
1789 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1790 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1791 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1792 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1793 Smi::FromInt(0),
1794 SKIP_WRITE_BARRIER);
1795 return regexp;
1796 }
1797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001799 PropertyAttributes final =
1800 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1801 PropertyAttributes writable =
1802 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001804 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001806 source,
1807 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001808 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001810 global,
1811 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812 ASSERT(!result->IsFailure());
1813 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001815 ignoreCase,
1816 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 multiline,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
1822 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001824 Smi::FromInt(0),
1825 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 ASSERT(!result->IsFailure());
1827 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001828 return regexp;
1829}
1830
1831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001832RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001834 ASSERT(args.length() == 1);
1835 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1836 // This is necessary to enable fast checks for absence of elements
1837 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001839 return Smi::FromInt(0);
1840}
1841
1842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1844 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001845 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001846 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001847 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1848 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1849 Handle<JSFunction> optimized =
1850 isolate->factory()->NewFunction(key,
1851 JS_OBJECT_TYPE,
1852 JSObject::kHeaderSize,
1853 code,
1854 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001855 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001856 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001857 return optimized;
1858}
1859
1860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001861RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001863 ASSERT(args.length() == 1);
1864 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1865
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001866 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1867 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1868 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1869 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1870 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1871 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1872 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001873
1874 return *holder;
1875}
1876
1877
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001878RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1879 NoHandleAllocation handle_free;
1880 ASSERT(args.length() == 1);
1881 CONVERT_CHECKED(JSFunction, function, args[0]);
1882 SharedFunctionInfo* shared = function->shared();
1883 if (shared->native() || shared->strict_mode()) {
1884 return isolate->heap()->undefined_value();
1885 }
1886 // Returns undefined for strict or native functions, or
1887 // the associated global receiver for "normal" functions.
1888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001890 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001891 return global_context->global()->global_receiver();
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001897 ASSERT(args.length() == 4);
1898 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001899 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 Handle<String> pattern = args.at<String>(2);
1901 Handle<String> flags = args.at<String>(3);
1902
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001903 // Get the RegExp function from the context in the literals array.
1904 // This is the RegExp function from the context in which the
1905 // function was created. We do not use the RegExp function from the
1906 // current global context because this might be the RegExp function
1907 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001908 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001909 Handle<JSFunction>(
1910 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 // Compute the regular expression literal.
1912 bool has_pending_exception;
1913 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001914 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1915 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001916 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 return Failure::Exception();
1919 }
1920 literals->set(index, *regexp);
1921 return *regexp;
1922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 1);
1928
1929 CONVERT_CHECKED(JSFunction, f, args[0]);
1930 return f->shared()->name();
1931}
1932
1933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001934RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001935 NoHandleAllocation ha;
1936 ASSERT(args.length() == 2);
1937
1938 CONVERT_CHECKED(JSFunction, f, args[0]);
1939 CONVERT_CHECKED(String, name, args[1]);
1940 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001941 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001942}
1943
1944
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001945RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1946 NoHandleAllocation ha;
1947 ASSERT(args.length() == 1);
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
1949 return isolate->heap()->ToBoolean(
1950 f->shared()->name_should_print_as_anonymous());
1951}
1952
1953
1954RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1955 NoHandleAllocation ha;
1956 ASSERT(args.length() == 1);
1957 CONVERT_CHECKED(JSFunction, f, args[0]);
1958 f->shared()->set_name_should_print_as_anonymous(true);
1959 return isolate->heap()->undefined_value();
1960}
1961
1962
whesse@chromium.org7b260152011-06-20 15:33:18 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1964 HandleScope scope(isolate);
1965 ASSERT(args.length() == 1);
1966
1967 CONVERT_CHECKED(JSFunction, fun, args[0]);
1968 fun->shared()->set_bound(true);
1969 return isolate->heap()->undefined_value();
1970}
1971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001972RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001973 NoHandleAllocation ha;
1974 ASSERT(args.length() == 1);
1975
1976 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001977 Object* obj = f->RemovePrototype();
1978 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001980 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001981}
1982
1983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001984RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 ASSERT(args.length() == 1);
1987
1988 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001989 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1990 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991
1992 return *GetScriptWrapper(Handle<Script>::cast(script));
1993}
1994
1995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001996RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997 NoHandleAllocation ha;
1998 ASSERT(args.length() == 1);
1999
2000 CONVERT_CHECKED(JSFunction, f, args[0]);
2001 return f->shared()->GetSourceCode();
2002}
2003
2004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002005RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006 NoHandleAllocation ha;
2007 ASSERT(args.length() == 1);
2008
2009 CONVERT_CHECKED(JSFunction, fun, args[0]);
2010 int pos = fun->shared()->start_position();
2011 return Smi::FromInt(pos);
2012}
2013
2014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002015RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002016 ASSERT(args.length() == 2);
2017
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002018 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002019 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2020
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002021 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2022
2023 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002024 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002025}
2026
2027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002028RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 NoHandleAllocation ha;
2030 ASSERT(args.length() == 2);
2031
2032 CONVERT_CHECKED(JSFunction, fun, args[0]);
2033 CONVERT_CHECKED(String, name, args[1]);
2034 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 NoHandleAllocation ha;
2041 ASSERT(args.length() == 2);
2042
2043 CONVERT_CHECKED(JSFunction, fun, args[0]);
2044 CONVERT_CHECKED(Smi, length, args[1]);
2045 fun->shared()->set_length(length->value());
2046 return length;
2047}
2048
2049
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002050// Creates a local, readonly, property called length with the correct
2051// length (when read by the user). This effectively overwrites the
2052// interceptor used to normally provide the length.
2053RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2054 NoHandleAllocation ha;
2055 ASSERT(args.length() == 2);
2056 CONVERT_CHECKED(JSFunction, fun, args[0]);
2057 CONVERT_CHECKED(Smi, length, args[1]);
2058 MaybeObject* maybe_name =
2059 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2060 String* name;
2061 if (!maybe_name->To(&name)) return maybe_name;
2062 PropertyAttributes attr =
2063 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2064 return fun->AddProperty(name, length, attr, kNonStrictMode);
2065}
2066
2067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002068RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002069 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070 ASSERT(args.length() == 2);
2071
2072 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002073 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002074 Object* obj;
2075 { MaybeObject* maybe_obj =
2076 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2077 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002079 return args[0]; // return TOS
2080}
2081
2082
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002083RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2084 NoHandleAllocation ha;
2085 RUNTIME_ASSERT(args.length() == 1);
2086 CONVERT_CHECKED(JSFunction, function, args[0]);
2087
2088 MaybeObject* maybe_name =
2089 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2090 String* name;
2091 if (!maybe_name->To(&name)) return maybe_name;
2092
2093 if (function->HasFastProperties()) {
2094 // Construct a new field descriptor with updated attributes.
2095 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2096 int index = instance_desc->Search(name);
2097 ASSERT(index != DescriptorArray::kNotFound);
2098 PropertyDetails details(instance_desc->GetDetails(index));
2099 CallbacksDescriptor new_desc(name,
2100 instance_desc->GetValue(index),
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.index());
2103 // Construct a new field descriptors array containing the new descriptor.
2104 Object* descriptors_unchecked;
2105 { MaybeObject* maybe_descriptors_unchecked =
2106 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2107 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2108 return maybe_descriptors_unchecked;
2109 }
2110 }
2111 DescriptorArray* new_descriptors =
2112 DescriptorArray::cast(descriptors_unchecked);
2113 // Create a new map featuring the new field descriptors array.
2114 Object* map_unchecked;
2115 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2116 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2117 return maybe_map_unchecked;
2118 }
2119 }
2120 Map* new_map = Map::cast(map_unchecked);
2121 new_map->set_instance_descriptors(new_descriptors);
2122 function->set_map(new_map);
2123 } else { // Dictionary properties.
2124 // Directly manipulate the property details.
2125 int entry = function->property_dictionary()->FindEntry(name);
2126 ASSERT(entry != StringDictionary::kNotFound);
2127 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2128 PropertyDetails new_details(
2129 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2130 details.type(),
2131 details.index());
2132 function->property_dictionary()->DetailsAtPut(entry, new_details);
2133 }
2134 return function;
2135}
2136
2137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002138RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002139 NoHandleAllocation ha;
2140 ASSERT(args.length() == 1);
2141
2142 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002143 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002144}
2145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002147RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002148 NoHandleAllocation ha;
2149 ASSERT(args.length() == 1);
2150
2151 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002152 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002153}
2154
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002156RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002157 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002158 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 ASSERT(args.length() == 2);
2160
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002161 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 Handle<Object> code = args.at<Object>(1);
2163
2164 Handle<Context> context(target->context());
2165
2166 if (!code->IsNull()) {
2167 RUNTIME_ASSERT(code->IsJSFunction());
2168 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002169 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170
2171 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 return Failure::Exception();
2173 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002174 // Since we don't store the source for this we should never
2175 // optimize this.
2176 shared->code()->set_optimizable(false);
2177
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002178 // Set the code, scope info, formal parameter count,
2179 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002180 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002181 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002183 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002185 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002186 // Set the source code of the target function to undefined.
2187 // SetCode is only used for built-in constructors like String,
2188 // Array, and Object, and some web code
2189 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002190 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002191 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002192 // Clear the optimization hints related to the compiled code as these are no
2193 // longer valid when the code is overwritten.
2194 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 context = Handle<Context>(fun->context());
2196
2197 // Make sure we get a fresh copy of the literal vector to avoid
2198 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002199 int number_of_literals = fun->NumberOfLiterals();
2200 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 // Insert the object, regexp and array functions in the literals
2204 // array prefix. These are the functions that will be used when
2205 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002206 literals->set(JSFunction::kLiteralGlobalContextIndex,
2207 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002209 // It's okay to skip the write barrier here because the literals
2210 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002211 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002213 }
2214
2215 target->set_context(*context);
2216 return *target;
2217}
2218
2219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002220RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002222 ASSERT(args.length() == 2);
2223 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002224 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002225 RUNTIME_ASSERT(num >= 0);
2226 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002228}
2229
2230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2232 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002234 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002236 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002237 }
2238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240}
2241
2242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002243RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002244 NoHandleAllocation ha;
2245 ASSERT(args.length() == 2);
2246
2247 CONVERT_CHECKED(String, subject, args[0]);
2248 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251 uint32_t i = 0;
2252 if (index->IsSmi()) {
2253 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002255 i = value;
2256 } else {
2257 ASSERT(index->IsHeapNumber());
2258 double value = HeapNumber::cast(index)->value();
2259 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002260 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002261
2262 // Flatten the string. If someone wants to get a char at an index
2263 // in a cons string, it is likely that more indices will be
2264 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002265 Object* flat;
2266 { MaybeObject* maybe_flat = subject->TryFlatten();
2267 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2268 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002269 subject = String::cast(flat);
2270
2271 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002273 }
2274
2275 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002276}
2277
2278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002279RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280 NoHandleAllocation ha;
2281 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002282 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002283}
2284
lrn@chromium.org25156de2010-04-06 13:10:27 +00002285
2286class FixedArrayBuilder {
2287 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2289 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 length_(0) {
2291 // Require a non-zero initial size. Ensures that doubling the size to
2292 // extend the array will work.
2293 ASSERT(initial_capacity > 0);
2294 }
2295
2296 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2297 : array_(backing_store),
2298 length_(0) {
2299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(backing_store->length() > 0);
2302 }
2303
2304 bool HasCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 return (length >= required_length);
2308 }
2309
2310 void EnsureCapacity(int elements) {
2311 int length = array_->length();
2312 int required_length = length_ + elements;
2313 if (length < required_length) {
2314 int new_length = length;
2315 do {
2316 new_length *= 2;
2317 } while (new_length < required_length);
2318 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 array_->CopyTo(0, *extended_array, 0, length_);
2321 array_ = extended_array;
2322 }
2323 }
2324
2325 void Add(Object* value) {
2326 ASSERT(length_ < capacity());
2327 array_->set(length_, value);
2328 length_++;
2329 }
2330
2331 void Add(Smi* value) {
2332 ASSERT(length_ < capacity());
2333 array_->set(length_, value);
2334 length_++;
2335 }
2336
2337 Handle<FixedArray> array() {
2338 return array_;
2339 }
2340
2341 int length() {
2342 return length_;
2343 }
2344
2345 int capacity() {
2346 return array_->length();
2347 }
2348
2349 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002350 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002351 result_array->set_length(Smi::FromInt(length_));
2352 return result_array;
2353 }
2354
2355 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2356 target_array->set_elements(*array_);
2357 target_array->set_length(Smi::FromInt(length_));
2358 return target_array;
2359 }
2360
2361 private:
2362 Handle<FixedArray> array_;
2363 int length_;
2364};
2365
2366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002368const int kStringBuilderConcatHelperLengthBits = 11;
2369const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002370
2371template <typename schar>
2372static inline void StringBuilderConcatHelper(String*,
2373 schar*,
2374 FixedArray*,
2375 int);
2376
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2378 StringBuilderSubstringLength;
2379typedef BitField<int,
2380 kStringBuilderConcatHelperLengthBits,
2381 kStringBuilderConcatHelperPositionBits>
2382 StringBuilderSubstringPosition;
2383
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384
2385class ReplacementStringBuilder {
2386 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002387 ReplacementStringBuilder(Heap* heap,
2388 Handle<String> subject,
2389 int estimated_part_count)
2390 : heap_(heap),
2391 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002394 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002395 // Require a non-zero initial size. Ensures that doubling the size to
2396 // extend the array will work.
2397 ASSERT(estimated_part_count > 0);
2398 }
2399
lrn@chromium.org25156de2010-04-06 13:10:27 +00002400 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2401 int from,
2402 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403 ASSERT(from >= 0);
2404 int length = to - from;
2405 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 if (StringBuilderSubstringLength::is_valid(length) &&
2407 StringBuilderSubstringPosition::is_valid(from)) {
2408 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2409 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002411 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002412 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 builder->Add(Smi::FromInt(-length));
2414 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 }
2417
2418
2419 void EnsureCapacity(int elements) {
2420 array_builder_.EnsureCapacity(elements);
2421 }
2422
2423
2424 void AddSubjectSlice(int from, int to) {
2425 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 }
2428
2429
2430 void AddString(Handle<String> string) {
2431 int length = string->length();
2432 ASSERT(length > 0);
2433 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002434 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 is_ascii_ = false;
2436 }
2437 IncrementCharacterCount(length);
2438 }
2439
2440
2441 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002442 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002443 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 }
2445
2446 Handle<String> joined_string;
2447 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002450 char* char_buffer = seq->GetChars();
2451 StringBuilderConcatHelper(*subject_,
2452 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 *array_builder_.array(),
2454 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002455 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 } else {
2457 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002458 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 uc16* char_buffer = seq->GetChars();
2461 StringBuilderConcatHelper(*subject_,
2462 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002463 *array_builder_.array(),
2464 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002465 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002466 }
2467 return joined_string;
2468 }
2469
2470
2471 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002472 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 V8::FatalProcessOutOfMemory("String.replace result too large.");
2474 }
2475 character_count_ += by;
2476 }
2477
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002479 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002480 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002481
lrn@chromium.org25156de2010-04-06 13:10:27 +00002482 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002483 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2484 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002485 }
2486
2487
ager@chromium.org04921a82011-06-27 13:21:41 +00002488 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2489 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490 }
2491
2492
2493 void AddElement(Object* element) {
2494 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002495 ASSERT(array_builder_.capacity() > array_builder_.length());
2496 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 }
2498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002499 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002500 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002502 int character_count_;
2503 bool is_ascii_;
2504};
2505
2506
2507class CompiledReplacement {
2508 public:
2509 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002510 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002511
2512 void Compile(Handle<String> replacement,
2513 int capture_count,
2514 int subject_length);
2515
2516 void Apply(ReplacementStringBuilder* builder,
2517 int match_from,
2518 int match_to,
2519 Handle<JSArray> last_match_info);
2520
2521 // Number of distinct parts of the replacement pattern.
2522 int parts() {
2523 return parts_.length();
2524 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002525
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002526 bool simple_hint() {
2527 return simple_hint_;
2528 }
2529
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002530 private:
2531 enum PartType {
2532 SUBJECT_PREFIX = 1,
2533 SUBJECT_SUFFIX,
2534 SUBJECT_CAPTURE,
2535 REPLACEMENT_SUBSTRING,
2536 REPLACEMENT_STRING,
2537
2538 NUMBER_OF_PART_TYPES
2539 };
2540
2541 struct ReplacementPart {
2542 static inline ReplacementPart SubjectMatch() {
2543 return ReplacementPart(SUBJECT_CAPTURE, 0);
2544 }
2545 static inline ReplacementPart SubjectCapture(int capture_index) {
2546 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2547 }
2548 static inline ReplacementPart SubjectPrefix() {
2549 return ReplacementPart(SUBJECT_PREFIX, 0);
2550 }
2551 static inline ReplacementPart SubjectSuffix(int subject_length) {
2552 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2553 }
2554 static inline ReplacementPart ReplacementString() {
2555 return ReplacementPart(REPLACEMENT_STRING, 0);
2556 }
2557 static inline ReplacementPart ReplacementSubString(int from, int to) {
2558 ASSERT(from >= 0);
2559 ASSERT(to > from);
2560 return ReplacementPart(-from, to);
2561 }
2562
2563 // If tag <= 0 then it is the negation of a start index of a substring of
2564 // the replacement pattern, otherwise it's a value from PartType.
2565 ReplacementPart(int tag, int data)
2566 : tag(tag), data(data) {
2567 // Must be non-positive or a PartType value.
2568 ASSERT(tag < NUMBER_OF_PART_TYPES);
2569 }
2570 // Either a value of PartType or a non-positive number that is
2571 // the negation of an index into the replacement string.
2572 int tag;
2573 // The data value's interpretation depends on the value of tag:
2574 // tag == SUBJECT_PREFIX ||
2575 // tag == SUBJECT_SUFFIX: data is unused.
2576 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2577 // tag == REPLACEMENT_SUBSTRING ||
2578 // tag == REPLACEMENT_STRING: data is index into array of substrings
2579 // of the replacement string.
2580 // tag <= 0: Temporary representation of the substring of the replacement
2581 // string ranging over -tag .. data.
2582 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2583 // substring objects.
2584 int data;
2585 };
2586
2587 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002588 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002589 Vector<Char> characters,
2590 int capture_count,
2591 int subject_length) {
2592 int length = characters.length();
2593 int last = 0;
2594 for (int i = 0; i < length; i++) {
2595 Char c = characters[i];
2596 if (c == '$') {
2597 int next_index = i + 1;
2598 if (next_index == length) { // No next character!
2599 break;
2600 }
2601 Char c2 = characters[next_index];
2602 switch (c2) {
2603 case '$':
2604 if (i > last) {
2605 // There is a substring before. Include the first "$".
2606 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2607 last = next_index + 1; // Continue after the second "$".
2608 } else {
2609 // Let the next substring start with the second "$".
2610 last = next_index;
2611 }
2612 i = next_index;
2613 break;
2614 case '`':
2615 if (i > last) {
2616 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2617 }
2618 parts->Add(ReplacementPart::SubjectPrefix());
2619 i = next_index;
2620 last = i + 1;
2621 break;
2622 case '\'':
2623 if (i > last) {
2624 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2625 }
2626 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2627 i = next_index;
2628 last = i + 1;
2629 break;
2630 case '&':
2631 if (i > last) {
2632 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2633 }
2634 parts->Add(ReplacementPart::SubjectMatch());
2635 i = next_index;
2636 last = i + 1;
2637 break;
2638 case '0':
2639 case '1':
2640 case '2':
2641 case '3':
2642 case '4':
2643 case '5':
2644 case '6':
2645 case '7':
2646 case '8':
2647 case '9': {
2648 int capture_ref = c2 - '0';
2649 if (capture_ref > capture_count) {
2650 i = next_index;
2651 continue;
2652 }
2653 int second_digit_index = next_index + 1;
2654 if (second_digit_index < length) {
2655 // Peek ahead to see if we have two digits.
2656 Char c3 = characters[second_digit_index];
2657 if ('0' <= c3 && c3 <= '9') { // Double digits.
2658 int double_digit_ref = capture_ref * 10 + c3 - '0';
2659 if (double_digit_ref <= capture_count) {
2660 next_index = second_digit_index;
2661 capture_ref = double_digit_ref;
2662 }
2663 }
2664 }
2665 if (capture_ref > 0) {
2666 if (i > last) {
2667 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2668 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002669 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002670 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2671 last = next_index + 1;
2672 }
2673 i = next_index;
2674 break;
2675 }
2676 default:
2677 i = next_index;
2678 break;
2679 }
2680 }
2681 }
2682 if (length > last) {
2683 if (last == 0) {
2684 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002685 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002686 } else {
2687 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2688 }
2689 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002690 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002691 }
2692
2693 ZoneList<ReplacementPart> parts_;
2694 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002695 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002696};
2697
2698
2699void CompiledReplacement::Compile(Handle<String> replacement,
2700 int capture_count,
2701 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002702 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002703 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002704 String::FlatContent content = replacement->GetFlatContent();
2705 ASSERT(content.IsFlat());
2706 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002707 simple_hint_ = ParseReplacementPattern(&parts_,
2708 content.ToAsciiVector(),
2709 capture_count,
2710 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002711 } else {
2712 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002713 simple_hint_ = ParseReplacementPattern(&parts_,
2714 content.ToUC16Vector(),
2715 capture_count,
2716 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002717 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002718 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002720 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002721 int substring_index = 0;
2722 for (int i = 0, n = parts_.length(); i < n; i++) {
2723 int tag = parts_[i].tag;
2724 if (tag <= 0) { // A replacement string slice.
2725 int from = -tag;
2726 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002727 replacement_substrings_.Add(
2728 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002729 parts_[i].tag = REPLACEMENT_SUBSTRING;
2730 parts_[i].data = substring_index;
2731 substring_index++;
2732 } else if (tag == REPLACEMENT_STRING) {
2733 replacement_substrings_.Add(replacement);
2734 parts_[i].data = substring_index;
2735 substring_index++;
2736 }
2737 }
2738}
2739
2740
2741void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2742 int match_from,
2743 int match_to,
2744 Handle<JSArray> last_match_info) {
2745 for (int i = 0, n = parts_.length(); i < n; i++) {
2746 ReplacementPart part = parts_[i];
2747 switch (part.tag) {
2748 case SUBJECT_PREFIX:
2749 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2750 break;
2751 case SUBJECT_SUFFIX: {
2752 int subject_length = part.data;
2753 if (match_to < subject_length) {
2754 builder->AddSubjectSlice(match_to, subject_length);
2755 }
2756 break;
2757 }
2758 case SUBJECT_CAPTURE: {
2759 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002760 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002761 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2762 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2763 if (from >= 0 && to > from) {
2764 builder->AddSubjectSlice(from, to);
2765 }
2766 break;
2767 }
2768 case REPLACEMENT_SUBSTRING:
2769 case REPLACEMENT_STRING:
2770 builder->AddString(replacement_substrings_[part.data]);
2771 break;
2772 default:
2773 UNREACHABLE();
2774 }
2775 }
2776}
2777
2778
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002779void FindAsciiStringIndices(Vector<const char> subject,
2780 char pattern,
2781 ZoneList<int>* indices,
2782 unsigned int limit) {
2783 ASSERT(limit > 0);
2784 // Collect indices of pattern in subject using memchr.
2785 // Stop after finding at most limit values.
2786 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2787 const char* subject_end = subject_start + subject.length();
2788 const char* pos = subject_start;
2789 while (limit > 0) {
2790 pos = reinterpret_cast<const char*>(
2791 memchr(pos, pattern, subject_end - pos));
2792 if (pos == NULL) return;
2793 indices->Add(static_cast<int>(pos - subject_start));
2794 pos++;
2795 limit--;
2796 }
2797}
2798
2799
2800template <typename SubjectChar, typename PatternChar>
2801void FindStringIndices(Isolate* isolate,
2802 Vector<const SubjectChar> subject,
2803 Vector<const PatternChar> pattern,
2804 ZoneList<int>* indices,
2805 unsigned int limit) {
2806 ASSERT(limit > 0);
2807 // Collect indices of pattern in subject.
2808 // Stop after finding at most limit values.
2809 int pattern_length = pattern.length();
2810 int index = 0;
2811 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2812 while (limit > 0) {
2813 index = search.Search(subject, index);
2814 if (index < 0) return;
2815 indices->Add(index);
2816 index += pattern_length;
2817 limit--;
2818 }
2819}
2820
2821
2822void FindStringIndicesDispatch(Isolate* isolate,
2823 String* subject,
2824 String* pattern,
2825 ZoneList<int>* indices,
2826 unsigned int limit) {
2827 {
2828 AssertNoAllocation no_gc;
2829 String::FlatContent subject_content = subject->GetFlatContent();
2830 String::FlatContent pattern_content = pattern->GetFlatContent();
2831 ASSERT(subject_content.IsFlat());
2832 ASSERT(pattern_content.IsFlat());
2833 if (subject_content.IsAscii()) {
2834 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2835 if (pattern_content.IsAscii()) {
2836 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2837 if (pattern_vector.length() == 1) {
2838 FindAsciiStringIndices(subject_vector,
2839 pattern_vector[0],
2840 indices,
2841 limit);
2842 } else {
2843 FindStringIndices(isolate,
2844 subject_vector,
2845 pattern_vector,
2846 indices,
2847 limit);
2848 }
2849 } else {
2850 FindStringIndices(isolate,
2851 subject_vector,
2852 pattern_content.ToUC16Vector(),
2853 indices,
2854 limit);
2855 }
2856 } else {
2857 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
2858 if (pattern->IsAsciiRepresentation()) {
2859 FindStringIndices(isolate,
2860 subject_vector,
2861 pattern_content.ToAsciiVector(),
2862 indices,
2863 limit);
2864 } else {
2865 FindStringIndices(isolate,
2866 subject_vector,
2867 pattern_content.ToUC16Vector(),
2868 indices,
2869 limit);
2870 }
2871 }
2872 }
2873}
2874
2875
2876template<typename ResultSeqString>
2877MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2878 Isolate* isolate,
2879 Handle<String> subject,
2880 Handle<JSRegExp> pattern_regexp,
2881 Handle<String> replacement) {
2882 ASSERT(subject->IsFlat());
2883 ASSERT(replacement->IsFlat());
2884
2885 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2886 ZoneList<int> indices(8);
2887 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2888 String* pattern =
2889 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2890 int subject_len = subject->length();
2891 int pattern_len = pattern->length();
2892 int replacement_len = replacement->length();
2893
2894 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2895
2896 int matches = indices.length();
2897 if (matches == 0) return *subject;
2898
2899 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2900 int subject_pos = 0;
2901 int result_pos = 0;
2902
2903 Handle<ResultSeqString> result;
2904 if (ResultSeqString::kHasAsciiEncoding) {
2905 result = Handle<ResultSeqString>::cast(
2906 isolate->factory()->NewRawAsciiString(result_len));
2907 } else {
2908 result = Handle<ResultSeqString>::cast(
2909 isolate->factory()->NewRawTwoByteString(result_len));
2910 }
2911
2912 for (int i = 0; i < matches; i++) {
2913 // Copy non-matched subject content.
2914 if (subject_pos < indices.at(i)) {
2915 String::WriteToFlat(*subject,
2916 result->GetChars() + result_pos,
2917 subject_pos,
2918 indices.at(i));
2919 result_pos += indices.at(i) - subject_pos;
2920 }
2921
2922 // Replace match.
2923 if (replacement_len > 0) {
2924 String::WriteToFlat(*replacement,
2925 result->GetChars() + result_pos,
2926 0,
2927 replacement_len);
2928 result_pos += replacement_len;
2929 }
2930
2931 subject_pos = indices.at(i) + pattern_len;
2932 }
2933 // Add remaining subject content at the end.
2934 if (subject_pos < subject_len) {
2935 String::WriteToFlat(*subject,
2936 result->GetChars() + result_pos,
2937 subject_pos,
2938 subject_len);
2939 }
2940 return *result;
2941}
2942
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002943
lrn@chromium.org303ada72010-10-27 09:33:13 +00002944MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002945 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002946 String* subject,
2947 JSRegExp* regexp,
2948 String* replacement,
2949 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002950 ASSERT(subject->IsFlat());
2951 ASSERT(replacement->IsFlat());
2952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002953 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002954
2955 int length = subject->length();
2956 Handle<String> subject_handle(subject);
2957 Handle<JSRegExp> regexp_handle(regexp);
2958 Handle<String> replacement_handle(replacement);
2959 Handle<JSArray> last_match_info_handle(last_match_info);
2960 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2961 subject_handle,
2962 0,
2963 last_match_info_handle);
2964 if (match.is_null()) {
2965 return Failure::Exception();
2966 }
2967 if (match->IsNull()) {
2968 return *subject_handle;
2969 }
2970
2971 int capture_count = regexp_handle->CaptureCount();
2972
2973 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002974 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002975 CompiledReplacement compiled_replacement;
2976 compiled_replacement.Compile(replacement_handle,
2977 capture_count,
2978 length);
2979
2980 bool is_global = regexp_handle->GetFlags().is_global();
2981
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002982 // Shortcut for simple non-regexp global replacements
2983 if (is_global &&
2984 regexp->TypeTag() == JSRegExp::ATOM &&
2985 compiled_replacement.simple_hint()) {
2986 if (subject_handle->HasOnlyAsciiChars() &&
2987 replacement_handle->HasOnlyAsciiChars()) {
2988 return StringReplaceStringWithString<SeqAsciiString>(
2989 isolate, subject_handle, regexp_handle, replacement_handle);
2990 } else {
2991 return StringReplaceStringWithString<SeqTwoByteString>(
2992 isolate, subject_handle, regexp_handle, replacement_handle);
2993 }
2994 }
2995
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002996 // Guessing the number of parts that the final result string is built
2997 // from. Global regexps can match any number of times, so we guess
2998 // conservatively.
2999 int expected_parts =
3000 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003001 ReplacementStringBuilder builder(isolate->heap(),
3002 subject_handle,
3003 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004
3005 // Index of end of last match.
3006 int prev = 0;
3007
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003008 // Number of parts added by compiled replacement plus preceeding
3009 // string and possibly suffix after last match. It is possible for
3010 // all components to use two elements when encoded as two smis.
3011 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003012 bool matched = true;
3013 do {
3014 ASSERT(last_match_info_handle->HasFastElements());
3015 // Increase the capacity of the builder before entering local handle-scope,
3016 // so its internal buffer can safely allocate a new handle if it grows.
3017 builder.EnsureCapacity(parts_added_per_loop);
3018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003019 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003020 int start, end;
3021 {
3022 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003023 FixedArray* match_info_array =
3024 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003025
3026 ASSERT_EQ(capture_count * 2 + 2,
3027 RegExpImpl::GetLastCaptureCount(match_info_array));
3028 start = RegExpImpl::GetCapture(match_info_array, 0);
3029 end = RegExpImpl::GetCapture(match_info_array, 1);
3030 }
3031
3032 if (prev < start) {
3033 builder.AddSubjectSlice(prev, start);
3034 }
3035 compiled_replacement.Apply(&builder,
3036 start,
3037 end,
3038 last_match_info_handle);
3039 prev = end;
3040
3041 // Only continue checking for global regexps.
3042 if (!is_global) break;
3043
3044 // Continue from where the match ended, unless it was an empty match.
3045 int next = end;
3046 if (start == end) {
3047 next = end + 1;
3048 if (next > length) break;
3049 }
3050
3051 match = RegExpImpl::Exec(regexp_handle,
3052 subject_handle,
3053 next,
3054 last_match_info_handle);
3055 if (match.is_null()) {
3056 return Failure::Exception();
3057 }
3058 matched = !match->IsNull();
3059 } while (matched);
3060
3061 if (prev < length) {
3062 builder.AddSubjectSlice(prev, length);
3063 }
3064
3065 return *(builder.ToString());
3066}
3067
3068
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003069template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003070MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003071 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003072 String* subject,
3073 JSRegExp* regexp,
3074 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003075 ASSERT(subject->IsFlat());
3076
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003077 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078
3079 Handle<String> subject_handle(subject);
3080 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003081
3082 // Shortcut for simple non-regexp global replacements
3083 if (regexp_handle->GetFlags().is_global() &&
3084 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3085 Handle<String> empty_string_handle(HEAP->empty_string());
3086 if (subject_handle->HasOnlyAsciiChars()) {
3087 return StringReplaceStringWithString<SeqAsciiString>(
3088 isolate, subject_handle, regexp_handle, empty_string_handle);
3089 } else {
3090 return StringReplaceStringWithString<SeqTwoByteString>(
3091 isolate, subject_handle, regexp_handle, empty_string_handle);
3092 }
3093 }
3094
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003095 Handle<JSArray> last_match_info_handle(last_match_info);
3096 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3097 subject_handle,
3098 0,
3099 last_match_info_handle);
3100 if (match.is_null()) return Failure::Exception();
3101 if (match->IsNull()) return *subject_handle;
3102
3103 ASSERT(last_match_info_handle->HasFastElements());
3104
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003105 int start, end;
3106 {
3107 AssertNoAllocation match_info_array_is_not_in_a_handle;
3108 FixedArray* match_info_array =
3109 FixedArray::cast(last_match_info_handle->elements());
3110
3111 start = RegExpImpl::GetCapture(match_info_array, 0);
3112 end = RegExpImpl::GetCapture(match_info_array, 1);
3113 }
3114
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003115 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003116 int new_length = length - (end - start);
3117 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003118 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003119 }
3120 Handle<ResultSeqString> answer;
3121 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 answer = Handle<ResultSeqString>::cast(
3123 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003124 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003125 answer = Handle<ResultSeqString>::cast(
3126 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003127 }
3128
3129 // If the regexp isn't global, only match once.
3130 if (!regexp_handle->GetFlags().is_global()) {
3131 if (start > 0) {
3132 String::WriteToFlat(*subject_handle,
3133 answer->GetChars(),
3134 0,
3135 start);
3136 }
3137 if (end < length) {
3138 String::WriteToFlat(*subject_handle,
3139 answer->GetChars() + start,
3140 end,
3141 length);
3142 }
3143 return *answer;
3144 }
3145
3146 int prev = 0; // Index of end of last match.
3147 int next = 0; // Start of next search (prev unless last match was empty).
3148 int position = 0;
3149
3150 do {
3151 if (prev < start) {
3152 // Add substring subject[prev;start] to answer string.
3153 String::WriteToFlat(*subject_handle,
3154 answer->GetChars() + position,
3155 prev,
3156 start);
3157 position += start - prev;
3158 }
3159 prev = end;
3160 next = end;
3161 // Continue from where the match ended, unless it was an empty match.
3162 if (start == end) {
3163 next++;
3164 if (next > length) break;
3165 }
3166 match = RegExpImpl::Exec(regexp_handle,
3167 subject_handle,
3168 next,
3169 last_match_info_handle);
3170 if (match.is_null()) return Failure::Exception();
3171 if (match->IsNull()) break;
3172
3173 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003174 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003175 {
3176 AssertNoAllocation match_info_array_is_not_in_a_handle;
3177 FixedArray* match_info_array =
3178 FixedArray::cast(last_match_info_handle->elements());
3179 start = RegExpImpl::GetCapture(match_info_array, 0);
3180 end = RegExpImpl::GetCapture(match_info_array, 1);
3181 }
3182 } while (true);
3183
3184 if (prev < length) {
3185 // Add substring subject[prev;length] to answer string.
3186 String::WriteToFlat(*subject_handle,
3187 answer->GetChars() + position,
3188 prev,
3189 length);
3190 position += length - prev;
3191 }
3192
3193 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003194 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003195 }
3196
3197 // Shorten string and fill
3198 int string_size = ResultSeqString::SizeFor(position);
3199 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3200 int delta = allocated_string_size - string_size;
3201
3202 answer->set_length(position);
3203 if (delta == 0) return *answer;
3204
3205 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003206 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003207
3208 return *answer;
3209}
3210
3211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003212RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003213 ASSERT(args.length() == 4);
3214
3215 CONVERT_CHECKED(String, subject, args[0]);
3216 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003217 Object* flat_subject;
3218 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3219 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3220 return maybe_flat_subject;
3221 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003222 }
3223 subject = String::cast(flat_subject);
3224 }
3225
3226 CONVERT_CHECKED(String, replacement, args[2]);
3227 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003228 Object* flat_replacement;
3229 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3230 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3231 return maybe_flat_replacement;
3232 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003233 }
3234 replacement = String::cast(flat_replacement);
3235 }
3236
3237 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3238 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3239
3240 ASSERT(last_match_info->HasFastElements());
3241
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003242 if (replacement->length() == 0) {
3243 if (subject->HasOnlyAsciiChars()) {
3244 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003246 } else {
3247 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003248 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003249 }
3250 }
3251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003252 return StringReplaceRegExpWithString(isolate,
3253 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003254 regexp,
3255 replacement,
3256 last_match_info);
3257}
3258
3259
ager@chromium.org7c537e22008-10-16 08:43:32 +00003260// Perform string match of pattern on subject, starting at start index.
3261// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003262// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003263int Runtime::StringMatch(Isolate* isolate,
3264 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003265 Handle<String> pat,
3266 int start_index) {
3267 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003268 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003269
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003270 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003271 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003272
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003273 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003274 if (start_index + pattern_length > subject_length) return -1;
3275
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003276 if (!sub->IsFlat()) FlattenString(sub);
3277 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003278
ager@chromium.org7c537e22008-10-16 08:43:32 +00003279 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003280 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003281 String::FlatContent seq_sub = sub->GetFlatContent();
3282 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003283
ager@chromium.org7c537e22008-10-16 08:43:32 +00003284 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003285 if (seq_pat.IsAscii()) {
3286 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3287 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003289 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003290 pat_vector,
3291 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003292 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003293 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003294 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003295 pat_vector,
3296 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003297 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003298 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3299 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003300 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003301 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003302 pat_vector,
3303 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003305 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003306 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003307 pat_vector,
3308 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003309}
3310
3311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003313 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003314 ASSERT(args.length() == 3);
3315
ager@chromium.org7c537e22008-10-16 08:43:32 +00003316 CONVERT_ARG_CHECKED(String, sub, 0);
3317 CONVERT_ARG_CHECKED(String, pat, 1);
3318
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003319 Object* index = args[2];
3320 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003321 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003322
ager@chromium.org870a0b62008-11-04 11:43:05 +00003323 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003324 int position =
3325 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003326 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003327}
3328
3329
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003330template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003331static int StringMatchBackwards(Vector<const schar> subject,
3332 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003333 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003334 int pattern_length = pattern.length();
3335 ASSERT(pattern_length >= 1);
3336 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003337
3338 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003339 for (int i = 0; i < pattern_length; i++) {
3340 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003341 if (c > String::kMaxAsciiCharCode) {
3342 return -1;
3343 }
3344 }
3345 }
3346
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003347 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003348 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003349 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003350 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003351 while (j < pattern_length) {
3352 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003353 break;
3354 }
3355 j++;
3356 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003357 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003358 return i;
3359 }
3360 }
3361 return -1;
3362}
3363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003364RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003365 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003366 ASSERT(args.length() == 3);
3367
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003368 CONVERT_ARG_CHECKED(String, sub, 0);
3369 CONVERT_ARG_CHECKED(String, pat, 1);
3370
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003372 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003373 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003374
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003376 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003378 if (start_index + pat_length > sub_length) {
3379 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003382 if (pat_length == 0) {
3383 return Smi::FromInt(start_index);
3384 }
3385
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003386 if (!sub->IsFlat()) FlattenString(sub);
3387 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003388
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003389 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003390 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3391
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003392 String::FlatContent sub_content = sub->GetFlatContent();
3393 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003394
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003395 if (pat_content.IsAscii()) {
3396 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3397 if (sub_content.IsAscii()) {
3398 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003399 pat_vector,
3400 start_index);
3401 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003402 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003403 pat_vector,
3404 start_index);
3405 }
3406 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003407 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3408 if (sub_content.IsAscii()) {
3409 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003410 pat_vector,
3411 start_index);
3412 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003413 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003414 pat_vector,
3415 start_index);
3416 }
3417 }
3418
3419 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003420}
3421
3422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003423RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 NoHandleAllocation ha;
3425 ASSERT(args.length() == 2);
3426
3427 CONVERT_CHECKED(String, str1, args[0]);
3428 CONVERT_CHECKED(String, str2, args[1]);
3429
3430 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003431 int str1_length = str1->length();
3432 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
3434 // Decide trivial cases without flattening.
3435 if (str1_length == 0) {
3436 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3437 return Smi::FromInt(-str2_length);
3438 } else {
3439 if (str2_length == 0) return Smi::FromInt(str1_length);
3440 }
3441
3442 int end = str1_length < str2_length ? str1_length : str2_length;
3443
3444 // No need to flatten if we are going to find the answer on the first
3445 // character. At this point we know there is at least one character
3446 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003447 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 if (d != 0) return Smi::FromInt(d);
3449
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003450 str1->TryFlatten();
3451 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003453 StringInputBuffer& buf1 =
3454 *isolate->runtime_state()->string_locale_compare_buf1();
3455 StringInputBuffer& buf2 =
3456 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457
3458 buf1.Reset(str1);
3459 buf2.Reset(str2);
3460
3461 for (int i = 0; i < end; i++) {
3462 uint16_t char1 = buf1.GetNext();
3463 uint16_t char2 = buf2.GetNext();
3464 if (char1 != char2) return Smi::FromInt(char1 - char2);
3465 }
3466
3467 return Smi::FromInt(str1_length - str2_length);
3468}
3469
3470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003471RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472 NoHandleAllocation ha;
3473 ASSERT(args.length() == 3);
3474
3475 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003476 int start, end;
3477 // We have a fast integer-only case here to avoid a conversion to double in
3478 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003479 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3480 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3481 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3482 start = from_number;
3483 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003484 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003485 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3486 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003487 start = FastD2I(from_number);
3488 end = FastD2I(to_number);
3489 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003490 RUNTIME_ASSERT(end >= start);
3491 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003492 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003493 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003494 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003495}
3496
3497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003498RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003499 ASSERT_EQ(3, args.length());
3500
3501 CONVERT_ARG_CHECKED(String, subject, 0);
3502 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3503 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3504 HandleScope handles;
3505
3506 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3507
3508 if (match.is_null()) {
3509 return Failure::Exception();
3510 }
3511 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003512 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003513 }
3514 int length = subject->length();
3515
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003516 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003517 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003518 int start;
3519 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003520 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003521 {
3522 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003523 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003524 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3525 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3526 }
3527 offsets.Add(start);
3528 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003529 if (start == end) if (++end > length) break;
3530 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003531 if (match.is_null()) {
3532 return Failure::Exception();
3533 }
3534 } while (!match->IsNull());
3535 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003536 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003537 Handle<String> substring = isolate->factory()->
3538 NewSubString(subject, offsets.at(0), offsets.at(1));
3539 elements->set(0, *substring);
3540 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003541 int from = offsets.at(i * 2);
3542 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003543 Handle<String> substring = isolate->factory()->
3544 NewProperSubString(subject, from, to);
3545 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003547 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003548 result->set_length(Smi::FromInt(matches));
3549 return *result;
3550}
3551
3552
lrn@chromium.org25156de2010-04-06 13:10:27 +00003553// Two smis before and after the match, for very long strings.
3554const int kMaxBuilderEntriesPerRegExpMatch = 5;
3555
3556
3557static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3558 Handle<JSArray> last_match_info,
3559 int match_start,
3560 int match_end) {
3561 // Fill last_match_info with a single capture.
3562 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3563 AssertNoAllocation no_gc;
3564 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3565 RegExpImpl::SetLastCaptureCount(elements, 2);
3566 RegExpImpl::SetLastInput(elements, *subject);
3567 RegExpImpl::SetLastSubject(elements, *subject);
3568 RegExpImpl::SetCapture(elements, 0, match_start);
3569 RegExpImpl::SetCapture(elements, 1, match_end);
3570}
3571
3572
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003573template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003574static bool SearchStringMultiple(Isolate* isolate,
3575 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003576 Vector<const PatternChar> pattern,
3577 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003578 FixedArrayBuilder* builder,
3579 int* match_pos) {
3580 int pos = *match_pos;
3581 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003582 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003583 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003584 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003585 while (pos <= max_search_start) {
3586 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3587 *match_pos = pos;
3588 return false;
3589 }
3590 // Position of end of previous match.
3591 int match_end = pos + pattern_length;
3592 int new_pos = search.Search(subject, match_end);
3593 if (new_pos >= 0) {
3594 // A match.
3595 if (new_pos > match_end) {
3596 ReplacementStringBuilder::AddSubjectSlice(builder,
3597 match_end,
3598 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003599 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003600 pos = new_pos;
3601 builder->Add(pattern_string);
3602 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003603 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003604 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003605 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003606
lrn@chromium.org25156de2010-04-06 13:10:27 +00003607 if (pos < max_search_start) {
3608 ReplacementStringBuilder::AddSubjectSlice(builder,
3609 pos + pattern_length,
3610 subject_length);
3611 }
3612 *match_pos = pos;
3613 return true;
3614}
3615
3616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617static bool SearchStringMultiple(Isolate* isolate,
3618 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003619 Handle<String> pattern,
3620 Handle<JSArray> last_match_info,
3621 FixedArrayBuilder* builder) {
3622 ASSERT(subject->IsFlat());
3623 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003624
3625 // Treating as if a previous match was before first character.
3626 int match_pos = -pattern->length();
3627
3628 for (;;) { // Break when search complete.
3629 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3630 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003631 String::FlatContent subject_content = subject->GetFlatContent();
3632 String::FlatContent pattern_content = pattern->GetFlatContent();
3633 if (subject_content.IsAscii()) {
3634 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3635 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 if (SearchStringMultiple(isolate,
3637 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003638 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003639 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003640 builder,
3641 &match_pos)) break;
3642 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 if (SearchStringMultiple(isolate,
3644 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003645 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003646 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003647 builder,
3648 &match_pos)) break;
3649 }
3650 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003651 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3652 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653 if (SearchStringMultiple(isolate,
3654 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003655 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003656 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003657 builder,
3658 &match_pos)) break;
3659 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003660 if (SearchStringMultiple(isolate,
3661 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003662 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003663 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003664 builder,
3665 &match_pos)) break;
3666 }
3667 }
3668 }
3669
3670 if (match_pos >= 0) {
3671 SetLastMatchInfoNoCaptures(subject,
3672 last_match_info,
3673 match_pos,
3674 match_pos + pattern->length());
3675 return true;
3676 }
3677 return false; // No matches at all.
3678}
3679
3680
3681static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003682 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 Handle<String> subject,
3684 Handle<JSRegExp> regexp,
3685 Handle<JSArray> last_match_array,
3686 FixedArrayBuilder* builder) {
3687 ASSERT(subject->IsFlat());
3688 int match_start = -1;
3689 int match_end = 0;
3690 int pos = 0;
3691 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3692 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3693
3694 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003695 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003697 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003698
3699 for (;;) { // Break on failure, return on exception.
3700 RegExpImpl::IrregexpResult result =
3701 RegExpImpl::IrregexpExecOnce(regexp,
3702 subject,
3703 pos,
3704 register_vector);
3705 if (result == RegExpImpl::RE_SUCCESS) {
3706 match_start = register_vector[0];
3707 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3708 if (match_end < match_start) {
3709 ReplacementStringBuilder::AddSubjectSlice(builder,
3710 match_end,
3711 match_start);
3712 }
3713 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003714 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003715 if (!first) {
3716 builder->Add(*isolate->factory()->NewProperSubString(subject,
3717 match_start,
3718 match_end));
3719 } else {
3720 builder->Add(*isolate->factory()->NewSubString(subject,
3721 match_start,
3722 match_end));
3723 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003724 if (match_start != match_end) {
3725 pos = match_end;
3726 } else {
3727 pos = match_end + 1;
3728 if (pos > subject_length) break;
3729 }
3730 } else if (result == RegExpImpl::RE_FAILURE) {
3731 break;
3732 } else {
3733 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3734 return result;
3735 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003736 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003737 }
3738
3739 if (match_start >= 0) {
3740 if (match_end < subject_length) {
3741 ReplacementStringBuilder::AddSubjectSlice(builder,
3742 match_end,
3743 subject_length);
3744 }
3745 SetLastMatchInfoNoCaptures(subject,
3746 last_match_array,
3747 match_start,
3748 match_end);
3749 return RegExpImpl::RE_SUCCESS;
3750 } else {
3751 return RegExpImpl::RE_FAILURE; // No matches at all.
3752 }
3753}
3754
3755
3756static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003757 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003758 Handle<String> subject,
3759 Handle<JSRegExp> regexp,
3760 Handle<JSArray> last_match_array,
3761 FixedArrayBuilder* builder) {
3762
3763 ASSERT(subject->IsFlat());
3764 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3765 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3766
3767 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003768 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003769
3770 RegExpImpl::IrregexpResult result =
3771 RegExpImpl::IrregexpExecOnce(regexp,
3772 subject,
3773 0,
3774 register_vector);
3775
3776 int capture_count = regexp->CaptureCount();
3777 int subject_length = subject->length();
3778
3779 // Position to search from.
3780 int pos = 0;
3781 // End of previous match. Differs from pos if match was empty.
3782 int match_end = 0;
3783 if (result == RegExpImpl::RE_SUCCESS) {
3784 // Need to keep a copy of the previous match for creating last_match_info
3785 // at the end, so we have two vectors that we swap between.
3786 OffsetsVector registers2(required_registers);
3787 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003788 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003789 do {
3790 int match_start = register_vector[0];
3791 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3792 if (match_end < match_start) {
3793 ReplacementStringBuilder::AddSubjectSlice(builder,
3794 match_end,
3795 match_start);
3796 }
3797 match_end = register_vector[1];
3798
3799 {
3800 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003802 // Arguments array to replace function is match, captures, index and
3803 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 Handle<FixedArray> elements =
3805 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003806 Handle<String> match;
3807 if (!first) {
3808 match = isolate->factory()->NewProperSubString(subject,
3809 match_start,
3810 match_end);
3811 } else {
3812 match = isolate->factory()->NewSubString(subject,
3813 match_start,
3814 match_end);
3815 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003816 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003817 for (int i = 1; i <= capture_count; i++) {
3818 int start = register_vector[i * 2];
3819 if (start >= 0) {
3820 int end = register_vector[i * 2 + 1];
3821 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003822 Handle<String> substring;
3823 if (!first) {
3824 substring = isolate->factory()->NewProperSubString(subject,
3825 start,
3826 end);
3827 } else {
3828 substring = isolate->factory()->NewSubString(subject, start, end);
3829 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003830 elements->set(i, *substring);
3831 } else {
3832 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003833 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003834 }
3835 }
3836 elements->set(capture_count + 1, Smi::FromInt(match_start));
3837 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003838 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003839 }
3840 // Swap register vectors, so the last successful match is in
3841 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003842 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003843 prev_register_vector = register_vector;
3844 register_vector = tmp;
3845
3846 if (match_end > match_start) {
3847 pos = match_end;
3848 } else {
3849 pos = match_end + 1;
3850 if (pos > subject_length) {
3851 break;
3852 }
3853 }
3854
3855 result = RegExpImpl::IrregexpExecOnce(regexp,
3856 subject,
3857 pos,
3858 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003859 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003860 } while (result == RegExpImpl::RE_SUCCESS);
3861
3862 if (result != RegExpImpl::RE_EXCEPTION) {
3863 // Finished matching, with at least one match.
3864 if (match_end < subject_length) {
3865 ReplacementStringBuilder::AddSubjectSlice(builder,
3866 match_end,
3867 subject_length);
3868 }
3869
3870 int last_match_capture_count = (capture_count + 1) * 2;
3871 int last_match_array_size =
3872 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3873 last_match_array->EnsureSize(last_match_array_size);
3874 AssertNoAllocation no_gc;
3875 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3876 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3877 RegExpImpl::SetLastSubject(elements, *subject);
3878 RegExpImpl::SetLastInput(elements, *subject);
3879 for (int i = 0; i < last_match_capture_count; i++) {
3880 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3881 }
3882 return RegExpImpl::RE_SUCCESS;
3883 }
3884 }
3885 // No matches at all, return failure or exception result directly.
3886 return result;
3887}
3888
3889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003890RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003893
3894 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003895 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003896 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3897 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3898 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3899
3900 ASSERT(last_match_info->HasFastElements());
3901 ASSERT(regexp->GetFlags().is_global());
3902 Handle<FixedArray> result_elements;
3903 if (result_array->HasFastElements()) {
3904 result_elements =
3905 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003906 }
3907 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003908 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003909 }
3910 FixedArrayBuilder builder(result_elements);
3911
3912 if (regexp->TypeTag() == JSRegExp::ATOM) {
3913 Handle<String> pattern(
3914 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003915 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 if (SearchStringMultiple(isolate, subject, pattern,
3917 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003918 return *builder.ToJSArray(result_array);
3919 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003920 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003921 }
3922
3923 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3924
3925 RegExpImpl::IrregexpResult result;
3926 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003927 result = SearchRegExpNoCaptureMultiple(isolate,
3928 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003929 regexp,
3930 last_match_info,
3931 &builder);
3932 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003933 result = SearchRegExpMultiple(isolate,
3934 subject,
3935 regexp,
3936 last_match_info,
3937 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003938 }
3939 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003941 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3942 return Failure::Exception();
3943}
3944
3945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003946RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947 NoHandleAllocation ha;
3948 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003949 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003950 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003951
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003952 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003953 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003954 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003955 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003956 // Character array used for conversion.
3957 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003958 return isolate->heap()->
3959 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003960 }
3961 }
3962
3963 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003964 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003966 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967 }
3968 if (isinf(value)) {
3969 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003970 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003972 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 MaybeObject* result =
3976 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 DeleteArray(str);
3978 return result;
3979}
3980
3981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003982RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 NoHandleAllocation ha;
3984 ASSERT(args.length() == 2);
3985
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003986 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003988 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 }
3990 if (isinf(value)) {
3991 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003992 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003993 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003994 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003996 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003997 int f = FastD2I(f_number);
3998 RUNTIME_ASSERT(f >= 0);
3999 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000 MaybeObject* res =
4001 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004002 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004003 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004}
4005
4006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004007RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 NoHandleAllocation ha;
4009 ASSERT(args.length() == 2);
4010
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004011 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 }
4015 if (isinf(value)) {
4016 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004019 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004021 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 int f = FastD2I(f_number);
4023 RUNTIME_ASSERT(f >= -1 && f <= 20);
4024 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004025 MaybeObject* res =
4026 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004027 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004028 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029}
4030
4031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004032RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 NoHandleAllocation ha;
4034 ASSERT(args.length() == 2);
4035
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004036 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004037 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004038 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 }
4040 if (isinf(value)) {
4041 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004042 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004044 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004046 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 int f = FastD2I(f_number);
4048 RUNTIME_ASSERT(f >= 1 && f <= 21);
4049 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004050 MaybeObject* res =
4051 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004053 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054}
4055
4056
4057// Returns a single character string where first character equals
4058// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004059static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004060 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004061 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004062 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004063 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004065 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066}
4067
4068
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004069MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4070 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004071 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 // Handle [] indexing on Strings
4073 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004074 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4075 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 }
4077
4078 // Handle [] indexing on String objects
4079 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004080 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4081 Handle<Object> result =
4082 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4083 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084 }
4085
4086 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004087 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 return prototype->GetElement(index);
4089 }
4090
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004091 return GetElement(object, index);
4092}
4093
4094
lrn@chromium.org303ada72010-10-27 09:33:13 +00004095MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 return object->GetElement(index);
4097}
4098
4099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4101 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004102 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004103 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004106 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004108 isolate->factory()->NewTypeError("non_object_property_load",
4109 HandleVector(args, 2));
4110 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 }
4112
4113 // Check if the given key is an array index.
4114 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004115 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004116 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 }
4118
4119 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004120 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004122 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 bool has_pending_exception = false;
4125 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004126 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004128 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129 }
4130
ager@chromium.org32912102009-01-16 10:38:43 +00004131 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004132 // the element if so.
4133 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004134 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004136 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137 }
4138}
4139
4140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004141RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 NoHandleAllocation ha;
4143 ASSERT(args.length() == 2);
4144
4145 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004146 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004147
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149}
4150
4151
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004152// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004153RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004154 NoHandleAllocation ha;
4155 ASSERT(args.length() == 2);
4156
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004157 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004158 // itself.
4159 //
4160 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004161 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004162 // global proxy object never has properties. This is the case
4163 // because the global proxy object forwards everything to its hidden
4164 // prototype including local lookups.
4165 //
4166 // Additionally, we need to make sure that we do not cache results
4167 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004168 if (args[0]->IsJSObject() &&
4169 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00004170 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004171 args[1]->IsString()) {
4172 JSObject* receiver = JSObject::cast(args[0]);
4173 String* key = String::cast(args[1]);
4174 if (receiver->HasFastProperties()) {
4175 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004176 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4178 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004179 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004180 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004181 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004182 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004183 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004184 LookupResult result;
4185 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004186 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004187 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004188 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004189 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004190 }
4191 } else {
4192 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004193 StringDictionary* dictionary = receiver->property_dictionary();
4194 int entry = dictionary->FindEntry(key);
4195 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004196 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004197 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004198 if (!receiver->IsGlobalObject()) return value;
4199 value = JSGlobalPropertyCell::cast(value)->value();
4200 if (!value->IsTheHole()) return value;
4201 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004202 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004203 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004204 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4205 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004206 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004207 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004208 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004209 if (index >= 0 && index < str->length()) {
4210 Handle<Object> result = GetCharAt(str, index);
4211 return *result;
4212 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004213 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004214
4215 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 return Runtime::GetObjectProperty(isolate,
4217 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004218 args.at<Object>(1));
4219}
4220
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004221// Implements part of 8.12.9 DefineOwnProperty.
4222// There are 3 cases that lead here:
4223// Step 4b - define a new accessor property.
4224// Steps 9c & 12 - replace an existing data property with an accessor property.
4225// Step 12 - update an existing accessor property with an accessor or generic
4226// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004227RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004228 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004229 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004230 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4231 CONVERT_CHECKED(String, name, args[1]);
4232 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004233 Object* fun = args[3];
4234 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004235 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4236 int unchecked = flag_attr->value();
4237 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4238 RUNTIME_ASSERT(!obj->IsNull());
4239 LookupResult result;
4240 obj->LocalLookupRealNamedProperty(name, &result);
4241
4242 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4243 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4244 // delete it to avoid running into trouble in DefineAccessor, which
4245 // handles this incorrectly if the property is readonly (does nothing)
4246 if (result.IsProperty() &&
4247 (result.type() == FIELD || result.type() == NORMAL
4248 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004249 Object* ok;
4250 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004251 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004252 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4253 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004254 }
4255 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4256}
4257
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004258// Implements part of 8.12.9 DefineOwnProperty.
4259// There are 3 cases that lead here:
4260// Step 4a - define a new data property.
4261// Steps 9b & 12 - replace an existing accessor property with a data property.
4262// Step 12 - update an existing data property with a data or generic
4263// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004264RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004265 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004266 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004267 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4268 CONVERT_ARG_CHECKED(String, name, 1);
4269 Handle<Object> obj_value = args.at<Object>(2);
4270
4271 CONVERT_CHECKED(Smi, flag, args[3]);
4272 int unchecked = flag->value();
4273 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4274
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004275 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4276
4277 // Check if this is an element.
4278 uint32_t index;
4279 bool is_element = name->AsArrayIndex(&index);
4280
4281 // Special case for elements if any of the flags are true.
4282 // If elements are in fast case we always implicitly assume that:
4283 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4284 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4285 is_element) {
4286 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004287 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004288 // We do not need to do access checks here since these has already
4289 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004290 Handle<Object> proto(js_object->GetPrototype());
4291 // If proxy is detached, ignore the assignment. Alternatively,
4292 // we could throw an exception.
4293 if (proto->IsNull()) return *obj_value;
4294 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004295 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004296 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004297 // Make sure that we never go back to fast case.
4298 dictionary->set_requires_slow_elements();
4299 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004300 Handle<NumberDictionary> extended_dictionary =
4301 NumberDictionarySet(dictionary, index, obj_value, details);
4302 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004303 if (js_object->GetElementsKind() ==
4304 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4305 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4306 } else {
4307 js_object->set_elements(*extended_dictionary);
4308 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004309 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004310 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004311 }
4312
ager@chromium.org5c838252010-02-19 08:53:10 +00004313 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004314 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004315
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004316 // To be compatible with safari we do not change the value on API objects
4317 // in defineProperty. Firefox disagrees here, and actually changes the value.
4318 if (result.IsProperty() &&
4319 (result.type() == CALLBACKS) &&
4320 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004321 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004322 }
4323
ager@chromium.org5c838252010-02-19 08:53:10 +00004324 // Take special care when attributes are different and there is already
4325 // a property. For simplicity we normalize the property which enables us
4326 // to not worry about changing the instance_descriptor and creating a new
4327 // map. The current version of SetObjectProperty does not handle attributes
4328 // correctly in the case where a property is a field and is reset with
4329 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004330 if (result.IsProperty() &&
4331 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004332 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004333 if (js_object->IsJSGlobalProxy()) {
4334 // Since the result is a property, the prototype will exist so
4335 // we don't have to check for null.
4336 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004337 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004338 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004339 // Use IgnoreAttributes version since a readonly property may be
4340 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004341 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4342 *obj_value,
4343 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004344 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004346 return Runtime::ForceSetObjectProperty(isolate,
4347 js_object,
4348 name,
4349 obj_value,
4350 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004351}
4352
4353
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004354// Special case for elements if any of the flags are true.
4355// If elements are in fast case we always implicitly assume that:
4356// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4357static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4358 Handle<JSObject> js_object,
4359 uint32_t index,
4360 Handle<Object> value,
4361 PropertyAttributes attr) {
4362 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004363 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004364 // Make sure that we never go back to fast case.
4365 dictionary->set_requires_slow_elements();
4366 PropertyDetails details = PropertyDetails(attr, NORMAL);
4367 Handle<NumberDictionary> extended_dictionary =
4368 NumberDictionarySet(dictionary, index, value, details);
4369 if (*extended_dictionary != *dictionary) {
4370 js_object->set_elements(*extended_dictionary);
4371 }
4372 return *value;
4373}
4374
4375
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004376MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4377 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004378 Handle<Object> key,
4379 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004380 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004381 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004382 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004383
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004384 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004385 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004387 isolate->factory()->NewTypeError("non_object_property_store",
4388 HandleVector(args, 2));
4389 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004390 }
4391
4392 // If the object isn't a JavaScript object, we ignore the store.
4393 if (!object->IsJSObject()) return *value;
4394
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004395 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004397 // Check if the given key is an array index.
4398 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004399 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004400 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4401 // of a string using [] notation. We need to support this too in
4402 // JavaScript.
4403 // In the case of a String object we just need to redirect the assignment to
4404 // the underlying string if the index is in range. Since the underlying
4405 // string does nothing with the assignment then we can ignore such
4406 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004407 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004409 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004410
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004411 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4412 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4413 }
4414
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004415 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004416 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004417 return *value;
4418 }
4419
4420 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004421 Handle<Object> result;
4422 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004423 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4424 return NormalizeObjectSetElement(isolate,
4425 js_object,
4426 index,
4427 value,
4428 attr);
4429 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004430 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004431 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004432 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004433 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004434 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004435 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004436 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004437 return *value;
4438 }
4439
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004441 bool has_pending_exception = false;
4442 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4443 if (has_pending_exception) return Failure::Exception();
4444 Handle<String> name = Handle<String>::cast(converted);
4445
4446 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004447 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004449 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004450 }
4451}
4452
4453
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4455 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004456 Handle<Object> key,
4457 Handle<Object> value,
4458 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004459 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004460
4461 // Check if the given key is an array index.
4462 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004463 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004464 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4465 // of a string using [] notation. We need to support this too in
4466 // JavaScript.
4467 // In the case of a String object we just need to redirect the assignment to
4468 // the underlying string if the index is in range. Since the underlying
4469 // string does nothing with the assignment then we can ignore such
4470 // assignments.
4471 if (js_object->IsStringObjectWithCharacterAt(index)) {
4472 return *value;
4473 }
4474
whesse@chromium.org7b260152011-06-20 15:33:18 +00004475 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004476 }
4477
4478 if (key->IsString()) {
4479 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004480 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004481 } else {
4482 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004483 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004484 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4485 *value,
4486 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004487 }
4488 }
4489
4490 // Call-back into JavaScript to convert the key to a string.
4491 bool has_pending_exception = false;
4492 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4493 if (has_pending_exception) return Failure::Exception();
4494 Handle<String> name = Handle<String>::cast(converted);
4495
4496 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004497 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004498 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004499 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004500 }
4501}
4502
4503
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004504MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004505 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004506 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004507 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004508
4509 // Check if the given key is an array index.
4510 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004511 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004512 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4513 // characters of a string using [] notation. In the case of a
4514 // String object we just need to redirect the deletion to the
4515 // underlying string if the index is in range. Since the
4516 // underlying string does nothing with the deletion, we can ignore
4517 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004518 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004519 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004520 }
4521
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004522 return JSObject::cast(*receiver)->DeleteElement(
4523 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004524 }
4525
4526 Handle<String> key_string;
4527 if (key->IsString()) {
4528 key_string = Handle<String>::cast(key);
4529 } else {
4530 // Call-back into JavaScript to convert the key to a string.
4531 bool has_pending_exception = false;
4532 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4533 if (has_pending_exception) return Failure::Exception();
4534 key_string = Handle<String>::cast(converted);
4535 }
4536
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004537 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004538 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004539}
4540
4541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004542RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004544 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004545
4546 Handle<Object> object = args.at<Object>(0);
4547 Handle<Object> key = args.at<Object>(1);
4548 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004549 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004550 RUNTIME_ASSERT(
4551 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004553 PropertyAttributes attributes =
4554 static_cast<PropertyAttributes>(unchecked_attributes);
4555
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004556 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004557 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004558 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004559 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4560 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004561 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004563
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004564 return Runtime::SetObjectProperty(isolate,
4565 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004566 key,
4567 value,
4568 attributes,
4569 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004570}
4571
4572
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004573// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004574// This is used to decide if we should transform null and undefined
4575// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004576RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004577 NoHandleAllocation ha;
4578 RUNTIME_ASSERT(args.length() == 1);
4579
4580 Handle<Object> object = args.at<Object>(0);
4581
4582 if (object->IsJSFunction()) {
4583 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004584 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004585 }
4586 return isolate->heap()->undefined_value();
4587}
4588
4589
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004590// Set a local property, even if it is READ_ONLY. If the property does not
4591// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004592RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004594 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 CONVERT_CHECKED(JSObject, object, args[0]);
4596 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004597 // Compute attributes.
4598 PropertyAttributes attributes = NONE;
4599 if (args.length() == 4) {
4600 CONVERT_CHECKED(Smi, value_obj, args[3]);
4601 int unchecked_value = value_obj->value();
4602 // Only attribute bits should be set.
4603 RUNTIME_ASSERT(
4604 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4605 attributes = static_cast<PropertyAttributes>(unchecked_value);
4606 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004608 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004609 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610}
4611
4612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004613RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004614 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004615 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004617 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004618 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004619 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004620 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004621 ? JSReceiver::STRICT_DELETION
4622 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004623}
4624
4625
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004626static Object* HasLocalPropertyImplementation(Isolate* isolate,
4627 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004628 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004629 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004630 // Handle hidden prototypes. If there's a hidden prototype above this thing
4631 // then we have to check it for properties, because they are supposed to
4632 // look like they are on this object.
4633 Handle<Object> proto(object->GetPrototype());
4634 if (proto->IsJSObject() &&
4635 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004636 return HasLocalPropertyImplementation(isolate,
4637 Handle<JSObject>::cast(proto),
4638 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004639 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004640 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004641}
4642
4643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004644RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 NoHandleAllocation ha;
4646 ASSERT(args.length() == 2);
4647 CONVERT_CHECKED(String, key, args[1]);
4648
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004649 uint32_t index;
4650 const bool key_is_array_index = key->AsArrayIndex(&index);
4651
ager@chromium.org9085a012009-05-11 19:22:57 +00004652 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004654 if (obj->IsJSObject()) {
4655 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004656 // Fast case: either the key is a real named property or it is not
4657 // an array index and there are no interceptors or hidden
4658 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004659 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004660 Map* map = object->map();
4661 if (!key_is_array_index &&
4662 !map->has_named_interceptor() &&
4663 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4664 return isolate->heap()->false_value();
4665 }
4666 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004667 HandleScope scope(isolate);
4668 return HasLocalPropertyImplementation(isolate,
4669 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004670 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004671 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004673 String* string = String::cast(obj);
4674 if (index < static_cast<uint32_t>(string->length())) {
4675 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004676 }
4677 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004678 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004679}
4680
4681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004682RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004683 NoHandleAllocation na;
4684 ASSERT(args.length() == 2);
4685
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004686 // Only JS receivers can have properties.
4687 if (args[0]->IsJSReceiver()) {
4688 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004690 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004692 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693}
4694
4695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004696RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697 NoHandleAllocation na;
4698 ASSERT(args.length() == 2);
4699
4700 // Only JS objects can have elements.
4701 if (args[0]->IsJSObject()) {
4702 JSObject* object = JSObject::cast(args[0]);
4703 CONVERT_CHECKED(Smi, index_obj, args[1]);
4704 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004705 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708}
4709
4710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004711RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 NoHandleAllocation ha;
4713 ASSERT(args.length() == 2);
4714
4715 CONVERT_CHECKED(JSObject, object, args[0]);
4716 CONVERT_CHECKED(String, key, args[1]);
4717
4718 uint32_t index;
4719 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004720 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004721 }
4722
ager@chromium.org870a0b62008-11-04 11:43:05 +00004723 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004724 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725}
4726
4727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004728RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004729 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004731 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004732 return *GetKeysFor(object);
4733}
4734
4735
4736// Returns either a FixedArray as Runtime_GetPropertyNames,
4737// or, if the given object has an enum cache that contains
4738// all enumerable properties of the object and its prototypes
4739// have none, the map of the object. This is used to speed up
4740// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004741RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742 ASSERT(args.length() == 1);
4743
4744 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4745
4746 if (raw_object->IsSimpleEnum()) return raw_object->map();
4747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004748 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004750 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4751 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752
4753 // Test again, since cache may have been built by preceding call.
4754 if (object->IsSimpleEnum()) return object->map();
4755
4756 return *content;
4757}
4758
4759
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004760// Find the length of the prototype chain that is to to handled as one. If a
4761// prototype object is hidden it is to be viewed as part of the the object it
4762// is prototype for.
4763static int LocalPrototypeChainLength(JSObject* obj) {
4764 int count = 1;
4765 Object* proto = obj->GetPrototype();
4766 while (proto->IsJSObject() &&
4767 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4768 count++;
4769 proto = JSObject::cast(proto)->GetPrototype();
4770 }
4771 return count;
4772}
4773
4774
4775// Return the names of the local named properties.
4776// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004777RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004778 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004779 ASSERT(args.length() == 1);
4780 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004781 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004782 }
4783 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4784
4785 // Skip the global proxy as it has no properties and always delegates to the
4786 // real global object.
4787 if (obj->IsJSGlobalProxy()) {
4788 // Only collect names if access is permitted.
4789 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004790 !isolate->MayNamedAccess(*obj,
4791 isolate->heap()->undefined_value(),
4792 v8::ACCESS_KEYS)) {
4793 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4794 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004795 }
4796 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4797 }
4798
4799 // Find the number of objects making up this.
4800 int length = LocalPrototypeChainLength(*obj);
4801
4802 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004803 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004804 int total_property_count = 0;
4805 Handle<JSObject> jsproto = obj;
4806 for (int i = 0; i < length; i++) {
4807 // Only collect names if access is permitted.
4808 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004809 !isolate->MayNamedAccess(*jsproto,
4810 isolate->heap()->undefined_value(),
4811 v8::ACCESS_KEYS)) {
4812 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4813 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004814 }
4815 int n;
4816 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4817 local_property_count[i] = n;
4818 total_property_count += n;
4819 if (i < length - 1) {
4820 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4821 }
4822 }
4823
4824 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004825 Handle<FixedArray> names =
4826 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004827
4828 // Get the property names.
4829 jsproto = obj;
4830 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004831 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004832 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004833 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4834 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004835 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004836 proto_with_hidden_properties++;
4837 }
4838 if (i < length - 1) {
4839 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4840 }
4841 }
4842
4843 // Filter out name of hidden propeties object.
4844 if (proto_with_hidden_properties > 0) {
4845 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004846 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004847 names->length() - proto_with_hidden_properties);
4848 int dest_pos = 0;
4849 for (int i = 0; i < total_property_count; i++) {
4850 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004851 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004852 continue;
4853 }
4854 names->set(dest_pos++, name);
4855 }
4856 }
4857
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004858 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004859}
4860
4861
4862// Return the names of the local indexed properties.
4863// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004864RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004865 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004866 ASSERT(args.length() == 1);
4867 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004868 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004869 }
4870 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4871
4872 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004873 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004874 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004875 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004876}
4877
4878
4879// Return information on whether an object has a named or indexed interceptor.
4880// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004881RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004882 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004883 ASSERT(args.length() == 1);
4884 if (!args[0]->IsJSObject()) {
4885 return Smi::FromInt(0);
4886 }
4887 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4888
4889 int result = 0;
4890 if (obj->HasNamedInterceptor()) result |= 2;
4891 if (obj->HasIndexedInterceptor()) result |= 1;
4892
4893 return Smi::FromInt(result);
4894}
4895
4896
4897// Return property names from named interceptor.
4898// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004899RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004900 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004901 ASSERT(args.length() == 1);
4902 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4903
4904 if (obj->HasNamedInterceptor()) {
4905 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4906 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004908 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004909}
4910
4911
4912// Return element names from indexed interceptor.
4913// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004914RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004915 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004916 ASSERT(args.length() == 1);
4917 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4918
4919 if (obj->HasIndexedInterceptor()) {
4920 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4921 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4922 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004924}
4925
4926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004927RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004928 ASSERT_EQ(args.length(), 1);
4929 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004930 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004931 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004932
4933 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004934 // Do access checks before going to the global object.
4935 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004936 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004937 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004938 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4939 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004940 }
4941
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004942 Handle<Object> proto(object->GetPrototype());
4943 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004944 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004945 object = Handle<JSObject>::cast(proto);
4946 }
4947
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004948 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4949 LOCAL_ONLY);
4950 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4951 // property array and since the result is mutable we have to create
4952 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004953 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004954 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004955 for (int i = 0; i < length; i++) {
4956 Object* entry = contents->get(i);
4957 if (entry->IsString()) {
4958 copy->set(i, entry);
4959 } else {
4960 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004961 HandleScope scope(isolate);
4962 Handle<Object> entry_handle(entry, isolate);
4963 Handle<Object> entry_str =
4964 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004965 copy->set(i, *entry_str);
4966 }
4967 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004968 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004969}
4970
4971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004972RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004973 NoHandleAllocation ha;
4974 ASSERT(args.length() == 1);
4975
4976 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004977 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004978 it.AdvanceToArgumentsFrame();
4979 JavaScriptFrame* frame = it.frame();
4980
4981 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004982 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004983
4984 // Try to convert the key to an index. If successful and within
4985 // index return the the argument from the frame.
4986 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004987 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004988 return frame->GetParameter(index);
4989 }
4990
4991 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004992 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004993 bool exception = false;
4994 Handle<Object> converted =
4995 Execution::ToString(args.at<Object>(0), &exception);
4996 if (exception) return Failure::Exception();
4997 Handle<String> key = Handle<String>::cast(converted);
4998
4999 // Try to convert the string key into an array index.
5000 if (key->AsArrayIndex(&index)) {
5001 if (index < n) {
5002 return frame->GetParameter(index);
5003 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005004 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005 }
5006 }
5007
5008 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5010 if (key->Equals(isolate->heap()->callee_symbol())) {
5011 Object* function = frame->function();
5012 if (function->IsJSFunction() &&
5013 JSFunction::cast(function)->shared()->strict_mode()) {
5014 return isolate->Throw(*isolate->factory()->NewTypeError(
5015 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5016 }
5017 return function;
5018 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005019
5020 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005021 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005022}
5023
5024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005025RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005026 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005027
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005028 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005029 Handle<Object> object = args.at<Object>(0);
5030 if (object->IsJSObject()) {
5031 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005032 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005033 MaybeObject* ok = js_object->TransformToFastProperties(0);
5034 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005035 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005036 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005037 return *object;
5038}
5039
5040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005041RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005042 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005043
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005044 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005045 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005046 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005047 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005048 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005049 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005050 return *object;
5051}
5052
5053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005054RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005055 NoHandleAllocation ha;
5056 ASSERT(args.length() == 1);
5057
5058 return args[0]->ToBoolean();
5059}
5060
5061
5062// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5063// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005064RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005065 NoHandleAllocation ha;
5066
5067 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005068 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005069 HeapObject* heap_obj = HeapObject::cast(obj);
5070
5071 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 if (heap_obj->map()->is_undetectable()) {
5073 return isolate->heap()->undefined_symbol();
5074 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005075
5076 InstanceType instance_type = heap_obj->map()->instance_type();
5077 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005079 }
5080
5081 switch (instance_type) {
5082 case ODDBALL_TYPE:
5083 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005085 }
5086 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005087 return FLAG_harmony_typeof
5088 ? isolate->heap()->null_symbol()
5089 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005090 }
5091 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005092 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005093 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005094 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 default:
5096 // For any kind of object not handled above, the spec rule for
5097 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005098 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005099 }
5100}
5101
5102
lrn@chromium.org25156de2010-04-06 13:10:27 +00005103static bool AreDigits(const char*s, int from, int to) {
5104 for (int i = from; i < to; i++) {
5105 if (s[i] < '0' || s[i] > '9') return false;
5106 }
5107
5108 return true;
5109}
5110
5111
5112static int ParseDecimalInteger(const char*s, int from, int to) {
5113 ASSERT(to - from < 10); // Overflow is not possible.
5114 ASSERT(from < to);
5115 int d = s[from] - '0';
5116
5117 for (int i = from + 1; i < to; i++) {
5118 d = 10 * d + (s[i] - '0');
5119 }
5120
5121 return d;
5122}
5123
5124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005125RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005126 NoHandleAllocation ha;
5127 ASSERT(args.length() == 1);
5128 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005129 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005130
5131 // Fast case: short integer or some sorts of junk values.
5132 int len = subject->length();
5133 if (subject->IsSeqAsciiString()) {
5134 if (len == 0) return Smi::FromInt(0);
5135
5136 char const* data = SeqAsciiString::cast(subject)->GetChars();
5137 bool minus = (data[0] == '-');
5138 int start_pos = (minus ? 1 : 0);
5139
5140 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005142 } else if (data[start_pos] > '9') {
5143 // Fast check for a junk value. A valid string may start from a
5144 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5145 // the 'I' character ('Infinity'). All of that have codes not greater than
5146 // '9' except 'I'.
5147 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005149 }
5150 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5151 // The maximal/minimal smi has 10 digits. If the string has less digits we
5152 // know it will fit into the smi-data type.
5153 int d = ParseDecimalInteger(data, start_pos, len);
5154 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005155 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005156 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005157 } else if (!subject->HasHashCode() &&
5158 len <= String::kMaxArrayIndexSize &&
5159 (len == 1 || data[0] != '0')) {
5160 // String hash is not calculated yet but all the data are present.
5161 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005162 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005163#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005164 subject->Hash(); // Force hash calculation.
5165 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5166 static_cast<int>(hash));
5167#endif
5168 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005169 }
5170 return Smi::FromInt(d);
5171 }
5172 }
5173
5174 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005175 return isolate->heap()->NumberFromDouble(
5176 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005177}
5178
5179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005180RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181 NoHandleAllocation ha;
5182 ASSERT(args.length() == 1);
5183
5184 CONVERT_CHECKED(JSArray, codes, args[0]);
5185 int length = Smi::cast(codes->length())->value();
5186
5187 // Check if the string can be ASCII.
5188 int i;
5189 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005190 Object* element;
5191 { MaybeObject* maybe_element = codes->GetElement(i);
5192 // We probably can't get an exception here, but just in order to enforce
5193 // the checking of inputs in the runtime calls we check here.
5194 if (!maybe_element->ToObject(&element)) return maybe_element;
5195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5197 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5198 break;
5199 }
5200
lrn@chromium.org303ada72010-10-27 09:33:13 +00005201 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005204 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005205 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 }
5207
lrn@chromium.org303ada72010-10-27 09:33:13 +00005208 Object* object = NULL;
5209 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005210 String* result = String::cast(object);
5211 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005212 Object* element;
5213 { MaybeObject* maybe_element = codes->GetElement(i);
5214 if (!maybe_element->ToObject(&element)) return maybe_element;
5215 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005217 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218 }
5219 return result;
5220}
5221
5222
5223// kNotEscaped is generated by the following:
5224//
5225// #!/bin/perl
5226// for (my $i = 0; $i < 256; $i++) {
5227// print "\n" if $i % 16 == 0;
5228// my $c = chr($i);
5229// my $escaped = 1;
5230// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5231// print $escaped ? "0, " : "1, ";
5232// }
5233
5234
5235static bool IsNotEscaped(uint16_t character) {
5236 // Only for 8 bit characters, the rest are always escaped (in a different way)
5237 ASSERT(character < 256);
5238 static const char kNotEscaped[256] = {
5239 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5240 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5241 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5242 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5243 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5244 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5245 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5246 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5251 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5252 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5253 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5254 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5255 };
5256 return kNotEscaped[character] != 0;
5257}
5258
5259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005260RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 const char hex_chars[] = "0123456789ABCDEF";
5262 NoHandleAllocation ha;
5263 ASSERT(args.length() == 1);
5264 CONVERT_CHECKED(String, source, args[0]);
5265
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005266 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267
5268 int escaped_length = 0;
5269 int length = source->length();
5270 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005271 Access<StringInputBuffer> buffer(
5272 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005273 buffer->Reset(source);
5274 while (buffer->has_more()) {
5275 uint16_t character = buffer->GetNext();
5276 if (character >= 256) {
5277 escaped_length += 6;
5278 } else if (IsNotEscaped(character)) {
5279 escaped_length++;
5280 } else {
5281 escaped_length += 3;
5282 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005283 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005284 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005285 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005286 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 return Failure::OutOfMemoryException();
5288 }
5289 }
5290 }
5291 // No length change implies no change. Return original string if no change.
5292 if (escaped_length == length) {
5293 return source;
5294 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005295 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 { MaybeObject* maybe_o =
5297 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005298 if (!maybe_o->ToObject(&o)) return maybe_o;
5299 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005300 String* destination = String::cast(o);
5301 int dest_position = 0;
5302
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005303 Access<StringInputBuffer> buffer(
5304 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005305 buffer->Rewind();
5306 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005307 uint16_t chr = buffer->GetNext();
5308 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005309 destination->Set(dest_position, '%');
5310 destination->Set(dest_position+1, 'u');
5311 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5312 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5313 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5314 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005316 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005317 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318 dest_position++;
5319 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005320 destination->Set(dest_position, '%');
5321 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5322 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323 dest_position += 3;
5324 }
5325 }
5326 return destination;
5327}
5328
5329
5330static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5331 static const signed char kHexValue['g'] = {
5332 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5333 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5334 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5335 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5336 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5337 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5338 -1, 10, 11, 12, 13, 14, 15 };
5339
5340 if (character1 > 'f') return -1;
5341 int hi = kHexValue[character1];
5342 if (hi == -1) return -1;
5343 if (character2 > 'f') return -1;
5344 int lo = kHexValue[character2];
5345 if (lo == -1) return -1;
5346 return (hi << 4) + lo;
5347}
5348
5349
ager@chromium.org870a0b62008-11-04 11:43:05 +00005350static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005351 int i,
5352 int length,
5353 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005354 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005355 int32_t hi = 0;
5356 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005357 if (character == '%' &&
5358 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005359 source->Get(i + 1) == 'u' &&
5360 (hi = TwoDigitHex(source->Get(i + 2),
5361 source->Get(i + 3))) != -1 &&
5362 (lo = TwoDigitHex(source->Get(i + 4),
5363 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005364 *step = 6;
5365 return (hi << 8) + lo;
5366 } else if (character == '%' &&
5367 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005368 (lo = TwoDigitHex(source->Get(i + 1),
5369 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 *step = 3;
5371 return lo;
5372 } else {
5373 *step = 1;
5374 return character;
5375 }
5376}
5377
5378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005379RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005380 NoHandleAllocation ha;
5381 ASSERT(args.length() == 1);
5382 CONVERT_CHECKED(String, source, args[0]);
5383
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005384 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385
5386 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005387 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388
5389 int unescaped_length = 0;
5390 for (int i = 0; i < length; unescaped_length++) {
5391 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005392 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005394 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 i += step;
5396 }
5397
5398 // No length change implies no change. Return original string if no change.
5399 if (unescaped_length == length)
5400 return source;
5401
lrn@chromium.org303ada72010-10-27 09:33:13 +00005402 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005403 { MaybeObject* maybe_o =
5404 ascii ?
5405 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5406 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005407 if (!maybe_o->ToObject(&o)) return maybe_o;
5408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 String* destination = String::cast(o);
5410
5411 int dest_position = 0;
5412 for (int i = 0; i < length; dest_position++) {
5413 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005414 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005415 i += step;
5416 }
5417 return destination;
5418}
5419
5420
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005421static const unsigned int kQuoteTableLength = 128u;
5422
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005423static const int kJsonQuotesCharactersPerEntry = 8;
5424static const char* const JsonQuotes =
5425 "\\u0000 \\u0001 \\u0002 \\u0003 "
5426 "\\u0004 \\u0005 \\u0006 \\u0007 "
5427 "\\b \\t \\n \\u000b "
5428 "\\f \\r \\u000e \\u000f "
5429 "\\u0010 \\u0011 \\u0012 \\u0013 "
5430 "\\u0014 \\u0015 \\u0016 \\u0017 "
5431 "\\u0018 \\u0019 \\u001a \\u001b "
5432 "\\u001c \\u001d \\u001e \\u001f "
5433 " ! \\\" # "
5434 "$ % & ' "
5435 "( ) * + "
5436 ", - . / "
5437 "0 1 2 3 "
5438 "4 5 6 7 "
5439 "8 9 : ; "
5440 "< = > ? "
5441 "@ A B C "
5442 "D E F G "
5443 "H I J K "
5444 "L M N O "
5445 "P Q R S "
5446 "T U V W "
5447 "X Y Z [ "
5448 "\\\\ ] ^ _ "
5449 "` a b c "
5450 "d e f g "
5451 "h i j k "
5452 "l m n o "
5453 "p q r s "
5454 "t u v w "
5455 "x y z { "
5456 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005457
5458
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005459// For a string that is less than 32k characters it should always be
5460// possible to allocate it in new space.
5461static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5462
5463
5464// Doing JSON quoting cannot make the string more than this many times larger.
5465static const int kJsonQuoteWorstCaseBlowup = 6;
5466
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005467static const int kSpaceForQuotesAndComma = 3;
5468static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005469
5470// Covers the entire ASCII range (all other characters are unchanged by JSON
5471// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005472static const byte JsonQuoteLengths[kQuoteTableLength] = {
5473 6, 6, 6, 6, 6, 6, 6, 6,
5474 2, 2, 2, 6, 2, 2, 6, 6,
5475 6, 6, 6, 6, 6, 6, 6, 6,
5476 6, 6, 6, 6, 6, 6, 6, 6,
5477 1, 1, 2, 1, 1, 1, 1, 1,
5478 1, 1, 1, 1, 1, 1, 1, 1,
5479 1, 1, 1, 1, 1, 1, 1, 1,
5480 1, 1, 1, 1, 1, 1, 1, 1,
5481 1, 1, 1, 1, 1, 1, 1, 1,
5482 1, 1, 1, 1, 1, 1, 1, 1,
5483 1, 1, 1, 1, 1, 1, 1, 1,
5484 1, 1, 1, 1, 2, 1, 1, 1,
5485 1, 1, 1, 1, 1, 1, 1, 1,
5486 1, 1, 1, 1, 1, 1, 1, 1,
5487 1, 1, 1, 1, 1, 1, 1, 1,
5488 1, 1, 1, 1, 1, 1, 1, 1,
5489};
5490
5491
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005492template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005493MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005494
5495
5496template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005497MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5498 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005499}
5500
5501
5502template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005503MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5504 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005505}
5506
5507
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005508template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005509static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5510 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005511 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005512 const Char* read_cursor = characters.start();
5513 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005514 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005515 int quoted_length = kSpaceForQuotes;
5516 while (read_cursor < end) {
5517 Char c = *(read_cursor++);
5518 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5519 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005520 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005521 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005522 }
5523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005524 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5525 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005526 Object* new_object;
5527 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005528 return new_alloc;
5529 }
5530 StringType* new_string = StringType::cast(new_object);
5531
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005532 Char* write_cursor = reinterpret_cast<Char*>(
5533 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005534 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005535 *(write_cursor++) = '"';
5536
5537 read_cursor = characters.start();
5538 while (read_cursor < end) {
5539 Char c = *(read_cursor++);
5540 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5541 *(write_cursor++) = c;
5542 } else {
5543 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5544 const char* replacement = JsonQuotes +
5545 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5546 for (int i = 0; i < len; i++) {
5547 *write_cursor++ = *replacement++;
5548 }
5549 }
5550 }
5551 *(write_cursor++) = '"';
5552 return new_string;
5553}
5554
5555
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005556template <typename SinkChar, typename SourceChar>
5557static inline SinkChar* WriteQuoteJsonString(
5558 Isolate* isolate,
5559 SinkChar* write_cursor,
5560 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005561 // SinkChar is only char if SourceChar is guaranteed to be char.
5562 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005563 const SourceChar* read_cursor = characters.start();
5564 const SourceChar* end = read_cursor + characters.length();
5565 *(write_cursor++) = '"';
5566 while (read_cursor < end) {
5567 SourceChar c = *(read_cursor++);
5568 if (sizeof(SourceChar) > 1u &&
5569 static_cast<unsigned>(c) >= kQuoteTableLength) {
5570 *(write_cursor++) = static_cast<SinkChar>(c);
5571 } else {
5572 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5573 const char* replacement = JsonQuotes +
5574 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5575 write_cursor[0] = replacement[0];
5576 if (len > 1) {
5577 write_cursor[1] = replacement[1];
5578 if (len > 2) {
5579 ASSERT(len == 6);
5580 write_cursor[2] = replacement[2];
5581 write_cursor[3] = replacement[3];
5582 write_cursor[4] = replacement[4];
5583 write_cursor[5] = replacement[5];
5584 }
5585 }
5586 write_cursor += len;
5587 }
5588 }
5589 *(write_cursor++) = '"';
5590 return write_cursor;
5591}
5592
5593
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005594template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005595static MaybeObject* QuoteJsonString(Isolate* isolate,
5596 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005597 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005598 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005599 int worst_case_length =
5600 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005601 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005602 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005603 }
5604
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005605 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5606 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005607 Object* new_object;
5608 if (!new_alloc->ToObject(&new_object)) {
5609 return new_alloc;
5610 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005611 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005612 // Even if our string is small enough to fit in new space we still have to
5613 // handle it being allocated in old space as may happen in the third
5614 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5615 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005616 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005617 }
5618 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005620
5621 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5622 Char* write_cursor = reinterpret_cast<Char*>(
5623 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005624 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005625 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5626 write_cursor,
5627 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005628 int final_length = static_cast<int>(
5629 write_cursor - reinterpret_cast<Char*>(
5630 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005631 isolate->heap()->new_space()->
5632 template ShrinkStringAtAllocationBoundary<StringType>(
5633 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005634 return new_string;
5635}
5636
5637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005638RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005639 NoHandleAllocation ha;
5640 CONVERT_CHECKED(String, str, args[0]);
5641 if (!str->IsFlat()) {
5642 MaybeObject* try_flatten = str->TryFlatten();
5643 Object* flat;
5644 if (!try_flatten->ToObject(&flat)) {
5645 return try_flatten;
5646 }
5647 str = String::cast(flat);
5648 ASSERT(str->IsFlat());
5649 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005650 String::FlatContent flat = str->GetFlatContent();
5651 ASSERT(flat.IsFlat());
5652 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005653 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005654 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005655 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005656 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005657 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005658 }
5659}
5660
5661
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005662RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005663 NoHandleAllocation ha;
5664 CONVERT_CHECKED(String, str, args[0]);
5665 if (!str->IsFlat()) {
5666 MaybeObject* try_flatten = str->TryFlatten();
5667 Object* flat;
5668 if (!try_flatten->ToObject(&flat)) {
5669 return try_flatten;
5670 }
5671 str = String::cast(flat);
5672 ASSERT(str->IsFlat());
5673 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005674 String::FlatContent flat = str->GetFlatContent();
5675 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005676 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005677 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005678 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005680 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005681 }
5682}
5683
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005684
5685template <typename Char, typename StringType>
5686static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5687 FixedArray* array,
5688 int worst_case_length) {
5689 int length = array->length();
5690
5691 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5692 worst_case_length);
5693 Object* new_object;
5694 if (!new_alloc->ToObject(&new_object)) {
5695 return new_alloc;
5696 }
5697 if (!isolate->heap()->new_space()->Contains(new_object)) {
5698 // Even if our string is small enough to fit in new space we still have to
5699 // handle it being allocated in old space as may happen in the third
5700 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5701 // CEntryStub::GenerateCore.
5702 return isolate->heap()->undefined_value();
5703 }
5704 AssertNoAllocation no_gc;
5705 StringType* new_string = StringType::cast(new_object);
5706 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5707
5708 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5709 Char* write_cursor = reinterpret_cast<Char*>(
5710 new_string->address() + SeqAsciiString::kHeaderSize);
5711 *(write_cursor++) = '[';
5712 for (int i = 0; i < length; i++) {
5713 if (i != 0) *(write_cursor++) = ',';
5714 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005715 String::FlatContent content = str->GetFlatContent();
5716 ASSERT(content.IsFlat());
5717 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005718 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5719 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005720 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005721 } else {
5722 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5723 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005724 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005725 }
5726 }
5727 *(write_cursor++) = ']';
5728
5729 int final_length = static_cast<int>(
5730 write_cursor - reinterpret_cast<Char*>(
5731 new_string->address() + SeqAsciiString::kHeaderSize));
5732 isolate->heap()->new_space()->
5733 template ShrinkStringAtAllocationBoundary<StringType>(
5734 new_string, final_length);
5735 return new_string;
5736}
5737
5738
5739RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5740 NoHandleAllocation ha;
5741 ASSERT(args.length() == 1);
5742 CONVERT_CHECKED(JSArray, array, args[0]);
5743
5744 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5745 FixedArray* elements = FixedArray::cast(array->elements());
5746 int n = elements->length();
5747 bool ascii = true;
5748 int total_length = 0;
5749
5750 for (int i = 0; i < n; i++) {
5751 Object* elt = elements->get(i);
5752 if (!elt->IsString()) return isolate->heap()->undefined_value();
5753 String* element = String::cast(elt);
5754 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5755 total_length += element->length();
5756 if (ascii && element->IsTwoByteRepresentation()) {
5757 ascii = false;
5758 }
5759 }
5760
5761 int worst_case_length =
5762 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5763 + total_length * kJsonQuoteWorstCaseBlowup;
5764
5765 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5766 return isolate->heap()->undefined_value();
5767 }
5768
5769 if (ascii) {
5770 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5771 elements,
5772 worst_case_length);
5773 } else {
5774 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5775 elements,
5776 worst_case_length);
5777 }
5778}
5779
5780
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005781RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005782 NoHandleAllocation ha;
5783
5784 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005785 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005786
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005787 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005788
lrn@chromium.org25156de2010-04-06 13:10:27 +00005789 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005790 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005791 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005792}
5793
5794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005795RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005796 NoHandleAllocation ha;
5797 CONVERT_CHECKED(String, str, args[0]);
5798
5799 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005800 double value = StringToDouble(isolate->unicode_cache(),
5801 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802
5803 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005804 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005805}
5806
5807
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005808template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005809MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005810 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005811 String* s,
5812 int length,
5813 int input_string_length,
5814 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005815 // We try this twice, once with the assumption that the result is no longer
5816 // than the input and, if that assumption breaks, again with the exact
5817 // length. This may not be pretty, but it is nicer than what was here before
5818 // and I hereby claim my vaffel-is.
5819 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005820 // Allocate the resulting string.
5821 //
5822 // NOTE: This assumes that the upper/lower case of an ascii
5823 // character is also ascii. This is currently the case, but it
5824 // might break in the future if we implement more context and locale
5825 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005826 Object* o;
5827 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005828 ? isolate->heap()->AllocateRawAsciiString(length)
5829 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005830 if (!maybe_o->ToObject(&o)) return maybe_o;
5831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005832 String* result = String::cast(o);
5833 bool has_changed_character = false;
5834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005835 // Convert all characters to upper case, assuming that they will fit
5836 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005837 Access<StringInputBuffer> buffer(
5838 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005839 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005840 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005841 // We can assume that the string is not empty
5842 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005843 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005844 bool has_next = buffer->has_more();
5845 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005846 int char_length = mapping->get(current, next, chars);
5847 if (char_length == 0) {
5848 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005849 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005850 i++;
5851 } else if (char_length == 1) {
5852 // Common case: converting the letter resulted in one character.
5853 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005854 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005855 has_changed_character = true;
5856 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005857 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858 // We've assumed that the result would be as long as the
5859 // input but here is a character that converts to several
5860 // characters. No matter, we calculate the exact length
5861 // of the result and try the whole thing again.
5862 //
5863 // Note that this leaves room for optimization. We could just
5864 // memcpy what we already have to the result string. Also,
5865 // the result string is the last object allocated we could
5866 // "realloc" it and probably, in the vast majority of cases,
5867 // extend the existing string to be able to hold the full
5868 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005869 int next_length = 0;
5870 if (has_next) {
5871 next_length = mapping->get(next, 0, chars);
5872 if (next_length == 0) next_length = 1;
5873 }
5874 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005875 while (buffer->has_more()) {
5876 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005877 // NOTE: we use 0 as the next character here because, while
5878 // the next character may affect what a character converts to,
5879 // it does not in any case affect the length of what it convert
5880 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005881 int char_length = mapping->get(current, 0, chars);
5882 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005883 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005884 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005885 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005886 return Failure::OutOfMemoryException();
5887 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005888 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005889 // Try again with the real length.
5890 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005891 } else {
5892 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005893 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894 i++;
5895 }
5896 has_changed_character = true;
5897 }
5898 current = next;
5899 }
5900 if (has_changed_character) {
5901 return result;
5902 } else {
5903 // If we didn't actually change anything in doing the conversion
5904 // we simple return the result and let the converted string
5905 // become garbage; there is no reason to keep two identical strings
5906 // alive.
5907 return s;
5908 }
5909}
5910
5911
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005912namespace {
5913
lrn@chromium.org303ada72010-10-27 09:33:13 +00005914static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5915
5916
5917// Given a word and two range boundaries returns a word with high bit
5918// set in every byte iff the corresponding input byte was strictly in
5919// the range (m, n). All the other bits in the result are cleared.
5920// This function is only useful when it can be inlined and the
5921// boundaries are statically known.
5922// Requires: all bytes in the input word and the boundaries must be
5923// ascii (less than 0x7F).
5924static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5925 // Every byte in an ascii string is less than or equal to 0x7F.
5926 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5927 // Use strict inequalities since in edge cases the function could be
5928 // further simplified.
5929 ASSERT(0 < m && m < n && n < 0x7F);
5930 // Has high bit set in every w byte less than n.
5931 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5932 // Has high bit set in every w byte greater than m.
5933 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5934 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5935}
5936
5937
5938enum AsciiCaseConversion {
5939 ASCII_TO_LOWER,
5940 ASCII_TO_UPPER
5941};
5942
5943
5944template <AsciiCaseConversion dir>
5945struct FastAsciiConverter {
5946 static bool Convert(char* dst, char* src, int length) {
5947#ifdef DEBUG
5948 char* saved_dst = dst;
5949 char* saved_src = src;
5950#endif
5951 // We rely on the distance between upper and lower case letters
5952 // being a known power of 2.
5953 ASSERT('a' - 'A' == (1 << 5));
5954 // Boundaries for the range of input characters than require conversion.
5955 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5956 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5957 bool changed = false;
5958 char* const limit = src + length;
5959#ifdef V8_HOST_CAN_READ_UNALIGNED
5960 // Process the prefix of the input that requires no conversion one
5961 // (machine) word at a time.
5962 while (src <= limit - sizeof(uintptr_t)) {
5963 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5964 if (AsciiRangeMask(w, lo, hi) != 0) {
5965 changed = true;
5966 break;
5967 }
5968 *reinterpret_cast<uintptr_t*>(dst) = w;
5969 src += sizeof(uintptr_t);
5970 dst += sizeof(uintptr_t);
5971 }
5972 // Process the remainder of the input performing conversion when
5973 // required one word at a time.
5974 while (src <= limit - sizeof(uintptr_t)) {
5975 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5976 uintptr_t m = AsciiRangeMask(w, lo, hi);
5977 // The mask has high (7th) bit set in every byte that needs
5978 // conversion and we know that the distance between cases is
5979 // 1 << 5.
5980 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5981 src += sizeof(uintptr_t);
5982 dst += sizeof(uintptr_t);
5983 }
5984#endif
5985 // Process the last few bytes of the input (or the whole input if
5986 // unaligned access is not supported).
5987 while (src < limit) {
5988 char c = *src;
5989 if (lo < c && c < hi) {
5990 c ^= (1 << 5);
5991 changed = true;
5992 }
5993 *dst = c;
5994 ++src;
5995 ++dst;
5996 }
5997#ifdef DEBUG
5998 CheckConvert(saved_dst, saved_src, length, changed);
5999#endif
6000 return changed;
6001 }
6002
6003#ifdef DEBUG
6004 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6005 bool expected_changed = false;
6006 for (int i = 0; i < length; i++) {
6007 if (dst[i] == src[i]) continue;
6008 expected_changed = true;
6009 if (dir == ASCII_TO_LOWER) {
6010 ASSERT('A' <= src[i] && src[i] <= 'Z');
6011 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6012 } else {
6013 ASSERT(dir == ASCII_TO_UPPER);
6014 ASSERT('a' <= src[i] && src[i] <= 'z');
6015 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6016 }
6017 }
6018 ASSERT(expected_changed == changed);
6019 }
6020#endif
6021};
6022
6023
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006024struct ToLowerTraits {
6025 typedef unibrow::ToLowercase UnibrowConverter;
6026
lrn@chromium.org303ada72010-10-27 09:33:13 +00006027 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006028};
6029
6030
6031struct ToUpperTraits {
6032 typedef unibrow::ToUppercase UnibrowConverter;
6033
lrn@chromium.org303ada72010-10-27 09:33:13 +00006034 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006035};
6036
6037} // namespace
6038
6039
6040template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006041MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006042 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006043 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006044 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006045 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006046 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006047 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006048
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006049 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006050 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006051 if (length == 0) return s;
6052
6053 // Simpler handling of ascii strings.
6054 //
6055 // NOTE: This assumes that the upper/lower case of an ascii
6056 // character is also ascii. This is currently the case, but it
6057 // might break in the future if we implement more context and locale
6058 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006059 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006060 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006061 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006062 if (!maybe_o->ToObject(&o)) return maybe_o;
6063 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006064 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006065 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006066 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006067 return has_changed_character ? result : s;
6068 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006069
lrn@chromium.org303ada72010-10-27 09:33:13 +00006070 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006071 { MaybeObject* maybe_answer =
6072 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006073 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6074 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006075 if (answer->IsSmi()) {
6076 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006077 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006078 ConvertCaseHelper(isolate,
6079 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006080 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6081 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006082 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006083 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006084}
6085
6086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006087RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006088 return ConvertCase<ToLowerTraits>(
6089 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006090}
6091
6092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006093RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006094 return ConvertCase<ToUpperTraits>(
6095 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006096}
6097
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006098
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006099static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
6100 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
6101}
6102
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006104RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006105 NoHandleAllocation ha;
6106 ASSERT(args.length() == 3);
6107
6108 CONVERT_CHECKED(String, s, args[0]);
6109 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6110 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6111
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006112 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006113 int length = s->length();
6114
6115 int left = 0;
6116 if (trimLeft) {
6117 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6118 left++;
6119 }
6120 }
6121
6122 int right = length;
6123 if (trimRight) {
6124 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6125 right--;
6126 }
6127 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006128 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006129}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006130
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006132RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006133 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006134 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006135 CONVERT_ARG_CHECKED(String, subject, 0);
6136 CONVERT_ARG_CHECKED(String, pattern, 1);
6137 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6138
6139 int subject_length = subject->length();
6140 int pattern_length = pattern->length();
6141 RUNTIME_ASSERT(pattern_length > 0);
6142
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006143 if (limit == 0xffffffffu) {
6144 Handle<Object> cached_answer(StringSplitCache::Lookup(
6145 isolate->heap()->string_split_cache(),
6146 *subject,
6147 *pattern));
6148 if (*cached_answer != Smi::FromInt(0)) {
6149 Handle<JSArray> result =
6150 isolate->factory()->NewJSArrayWithElements(
6151 Handle<FixedArray>::cast(cached_answer));
6152 return *result;
6153 }
6154 }
6155
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006156 // The limit can be very large (0xffffffffu), but since the pattern
6157 // isn't empty, we can never create more parts than ~half the length
6158 // of the subject.
6159
6160 if (!subject->IsFlat()) FlattenString(subject);
6161
6162 static const int kMaxInitialListCapacity = 16;
6163
danno@chromium.org40cb8782011-05-25 07:58:50 +00006164 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006165
6166 // Find (up to limit) indices of separator and end-of-string in subject
6167 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6168 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006169 if (!pattern->IsFlat()) FlattenString(pattern);
6170
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006171 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006172
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006173 if (static_cast<uint32_t>(indices.length()) < limit) {
6174 indices.Add(subject_length);
6175 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006176
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006177 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006178
6179 // Create JSArray of substrings separated by separator.
6180 int part_count = indices.length();
6181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006182 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006183 result->set_length(Smi::FromInt(part_count));
6184
6185 ASSERT(result->HasFastElements());
6186
6187 if (part_count == 1 && indices.at(0) == subject_length) {
6188 FixedArray::cast(result->elements())->set(0, *subject);
6189 return *result;
6190 }
6191
6192 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6193 int part_start = 0;
6194 for (int i = 0; i < part_count; i++) {
6195 HandleScope local_loop_handle;
6196 int part_end = indices.at(i);
6197 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006198 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006199 elements->set(i, *substring);
6200 part_start = part_end + pattern_length;
6201 }
6202
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006203 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006204 if (result->HasFastElements()) {
6205 StringSplitCache::Enter(isolate->heap(),
6206 isolate->heap()->string_split_cache(),
6207 *subject,
6208 *pattern,
6209 *elements);
6210 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006211 }
6212
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006213 return *result;
6214}
6215
6216
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006217// Copies ascii characters to the given fixed array looking up
6218// one-char strings in the cache. Gives up on the first char that is
6219// not in the cache and fills the remainder with smi zeros. Returns
6220// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006221static int CopyCachedAsciiCharsToArray(Heap* heap,
6222 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223 FixedArray* elements,
6224 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006225 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006226 FixedArray* ascii_cache = heap->single_character_string_cache();
6227 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006228 int i;
6229 for (i = 0; i < length; ++i) {
6230 Object* value = ascii_cache->get(chars[i]);
6231 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006232 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006233 elements->set(i, value, SKIP_WRITE_BARRIER);
6234 }
6235 if (i < length) {
6236 ASSERT(Smi::FromInt(0) == 0);
6237 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6238 }
6239#ifdef DEBUG
6240 for (int j = 0; j < length; ++j) {
6241 Object* element = elements->get(j);
6242 ASSERT(element == Smi::FromInt(0) ||
6243 (element->IsString() && String::cast(element)->LooksValid()));
6244 }
6245#endif
6246 return i;
6247}
6248
6249
6250// Converts a String to JSArray.
6251// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006252RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006253 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006254 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006255 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006256 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006257
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006258 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006259 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006260
6261 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006262 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006263 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006264 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006265 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 { MaybeObject* maybe_obj =
6267 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006268 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6269 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006270 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006271 String::FlatContent content = s->GetFlatContent();
6272 if (content.IsAscii()) {
6273 Vector<const char> chars = content.ToAsciiVector();
6274 // Note, this will initialize all elements (not only the prefix)
6275 // to prevent GC from seeing partially initialized array.
6276 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6277 chars.start(),
6278 *elements,
6279 length);
6280 } else {
6281 MemsetPointer(elements->data_start(),
6282 isolate->heap()->undefined_value(),
6283 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006284 }
6285 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006286 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006287 }
6288 for (int i = position; i < length; ++i) {
6289 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6290 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006291 }
6292
6293#ifdef DEBUG
6294 for (int i = 0; i < length; ++i) {
6295 ASSERT(String::cast(elements->get(i))->length() == 1);
6296 }
6297#endif
6298
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006299 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006300}
6301
6302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006303RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006304 NoHandleAllocation ha;
6305 ASSERT(args.length() == 1);
6306 CONVERT_CHECKED(String, value, args[0]);
6307 return value->ToObject();
6308}
6309
6310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006312 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006313 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006314 return char_length == 0;
6315}
6316
6317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006318RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006319 NoHandleAllocation ha;
6320 ASSERT(args.length() == 1);
6321
6322 Object* number = args[0];
6323 RUNTIME_ASSERT(number->IsNumber());
6324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006325 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006326}
6327
6328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006329RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006330 NoHandleAllocation ha;
6331 ASSERT(args.length() == 1);
6332
6333 Object* number = args[0];
6334 RUNTIME_ASSERT(number->IsNumber());
6335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006336 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006337}
6338
6339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006340RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006341 NoHandleAllocation ha;
6342 ASSERT(args.length() == 1);
6343
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006344 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006345
6346 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6347 if (number > 0 && number <= Smi::kMaxValue) {
6348 return Smi::FromInt(static_cast<int>(number));
6349 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006350 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006351}
6352
6353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006354RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006355 NoHandleAllocation ha;
6356 ASSERT(args.length() == 1);
6357
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006358 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006359
6360 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6361 if (number > 0 && number <= Smi::kMaxValue) {
6362 return Smi::FromInt(static_cast<int>(number));
6363 }
6364
6365 double double_value = DoubleToInteger(number);
6366 // Map both -0 and +0 to +0.
6367 if (double_value == 0) double_value = 0;
6368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006370}
6371
6372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006373RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006374 NoHandleAllocation ha;
6375 ASSERT(args.length() == 1);
6376
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006377 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006378 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006379}
6380
6381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006382RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006383 NoHandleAllocation ha;
6384 ASSERT(args.length() == 1);
6385
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006386 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006387
6388 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6389 if (number > 0 && number <= Smi::kMaxValue) {
6390 return Smi::FromInt(static_cast<int>(number));
6391 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006392 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006393}
6394
6395
ager@chromium.org870a0b62008-11-04 11:43:05 +00006396// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6397// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006398RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006399 NoHandleAllocation ha;
6400 ASSERT(args.length() == 1);
6401
6402 Object* obj = args[0];
6403 if (obj->IsSmi()) {
6404 return obj;
6405 }
6406 if (obj->IsHeapNumber()) {
6407 double value = HeapNumber::cast(obj)->value();
6408 int int_value = FastD2I(value);
6409 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6410 return Smi::FromInt(int_value);
6411 }
6412 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006413 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006414}
6415
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006417RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006418 NoHandleAllocation ha;
6419 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006421}
6422
6423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006424RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006425 NoHandleAllocation ha;
6426 ASSERT(args.length() == 2);
6427
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006428 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6429 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006431}
6432
6433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006434RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006435 NoHandleAllocation ha;
6436 ASSERT(args.length() == 2);
6437
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006438 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6439 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006440 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441}
6442
6443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006444RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006445 NoHandleAllocation ha;
6446 ASSERT(args.length() == 2);
6447
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006448 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6449 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006450 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451}
6452
6453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006454RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006455 NoHandleAllocation ha;
6456 ASSERT(args.length() == 1);
6457
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006458 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460}
6461
6462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006463RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 0);
6466
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006467 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006468}
6469
6470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006471RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006472 NoHandleAllocation ha;
6473 ASSERT(args.length() == 2);
6474
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006475 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6476 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006477 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006478}
6479
6480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006481RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006482 NoHandleAllocation ha;
6483 ASSERT(args.length() == 2);
6484
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006485 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6486 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006487
ager@chromium.org3811b432009-10-28 14:53:37 +00006488 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006489 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006490 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006491}
6492
6493
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006494RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006495 NoHandleAllocation ha;
6496 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006497 CONVERT_CHECKED(String, str1, args[0]);
6498 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 isolate->counters()->string_add_runtime()->Increment();
6500 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006501}
6502
6503
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006504template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006505static inline void StringBuilderConcatHelper(String* special,
6506 sinkchar* sink,
6507 FixedArray* fixed_array,
6508 int array_length) {
6509 int position = 0;
6510 for (int i = 0; i < array_length; i++) {
6511 Object* element = fixed_array->get(i);
6512 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006513 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006514 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006515 int pos;
6516 int len;
6517 if (encoded_slice > 0) {
6518 // Position and length encoded in one smi.
6519 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6520 len = StringBuilderSubstringLength::decode(encoded_slice);
6521 } else {
6522 // Position and length encoded in two smis.
6523 Object* obj = fixed_array->get(++i);
6524 ASSERT(obj->IsSmi());
6525 pos = Smi::cast(obj)->value();
6526 len = -encoded_slice;
6527 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006528 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006529 sink + position,
6530 pos,
6531 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006532 position += len;
6533 } else {
6534 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006535 int element_length = string->length();
6536 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006537 position += element_length;
6538 }
6539 }
6540}
6541
6542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006543RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006545 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006547 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006548 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006549 return Failure::OutOfMemoryException();
6550 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006551 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006552 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006553
6554 // This assumption is used by the slice encoding in one or two smis.
6555 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6556
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006557 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560 }
6561 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006562 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565
6566 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568 } else if (array_length == 1) {
6569 Object* first = fixed_array->get(0);
6570 if (first->IsString()) return first;
6571 }
6572
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006573 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006574 int position = 0;
6575 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006576 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577 Object* elt = fixed_array->get(i);
6578 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006579 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006580 int smi_value = Smi::cast(elt)->value();
6581 int pos;
6582 int len;
6583 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006584 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006585 pos = StringBuilderSubstringPosition::decode(smi_value);
6586 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006587 } else {
6588 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006589 len = -smi_value;
6590 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006591 i++;
6592 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006593 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006594 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006595 Object* next_smi = fixed_array->get(i);
6596 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006597 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006598 }
6599 pos = Smi::cast(next_smi)->value();
6600 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006601 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006602 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006604 ASSERT(pos >= 0);
6605 ASSERT(len >= 0);
6606 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006607 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006608 }
6609 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 } else if (elt->IsString()) {
6611 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006612 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006613 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006614 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006616 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006618 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006620 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006621 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006622 return Failure::OutOfMemoryException();
6623 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006624 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625 }
6626
6627 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006628 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006629
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006631 { MaybeObject* maybe_object =
6632 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006633 if (!maybe_object->ToObject(&object)) return maybe_object;
6634 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006635 SeqAsciiString* answer = SeqAsciiString::cast(object);
6636 StringBuilderConcatHelper(special,
6637 answer->GetChars(),
6638 fixed_array,
6639 array_length);
6640 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006642 { MaybeObject* maybe_object =
6643 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006644 if (!maybe_object->ToObject(&object)) return maybe_object;
6645 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006646 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6647 StringBuilderConcatHelper(special,
6648 answer->GetChars(),
6649 fixed_array,
6650 array_length);
6651 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653}
6654
6655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006656RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006657 NoHandleAllocation ha;
6658 ASSERT(args.length() == 3);
6659 CONVERT_CHECKED(JSArray, array, args[0]);
6660 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006661 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006662 return Failure::OutOfMemoryException();
6663 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006664 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006665 CONVERT_CHECKED(String, separator, args[2]);
6666
6667 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006668 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006669 }
6670 FixedArray* fixed_array = FixedArray::cast(array->elements());
6671 if (fixed_array->length() < array_length) {
6672 array_length = fixed_array->length();
6673 }
6674
6675 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006676 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006677 } else if (array_length == 1) {
6678 Object* first = fixed_array->get(0);
6679 if (first->IsString()) return first;
6680 }
6681
6682 int separator_length = separator->length();
6683 int max_nof_separators =
6684 (String::kMaxLength + separator_length - 1) / separator_length;
6685 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006686 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006687 return Failure::OutOfMemoryException();
6688 }
6689 int length = (array_length - 1) * separator_length;
6690 for (int i = 0; i < array_length; i++) {
6691 Object* element_obj = fixed_array->get(i);
6692 if (!element_obj->IsString()) {
6693 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006694 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006695 }
6696 String* element = String::cast(element_obj);
6697 int increment = element->length();
6698 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006699 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006700 return Failure::OutOfMemoryException();
6701 }
6702 length += increment;
6703 }
6704
6705 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006706 { MaybeObject* maybe_object =
6707 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006708 if (!maybe_object->ToObject(&object)) return maybe_object;
6709 }
6710 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6711
6712 uc16* sink = answer->GetChars();
6713#ifdef DEBUG
6714 uc16* end = sink + length;
6715#endif
6716
6717 String* first = String::cast(fixed_array->get(0));
6718 int first_length = first->length();
6719 String::WriteToFlat(first, sink, 0, first_length);
6720 sink += first_length;
6721
6722 for (int i = 1; i < array_length; i++) {
6723 ASSERT(sink + separator_length <= end);
6724 String::WriteToFlat(separator, sink, 0, separator_length);
6725 sink += separator_length;
6726
6727 String* element = String::cast(fixed_array->get(i));
6728 int element_length = element->length();
6729 ASSERT(sink + element_length <= end);
6730 String::WriteToFlat(element, sink, 0, element_length);
6731 sink += element_length;
6732 }
6733 ASSERT(sink == end);
6734
6735 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6736 return answer;
6737}
6738
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006739template <typename Char>
6740static void JoinSparseArrayWithSeparator(FixedArray* elements,
6741 int elements_length,
6742 uint32_t array_length,
6743 String* separator,
6744 Vector<Char> buffer) {
6745 int previous_separator_position = 0;
6746 int separator_length = separator->length();
6747 int cursor = 0;
6748 for (int i = 0; i < elements_length; i += 2) {
6749 int position = NumberToInt32(elements->get(i));
6750 String* string = String::cast(elements->get(i + 1));
6751 int string_length = string->length();
6752 if (string->length() > 0) {
6753 while (previous_separator_position < position) {
6754 String::WriteToFlat<Char>(separator, &buffer[cursor],
6755 0, separator_length);
6756 cursor += separator_length;
6757 previous_separator_position++;
6758 }
6759 String::WriteToFlat<Char>(string, &buffer[cursor],
6760 0, string_length);
6761 cursor += string->length();
6762 }
6763 }
6764 if (separator_length > 0) {
6765 // Array length must be representable as a signed 32-bit number,
6766 // otherwise the total string length would have been too large.
6767 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6768 int last_array_index = static_cast<int>(array_length - 1);
6769 while (previous_separator_position < last_array_index) {
6770 String::WriteToFlat<Char>(separator, &buffer[cursor],
6771 0, separator_length);
6772 cursor += separator_length;
6773 previous_separator_position++;
6774 }
6775 }
6776 ASSERT(cursor <= buffer.length());
6777}
6778
6779
6780RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6781 NoHandleAllocation ha;
6782 ASSERT(args.length() == 3);
6783 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6784 RUNTIME_ASSERT(elements_array->HasFastElements());
6785 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6786 CONVERT_CHECKED(String, separator, args[2]);
6787 // elements_array is fast-mode JSarray of alternating positions
6788 // (increasing order) and strings.
6789 // array_length is length of original array (used to add separators);
6790 // separator is string to put between elements. Assumed to be non-empty.
6791
6792 // Find total length of join result.
6793 int string_length = 0;
6794 bool is_ascii = true;
6795 int max_string_length = SeqAsciiString::kMaxLength;
6796 bool overflow = false;
6797 CONVERT_NUMBER_CHECKED(int, elements_length,
6798 Int32, elements_array->length());
6799 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6800 FixedArray* elements = FixedArray::cast(elements_array->elements());
6801 for (int i = 0; i < elements_length; i += 2) {
6802 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6803 CONVERT_CHECKED(String, string, elements->get(i + 1));
6804 int length = string->length();
6805 if (is_ascii && !string->IsAsciiRepresentation()) {
6806 is_ascii = false;
6807 max_string_length = SeqTwoByteString::kMaxLength;
6808 }
6809 if (length > max_string_length ||
6810 max_string_length - length < string_length) {
6811 overflow = true;
6812 break;
6813 }
6814 string_length += length;
6815 }
6816 int separator_length = separator->length();
6817 if (!overflow && separator_length > 0) {
6818 if (array_length <= 0x7fffffffu) {
6819 int separator_count = static_cast<int>(array_length) - 1;
6820 int remaining_length = max_string_length - string_length;
6821 if ((remaining_length / separator_length) >= separator_count) {
6822 string_length += separator_length * (array_length - 1);
6823 } else {
6824 // Not room for the separators within the maximal string length.
6825 overflow = true;
6826 }
6827 } else {
6828 // Nonempty separator and at least 2^31-1 separators necessary
6829 // means that the string is too large to create.
6830 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6831 overflow = true;
6832 }
6833 }
6834 if (overflow) {
6835 // Throw OutOfMemory exception for creating too large a string.
6836 V8::FatalProcessOutOfMemory("Array join result too large.");
6837 }
6838
6839 if (is_ascii) {
6840 MaybeObject* result_allocation =
6841 isolate->heap()->AllocateRawAsciiString(string_length);
6842 if (result_allocation->IsFailure()) return result_allocation;
6843 SeqAsciiString* result_string =
6844 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6845 JoinSparseArrayWithSeparator<char>(elements,
6846 elements_length,
6847 array_length,
6848 separator,
6849 Vector<char>(result_string->GetChars(),
6850 string_length));
6851 return result_string;
6852 } else {
6853 MaybeObject* result_allocation =
6854 isolate->heap()->AllocateRawTwoByteString(string_length);
6855 if (result_allocation->IsFailure()) return result_allocation;
6856 SeqTwoByteString* result_string =
6857 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6858 JoinSparseArrayWithSeparator<uc16>(elements,
6859 elements_length,
6860 array_length,
6861 separator,
6862 Vector<uc16>(result_string->GetChars(),
6863 string_length));
6864 return result_string;
6865 }
6866}
6867
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006869RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870 NoHandleAllocation ha;
6871 ASSERT(args.length() == 2);
6872
6873 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6874 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006875 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006876}
6877
6878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006879RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880 NoHandleAllocation ha;
6881 ASSERT(args.length() == 2);
6882
6883 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6884 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006885 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006886}
6887
6888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006889RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006890 NoHandleAllocation ha;
6891 ASSERT(args.length() == 2);
6892
6893 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6894 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006895 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006896}
6897
6898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006899RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006900 NoHandleAllocation ha;
6901 ASSERT(args.length() == 1);
6902
6903 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006904 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006905}
6906
6907
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006908RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006909 NoHandleAllocation ha;
6910 ASSERT(args.length() == 2);
6911
6912 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6913 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006914 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006915}
6916
6917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006918RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006919 NoHandleAllocation ha;
6920 ASSERT(args.length() == 2);
6921
6922 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6923 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006924 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006925}
6926
6927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006928RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006929 NoHandleAllocation ha;
6930 ASSERT(args.length() == 2);
6931
6932 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6933 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006934 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006935}
6936
6937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006938RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939 NoHandleAllocation ha;
6940 ASSERT(args.length() == 2);
6941
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006942 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6943 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006944 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6945 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6946 if (x == y) return Smi::FromInt(EQUAL);
6947 Object* result;
6948 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6949 result = Smi::FromInt(EQUAL);
6950 } else {
6951 result = Smi::FromInt(NOT_EQUAL);
6952 }
6953 return result;
6954}
6955
6956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006957RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006958 NoHandleAllocation ha;
6959 ASSERT(args.length() == 2);
6960
6961 CONVERT_CHECKED(String, x, args[0]);
6962 CONVERT_CHECKED(String, y, args[1]);
6963
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006964 bool not_equal = !x->Equals(y);
6965 // This is slightly convoluted because the value that signifies
6966 // equality is 0 and inequality is 1 so we have to negate the result
6967 // from String::Equals.
6968 ASSERT(not_equal == 0 || not_equal == 1);
6969 STATIC_CHECK(EQUAL == 0);
6970 STATIC_CHECK(NOT_EQUAL == 1);
6971 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006972}
6973
6974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006975RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006976 NoHandleAllocation ha;
6977 ASSERT(args.length() == 3);
6978
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006979 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6980 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981 if (isnan(x) || isnan(y)) return args[2];
6982 if (x == y) return Smi::FromInt(EQUAL);
6983 if (isless(x, y)) return Smi::FromInt(LESS);
6984 return Smi::FromInt(GREATER);
6985}
6986
6987
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006988// Compare two Smis as if they were converted to strings and then
6989// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006990RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006991 NoHandleAllocation ha;
6992 ASSERT(args.length() == 2);
6993
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006994 // Extract the integer values from the Smis.
6995 CONVERT_CHECKED(Smi, x, args[0]);
6996 CONVERT_CHECKED(Smi, y, args[1]);
6997 int x_value = x->value();
6998 int y_value = y->value();
6999
7000 // If the integers are equal so are the string representations.
7001 if (x_value == y_value) return Smi::FromInt(EQUAL);
7002
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007003 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007004 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007005 if (x_value == 0 || y_value == 0)
7006 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007007
ager@chromium.org32912102009-01-16 10:38:43 +00007008 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007009 // smallest because the char code of '-' is less than the char code
7010 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007011
7012 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7013 // architectures using 32-bit Smis.
7014 uint32_t x_scaled = x_value;
7015 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007016 if (x_value < 0 || y_value < 0) {
7017 if (y_value >= 0) return Smi::FromInt(LESS);
7018 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007019 x_scaled = -x_value;
7020 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007021 }
7022
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007023 static const uint32_t kPowersOf10[] = {
7024 1, 10, 100, 1000, 10*1000, 100*1000,
7025 1000*1000, 10*1000*1000, 100*1000*1000,
7026 1000*1000*1000
7027 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007028
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007029 // If the integers have the same number of decimal digits they can be
7030 // compared directly as the numeric order is the same as the
7031 // lexicographic order. If one integer has fewer digits, it is scaled
7032 // by some power of 10 to have the same number of digits as the longer
7033 // integer. If the scaled integers are equal it means the shorter
7034 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007035
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007036 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7037 int x_log2 = IntegerLog2(x_scaled);
7038 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7039 x_log10 -= x_scaled < kPowersOf10[x_log10];
7040
7041 int y_log2 = IntegerLog2(y_scaled);
7042 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7043 y_log10 -= y_scaled < kPowersOf10[y_log10];
7044
7045 int tie = EQUAL;
7046
7047 if (x_log10 < y_log10) {
7048 // X has fewer digits. We would like to simply scale up X but that
7049 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7050 // be scaled up to 9_000_000_000. So we scale up by the next
7051 // smallest power and scale down Y to drop one digit. It is OK to
7052 // drop one digit from the longer integer since the final digit is
7053 // past the length of the shorter integer.
7054 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7055 y_scaled /= 10;
7056 tie = LESS;
7057 } else if (y_log10 < x_log10) {
7058 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7059 x_scaled /= 10;
7060 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007061 }
7062
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007063 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7064 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7065 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007066}
7067
7068
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007069static Object* StringInputBufferCompare(RuntimeState* state,
7070 String* x,
7071 String* y) {
7072 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7073 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007074 bufx.Reset(x);
7075 bufy.Reset(y);
7076 while (bufx.has_more() && bufy.has_more()) {
7077 int d = bufx.GetNext() - bufy.GetNext();
7078 if (d < 0) return Smi::FromInt(LESS);
7079 else if (d > 0) return Smi::FromInt(GREATER);
7080 }
7081
7082 // x is (non-trivial) prefix of y:
7083 if (bufy.has_more()) return Smi::FromInt(LESS);
7084 // y is prefix of x:
7085 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7086}
7087
7088
7089static Object* FlatStringCompare(String* x, String* y) {
7090 ASSERT(x->IsFlat());
7091 ASSERT(y->IsFlat());
7092 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7093 int prefix_length = x->length();
7094 if (y->length() < prefix_length) {
7095 prefix_length = y->length();
7096 equal_prefix_result = Smi::FromInt(GREATER);
7097 } else if (y->length() > prefix_length) {
7098 equal_prefix_result = Smi::FromInt(LESS);
7099 }
7100 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007101 String::FlatContent x_content = x->GetFlatContent();
7102 String::FlatContent y_content = y->GetFlatContent();
7103 if (x_content.IsAscii()) {
7104 Vector<const char> x_chars = x_content.ToAsciiVector();
7105 if (y_content.IsAscii()) {
7106 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007107 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007108 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007109 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007110 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7111 }
7112 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007113 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7114 if (y_content.IsAscii()) {
7115 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007116 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7117 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007118 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007119 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7120 }
7121 }
7122 Object* result;
7123 if (r == 0) {
7124 result = equal_prefix_result;
7125 } else {
7126 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7127 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007128 ASSERT(result ==
7129 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007130 return result;
7131}
7132
7133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007134RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007135 NoHandleAllocation ha;
7136 ASSERT(args.length() == 2);
7137
7138 CONVERT_CHECKED(String, x, args[0]);
7139 CONVERT_CHECKED(String, y, args[1]);
7140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007141 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 // A few fast case tests before we flatten.
7144 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007145 if (y->length() == 0) {
7146 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007147 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007148 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007149 return Smi::FromInt(LESS);
7150 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007151
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007152 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007153 if (d < 0) return Smi::FromInt(LESS);
7154 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007155
lrn@chromium.org303ada72010-10-27 09:33:13 +00007156 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007157 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007158 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7159 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007160 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007161 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007163
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007164 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007165 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007166}
7167
7168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007169RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007170 NoHandleAllocation ha;
7171 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007172 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007174 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007175 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007176}
7177
7178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007179RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007180 NoHandleAllocation ha;
7181 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007182 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007183
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007184 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007186}
7187
7188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007189RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007190 NoHandleAllocation ha;
7191 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007192 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007193
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007194 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007195 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007196}
7197
7198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007199static const double kPiDividedBy4 = 0.78539816339744830962;
7200
7201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007202RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007203 NoHandleAllocation ha;
7204 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007205 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007206
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007207 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7208 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007209 double result;
7210 if (isinf(x) && isinf(y)) {
7211 // Make sure that the result in case of two infinite arguments
7212 // is a multiple of Pi / 4. The sign of the result is determined
7213 // by the first argument (x) and the sign of the second argument
7214 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007215 int multiplier = (x < 0) ? -1 : 1;
7216 if (y < 0) multiplier *= 3;
7217 result = multiplier * kPiDividedBy4;
7218 } else {
7219 result = atan2(x, y);
7220 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007221 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007222}
7223
7224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007225RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007226 NoHandleAllocation ha;
7227 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007228 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007229
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007230 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007231 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007232}
7233
7234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007235RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007236 NoHandleAllocation ha;
7237 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007238 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007240 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007241 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007242}
7243
7244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007245RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007246 NoHandleAllocation ha;
7247 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007248 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007249
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007250 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007251 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007252}
7253
7254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007255RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007256 NoHandleAllocation ha;
7257 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007258 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007259
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007260 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007261 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007262}
7263
7264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007265RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007266 NoHandleAllocation ha;
7267 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007268 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007269
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007270 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007271 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272}
7273
7274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007275RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 NoHandleAllocation ha;
7277 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007278 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007279
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007280 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007281
7282 // If the second argument is a smi, it is much faster to call the
7283 // custom powi() function than the generic pow().
7284 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007285 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007287 }
7288
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007289 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007290 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007291}
7292
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007293// Fast version of Math.pow if we know that y is not an integer and
7294// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007295RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007296 NoHandleAllocation ha;
7297 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007298 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7299 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007300 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007301 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007302 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007303 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007304 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007305 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007306 }
7307}
7308
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007310RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311 NoHandleAllocation ha;
7312 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007315 if (!args[0]->IsHeapNumber()) {
7316 // Must be smi. Return the argument unchanged for all the other types
7317 // to make fuzz-natives test happy.
7318 return args[0];
7319 }
7320
7321 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7322
7323 double value = number->value();
7324 int exponent = number->get_exponent();
7325 int sign = number->get_sign();
7326
danno@chromium.org160a7b02011-04-18 15:51:38 +00007327 if (exponent < -1) {
7328 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7329 if (sign) return isolate->heap()->minus_zero_value();
7330 return Smi::FromInt(0);
7331 }
7332
7333 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7334 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7335 // agument holds for 32-bit smis).
7336 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007337 return Smi::FromInt(static_cast<int>(value + 0.5));
7338 }
7339
7340 // If the magnitude is big enough, there's no place for fraction part. If we
7341 // try to add 0.5 to this number, 1.0 will be added instead.
7342 if (exponent >= 52) {
7343 return number;
7344 }
7345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007347
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007348 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007349 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350}
7351
7352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007353RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354 NoHandleAllocation ha;
7355 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007358 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360}
7361
7362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007363RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364 NoHandleAllocation ha;
7365 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007368 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370}
7371
7372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007373RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 NoHandleAllocation ha;
7375 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007378 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380}
7381
7382
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007383static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007384 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7385 181, 212, 243, 273, 304, 334};
7386 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7387 182, 213, 244, 274, 305, 335};
7388
7389 year += month / 12;
7390 month %= 12;
7391 if (month < 0) {
7392 year--;
7393 month += 12;
7394 }
7395
7396 ASSERT(month >= 0);
7397 ASSERT(month < 12);
7398
7399 // year_delta is an arbitrary number such that:
7400 // a) year_delta = -1 (mod 400)
7401 // b) year + year_delta > 0 for years in the range defined by
7402 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7403 // Jan 1 1970. This is required so that we don't run into integer
7404 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007405 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007406 // operations.
7407 static const int year_delta = 399999;
7408 static const int base_day = 365 * (1970 + year_delta) +
7409 (1970 + year_delta) / 4 -
7410 (1970 + year_delta) / 100 +
7411 (1970 + year_delta) / 400;
7412
7413 int year1 = year + year_delta;
7414 int day_from_year = 365 * year1 +
7415 year1 / 4 -
7416 year1 / 100 +
7417 year1 / 400 -
7418 base_day;
7419
7420 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007421 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007422 }
7423
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007424 return day_from_year + day_from_month_leap[month] + day - 1;
7425}
7426
7427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007428RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007429 NoHandleAllocation ha;
7430 ASSERT(args.length() == 3);
7431
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007432 CONVERT_SMI_ARG_CHECKED(year, 0);
7433 CONVERT_SMI_ARG_CHECKED(month, 1);
7434 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007435
7436 return Smi::FromInt(MakeDay(year, month, date));
7437}
7438
7439
7440static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7441static const int kDaysIn4Years = 4 * 365 + 1;
7442static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7443static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7444static const int kDays1970to2000 = 30 * 365 + 7;
7445static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7446 kDays1970to2000;
7447static const int kYearsOffset = 400000;
7448
7449static const char kDayInYear[] = {
7450 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7451 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7452 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7453 22, 23, 24, 25, 26, 27, 28,
7454 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7455 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7456 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7457 22, 23, 24, 25, 26, 27, 28, 29, 30,
7458 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7459 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7460 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7461 22, 23, 24, 25, 26, 27, 28, 29, 30,
7462 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7463 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7464 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7465 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7466 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7467 22, 23, 24, 25, 26, 27, 28, 29, 30,
7468 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7469 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7470 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7471 22, 23, 24, 25, 26, 27, 28, 29, 30,
7472 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7473 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7474
7475 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7476 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7477 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7478 22, 23, 24, 25, 26, 27, 28,
7479 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7480 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7481 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7482 22, 23, 24, 25, 26, 27, 28, 29, 30,
7483 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7484 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7485 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7486 22, 23, 24, 25, 26, 27, 28, 29, 30,
7487 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7488 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7489 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7490 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7491 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7492 22, 23, 24, 25, 26, 27, 28, 29, 30,
7493 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7494 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7495 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7496 22, 23, 24, 25, 26, 27, 28, 29, 30,
7497 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7498 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7499
7500 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7501 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7502 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7503 22, 23, 24, 25, 26, 27, 28, 29,
7504 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7505 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7506 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7507 22, 23, 24, 25, 26, 27, 28, 29, 30,
7508 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7509 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7510 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7511 22, 23, 24, 25, 26, 27, 28, 29, 30,
7512 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7513 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7514 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7515 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7516 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7517 22, 23, 24, 25, 26, 27, 28, 29, 30,
7518 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7519 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7520 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7521 22, 23, 24, 25, 26, 27, 28, 29, 30,
7522 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7523 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7524
7525 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7526 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7527 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7528 22, 23, 24, 25, 26, 27, 28,
7529 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7530 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7531 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7532 22, 23, 24, 25, 26, 27, 28, 29, 30,
7533 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7534 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7535 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7536 22, 23, 24, 25, 26, 27, 28, 29, 30,
7537 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7538 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7539 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7540 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7541 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7542 22, 23, 24, 25, 26, 27, 28, 29, 30,
7543 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7544 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7545 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7546 22, 23, 24, 25, 26, 27, 28, 29, 30,
7547 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7548 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7549
7550static const char kMonthInYear[] = {
7551 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7552 0, 0, 0, 0, 0, 0,
7553 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7554 1, 1, 1,
7555 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7556 2, 2, 2, 2, 2, 2,
7557 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7558 3, 3, 3, 3, 3,
7559 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7560 4, 4, 4, 4, 4, 4,
7561 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7562 5, 5, 5, 5, 5,
7563 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7564 6, 6, 6, 6, 6, 6,
7565 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7566 7, 7, 7, 7, 7, 7,
7567 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7568 8, 8, 8, 8, 8,
7569 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7570 9, 9, 9, 9, 9, 9,
7571 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7572 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7573 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7574 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7575
7576 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7577 0, 0, 0, 0, 0, 0,
7578 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7579 1, 1, 1,
7580 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7581 2, 2, 2, 2, 2, 2,
7582 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7583 3, 3, 3, 3, 3,
7584 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7585 4, 4, 4, 4, 4, 4,
7586 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7587 5, 5, 5, 5, 5,
7588 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7589 6, 6, 6, 6, 6, 6,
7590 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7591 7, 7, 7, 7, 7, 7,
7592 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7593 8, 8, 8, 8, 8,
7594 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7595 9, 9, 9, 9, 9, 9,
7596 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7597 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7598 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7599 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7600
7601 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7602 0, 0, 0, 0, 0, 0,
7603 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7604 1, 1, 1, 1,
7605 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7606 2, 2, 2, 2, 2, 2,
7607 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7608 3, 3, 3, 3, 3,
7609 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7610 4, 4, 4, 4, 4, 4,
7611 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7612 5, 5, 5, 5, 5,
7613 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7614 6, 6, 6, 6, 6, 6,
7615 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7616 7, 7, 7, 7, 7, 7,
7617 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7618 8, 8, 8, 8, 8,
7619 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7620 9, 9, 9, 9, 9, 9,
7621 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7622 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7623 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7624 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7625
7626 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7627 0, 0, 0, 0, 0, 0,
7628 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7629 1, 1, 1,
7630 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7631 2, 2, 2, 2, 2, 2,
7632 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7633 3, 3, 3, 3, 3,
7634 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7635 4, 4, 4, 4, 4, 4,
7636 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7637 5, 5, 5, 5, 5,
7638 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7639 6, 6, 6, 6, 6, 6,
7640 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7641 7, 7, 7, 7, 7, 7,
7642 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7643 8, 8, 8, 8, 8,
7644 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7645 9, 9, 9, 9, 9, 9,
7646 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7647 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7648 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7649 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7650
7651
7652// This function works for dates from 1970 to 2099.
7653static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007654 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007655#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007656 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007657#endif
7658
7659 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7660 date %= kDaysIn4Years;
7661
7662 month = kMonthInYear[date];
7663 day = kDayInYear[date];
7664
7665 ASSERT(MakeDay(year, month, day) == save_date);
7666}
7667
7668
7669static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007670 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007671#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007672 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007673#endif
7674
7675 date += kDaysOffset;
7676 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7677 date %= kDaysIn400Years;
7678
7679 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7680
7681 date--;
7682 int yd1 = date / kDaysIn100Years;
7683 date %= kDaysIn100Years;
7684 year += 100 * yd1;
7685
7686 date++;
7687 int yd2 = date / kDaysIn4Years;
7688 date %= kDaysIn4Years;
7689 year += 4 * yd2;
7690
7691 date--;
7692 int yd3 = date / 365;
7693 date %= 365;
7694 year += yd3;
7695
7696 bool is_leap = (!yd1 || yd2) && !yd3;
7697
7698 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007699 ASSERT(is_leap || (date >= 0));
7700 ASSERT((date < 365) || (is_leap && (date < 366)));
7701 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7702 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7703 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007704
7705 if (is_leap) {
7706 day = kDayInYear[2*365 + 1 + date];
7707 month = kMonthInYear[2*365 + 1 + date];
7708 } else {
7709 day = kDayInYear[date];
7710 month = kMonthInYear[date];
7711 }
7712
7713 ASSERT(MakeDay(year, month, day) == save_date);
7714}
7715
7716
7717static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007718 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007719 if (date >= 0 && date < 32 * kDaysIn4Years) {
7720 DateYMDFromTimeAfter1970(date, year, month, day);
7721 } else {
7722 DateYMDFromTimeSlow(date, year, month, day);
7723 }
7724}
7725
7726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007727RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007728 NoHandleAllocation ha;
7729 ASSERT(args.length() == 2);
7730
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007731 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007732 CONVERT_CHECKED(JSArray, res_array, args[1]);
7733
7734 int year, month, day;
7735 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7736
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007737 RUNTIME_ASSERT(res_array->elements()->map() ==
7738 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007739 FixedArray* elms = FixedArray::cast(res_array->elements());
7740 RUNTIME_ASSERT(elms->length() == 3);
7741
7742 elms->set(0, Smi::FromInt(year));
7743 elms->set(1, Smi::FromInt(month));
7744 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007745
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007746 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007747}
7748
7749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007750RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007751 HandleScope scope(isolate);
7752 ASSERT(args.length() == 3);
7753
7754 Handle<JSFunction> callee = args.at<JSFunction>(0);
7755 Object** parameters = reinterpret_cast<Object**>(args[1]);
7756 const int argument_count = Smi::cast(args[2])->value();
7757
7758 Handle<JSObject> result =
7759 isolate->factory()->NewArgumentsObject(callee, argument_count);
7760 // Allocate the elements if needed.
7761 int parameter_count = callee->shared()->formal_parameter_count();
7762 if (argument_count > 0) {
7763 if (parameter_count > 0) {
7764 int mapped_count = Min(argument_count, parameter_count);
7765 Handle<FixedArray> parameter_map =
7766 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7767 parameter_map->set_map(
7768 isolate->heap()->non_strict_arguments_elements_map());
7769
7770 Handle<Map> old_map(result->map());
7771 Handle<Map> new_map =
7772 isolate->factory()->CopyMapDropTransitions(old_map);
7773 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7774
7775 result->set_map(*new_map);
7776 result->set_elements(*parameter_map);
7777
7778 // Store the context and the arguments array at the beginning of the
7779 // parameter map.
7780 Handle<Context> context(isolate->context());
7781 Handle<FixedArray> arguments =
7782 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7783 parameter_map->set(0, *context);
7784 parameter_map->set(1, *arguments);
7785
7786 // Loop over the actual parameters backwards.
7787 int index = argument_count - 1;
7788 while (index >= mapped_count) {
7789 // These go directly in the arguments array and have no
7790 // corresponding slot in the parameter map.
7791 arguments->set(index, *(parameters - index - 1));
7792 --index;
7793 }
7794
7795 ScopeInfo<> scope_info(callee->shared()->scope_info());
7796 while (index >= 0) {
7797 // Detect duplicate names to the right in the parameter list.
7798 Handle<String> name = scope_info.parameter_name(index);
7799 int context_slot_count = scope_info.number_of_context_slots();
7800 bool duplicate = false;
7801 for (int j = index + 1; j < parameter_count; ++j) {
7802 if (scope_info.parameter_name(j).is_identical_to(name)) {
7803 duplicate = true;
7804 break;
7805 }
7806 }
7807
7808 if (duplicate) {
7809 // This goes directly in the arguments array with a hole in the
7810 // parameter map.
7811 arguments->set(index, *(parameters - index - 1));
7812 parameter_map->set_the_hole(index + 2);
7813 } else {
7814 // The context index goes in the parameter map with a hole in the
7815 // arguments array.
7816 int context_index = -1;
7817 for (int j = Context::MIN_CONTEXT_SLOTS;
7818 j < context_slot_count;
7819 ++j) {
7820 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7821 context_index = j;
7822 break;
7823 }
7824 }
7825 ASSERT(context_index >= 0);
7826 arguments->set_the_hole(index);
7827 parameter_map->set(index + 2, Smi::FromInt(context_index));
7828 }
7829
7830 --index;
7831 }
7832 } else {
7833 // If there is no aliasing, the arguments object elements are not
7834 // special in any way.
7835 Handle<FixedArray> elements =
7836 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7837 result->set_elements(*elements);
7838 for (int i = 0; i < argument_count; ++i) {
7839 elements->set(i, *(parameters - i - 1));
7840 }
7841 }
7842 }
7843 return *result;
7844}
7845
7846
7847RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007848 NoHandleAllocation ha;
7849 ASSERT(args.length() == 3);
7850
7851 JSFunction* callee = JSFunction::cast(args[0]);
7852 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007853 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007854
lrn@chromium.org303ada72010-10-27 09:33:13 +00007855 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007856 { MaybeObject* maybe_result =
7857 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007858 if (!maybe_result->ToObject(&result)) return maybe_result;
7859 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007860 // Allocate the elements if needed.
7861 if (length > 0) {
7862 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007863 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007864 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007865 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7866 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007867
7868 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007869 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007870 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007871 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007872
7873 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007874 for (int i = 0; i < length; i++) {
7875 array->set(i, *--parameters, mode);
7876 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007877 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007878 }
7879 return result;
7880}
7881
7882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007883RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007885 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007886 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007887 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007888 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007889
whesse@chromium.org7b260152011-06-20 15:33:18 +00007890 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007891 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007892 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007893 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007894 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7895 context,
7896 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007897 return *result;
7898}
7899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007900
7901static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7902 int* total_argc) {
7903 // Find frame containing arguments passed to the caller.
7904 JavaScriptFrameIterator it;
7905 JavaScriptFrame* frame = it.frame();
7906 List<JSFunction*> functions(2);
7907 frame->GetFunctions(&functions);
7908 if (functions.length() > 1) {
7909 int inlined_frame_index = functions.length() - 1;
7910 JSFunction* inlined_function = functions[inlined_frame_index];
7911 int args_count = inlined_function->shared()->formal_parameter_count();
7912 ScopedVector<SlotRef> args_slots(args_count);
7913 SlotRef::ComputeSlotMappingForArguments(frame,
7914 inlined_frame_index,
7915 &args_slots);
7916
7917 *total_argc = bound_argc + args_count;
7918 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7919 for (int i = 0; i < args_count; i++) {
7920 Handle<Object> val = args_slots[i].GetValue();
7921 param_data[bound_argc + i] = val.location();
7922 }
7923 return param_data;
7924 } else {
7925 it.AdvanceToArgumentsFrame();
7926 frame = it.frame();
7927 int args_count = frame->ComputeParametersCount();
7928
7929 *total_argc = bound_argc + args_count;
7930 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7931 for (int i = 0; i < args_count; i++) {
7932 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7933 param_data[bound_argc + i] = val.location();
7934 }
7935 return param_data;
7936 }
7937}
7938
7939
7940RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007941 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007942 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007943 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007944 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007945
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007946 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007947 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007948 int bound_argc = 0;
7949 if (!args[1]->IsNull()) {
7950 CONVERT_ARG_CHECKED(JSArray, params, 1);
7951 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007952 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007953 bound_argc = Smi::cast(params->length())->value();
7954 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007956 int total_argc = 0;
7957 SmartPointer<Object**> param_data =
7958 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007959 for (int i = 0; i < bound_argc; i++) {
7960 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007961 param_data[i] = val.location();
7962 }
7963
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007964 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007965 Handle<Object> result =
7966 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007967 if (exception) {
7968 return Failure::Exception();
7969 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007970
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007971 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007972 return *result;
7973}
7974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007975
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007976static void TrySettingInlineConstructStub(Isolate* isolate,
7977 Handle<JSFunction> function) {
7978 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007979 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007980 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007981 }
7982 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007983 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007984 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007985 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007986 function->shared()->set_construct_stub(
7987 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007988 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007989 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007990}
7991
7992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007993RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007994 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007995 ASSERT(args.length() == 1);
7996
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007997 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007998
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007999 // If the constructor isn't a proper function we throw a type error.
8000 if (!constructor->IsJSFunction()) {
8001 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8002 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008003 isolate->factory()->NewTypeError("not_constructor", arguments);
8004 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008005 }
8006
8007 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008008
8009 // If function should not have prototype, construction is not allowed. In this
8010 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008011 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008012 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8013 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008014 isolate->factory()->NewTypeError("not_constructor", arguments);
8015 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008016 }
8017
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008018#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008019 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008020 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008021 if (debug->StepInActive()) {
8022 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008023 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008024#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008026 if (function->has_initial_map()) {
8027 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008028 // The 'Function' function ignores the receiver object when
8029 // called using 'new' and creates a new JSFunction object that
8030 // is returned. The receiver object is only used for error
8031 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008032 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008033 // allocate JSFunctions since it does not properly initialize
8034 // the shared part of the function. Since the receiver is
8035 // ignored anyway, we use the global object as the receiver
8036 // instead of a new JSFunction object. This way, errors are
8037 // reported the same way whether or not 'Function' is called
8038 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008039 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008040 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008041 }
8042
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008043 // The function should be compiled for the optimization hints to be
8044 // available. We cannot use EnsureCompiled because that forces a
8045 // compilation through the shared function info which makes it
8046 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008047 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008048 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008049
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008050 if (!function->has_initial_map() &&
8051 shared->IsInobjectSlackTrackingInProgress()) {
8052 // The tracking is already in progress for another function. We can only
8053 // track one initial_map at a time, so we force the completion before the
8054 // function is called as a constructor for the first time.
8055 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008056 }
8057
8058 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008059 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8060 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008061 // Delay setting the stub if inobject slack tracking is in progress.
8062 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008063 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008064 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008066 isolate->counters()->constructed_objects()->Increment();
8067 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008068
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008069 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008070}
8071
8072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008073RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008074 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008075 ASSERT(args.length() == 1);
8076
8077 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8078 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008079 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008081 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008082}
8083
8084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008085RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008086 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008087 ASSERT(args.length() == 1);
8088
8089 Handle<JSFunction> function = args.at<JSFunction>(0);
8090#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008091 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008092 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008093 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094 PrintF("]\n");
8095 }
8096#endif
8097
kasperl@chromium.org71affb52009-05-26 05:44:31 +00008098 // Compile the target function. Here we compile using CompileLazyInLoop in
8099 // order to get the optimized version. This helps code like delta-blue
8100 // that calls performance-critical routines through constructors. A
8101 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
8102 // direct call. Since the in-loop tracking takes place through CallICs
8103 // this means that things called through constructors are never known to
8104 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008106 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008107 return Failure::Exception();
8108 }
8109
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008110 // All done. Return the compiled code.
8111 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008112 return function->code();
8113}
8114
8115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008116RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008117 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008118 ASSERT(args.length() == 1);
8119 Handle<JSFunction> function = args.at<JSFunction>(0);
8120 // If the function is not optimizable or debugger is active continue using the
8121 // code from the full compiler.
8122 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008123 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008124 if (FLAG_trace_opt) {
8125 PrintF("[failed to optimize ");
8126 function->PrintName();
8127 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8128 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008129 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008130 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008131 function->ReplaceCode(function->shared()->code());
8132 return function->code();
8133 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008134 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008135 return function->code();
8136 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008137 if (FLAG_trace_opt) {
8138 PrintF("[failed to optimize ");
8139 function->PrintName();
8140 PrintF(": optimized compilation failed]\n");
8141 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008142 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008143 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008144}
8145
8146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008147RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008148 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008149 ASSERT(args.length() == 1);
8150 RUNTIME_ASSERT(args[0]->IsSmi());
8151 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008152 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008153 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8154 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008155 int frames = deoptimizer->output_count();
8156
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008157 deoptimizer->MaterializeHeapNumbers();
8158 delete deoptimizer;
8159
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008160 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008161 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008162 for (int i = 0; i < frames - 1; i++) it.Advance();
8163 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008164
8165 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008166 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008167 Handle<Object> arguments;
8168 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008169 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008170 if (arguments.is_null()) {
8171 // FunctionGetArguments can't throw an exception, so cast away the
8172 // doubt with an assert.
8173 arguments = Handle<Object>(
8174 Accessors::FunctionGetArguments(*function,
8175 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008176 ASSERT(*arguments != isolate->heap()->null_value());
8177 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008178 }
8179 frame->SetExpression(i, *arguments);
8180 }
8181 }
8182
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008183 if (type == Deoptimizer::EAGER) {
8184 RUNTIME_ASSERT(function->IsOptimized());
8185 } else {
8186 RUNTIME_ASSERT(!function->IsOptimized());
8187 }
8188
8189 // Avoid doing too much work when running with --always-opt and keep
8190 // the optimized code around.
8191 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008192 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008193 }
8194
8195 // Count the number of optimized activations of the function.
8196 int activations = 0;
8197 while (!it.done()) {
8198 JavaScriptFrame* frame = it.frame();
8199 if (frame->is_optimized() && frame->function() == *function) {
8200 activations++;
8201 }
8202 it.Advance();
8203 }
8204
8205 // TODO(kasperl): For now, we cannot support removing the optimized
8206 // code when we have recursive invocations of the same function.
8207 if (activations == 0) {
8208 if (FLAG_trace_deopt) {
8209 PrintF("[removing optimized code for: ");
8210 function->PrintName();
8211 PrintF("]\n");
8212 }
8213 function->ReplaceCode(function->shared()->code());
8214 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008215 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008216}
8217
8218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008219RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008220 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008221 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008222 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008223}
8224
8225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008226RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008227 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008228 ASSERT(args.length() == 1);
8229 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008230 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008231
8232 Deoptimizer::DeoptimizeFunction(*function);
8233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008234 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008235}
8236
8237
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008238RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8239#if defined(USE_SIMULATOR)
8240 return isolate->heap()->true_value();
8241#else
8242 return isolate->heap()->false_value();
8243#endif
8244}
8245
8246
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008247RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8248 HandleScope scope(isolate);
8249 ASSERT(args.length() == 1);
8250 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8251 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8252 function->MarkForLazyRecompilation();
8253 return isolate->heap()->undefined_value();
8254}
8255
8256
lrn@chromium.org1c092762011-05-09 09:42:16 +00008257RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8258 HandleScope scope(isolate);
8259 ASSERT(args.length() == 1);
8260 if (!V8::UseCrankshaft()) {
8261 return Smi::FromInt(4); // 4 == "never".
8262 }
8263 if (FLAG_always_opt) {
8264 return Smi::FromInt(3); // 3 == "always".
8265 }
8266 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8267 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8268 : Smi::FromInt(2); // 2 == "no".
8269}
8270
8271
8272RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8273 HandleScope scope(isolate);
8274 ASSERT(args.length() == 1);
8275 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8276 return Smi::FromInt(function->shared()->opt_count());
8277}
8278
8279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008280RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008281 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008282 ASSERT(args.length() == 1);
8283 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8284
8285 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008286 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008287
8288 // We have hit a back edge in an unoptimized frame for a function that was
8289 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008290 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008291 // Keep track of whether we've succeeded in optimizing.
8292 bool succeeded = unoptimized->optimizable();
8293 if (succeeded) {
8294 // If we are trying to do OSR when there are already optimized
8295 // activations of the function, it means (a) the function is directly or
8296 // indirectly recursive and (b) an optimized invocation has been
8297 // deoptimized so that we are currently in an unoptimized activation.
8298 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008299 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008300 while (succeeded && !it.done()) {
8301 JavaScriptFrame* frame = it.frame();
8302 succeeded = !frame->is_optimized() || frame->function() != *function;
8303 it.Advance();
8304 }
8305 }
8306
8307 int ast_id = AstNode::kNoNumber;
8308 if (succeeded) {
8309 // The top JS function is this one, the PC is somewhere in the
8310 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008311 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008312 JavaScriptFrame* frame = it.frame();
8313 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008314 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008315 ASSERT(unoptimized->contains(frame->pc()));
8316
8317 // Use linear search of the unoptimized code's stack check table to find
8318 // the AST id matching the PC.
8319 Address start = unoptimized->instruction_start();
8320 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008321 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008322 uint32_t table_length = Memory::uint32_at(table_cursor);
8323 table_cursor += kIntSize;
8324 for (unsigned i = 0; i < table_length; ++i) {
8325 // Table entries are (AST id, pc offset) pairs.
8326 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8327 if (pc_offset == target_pc_offset) {
8328 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8329 break;
8330 }
8331 table_cursor += 2 * kIntSize;
8332 }
8333 ASSERT(ast_id != AstNode::kNoNumber);
8334 if (FLAG_trace_osr) {
8335 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8336 function->PrintName();
8337 PrintF("]\n");
8338 }
8339
8340 // Try to compile the optimized code. A true return value from
8341 // CompileOptimized means that compilation succeeded, not necessarily
8342 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008343 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8344 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008345 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8346 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008347 if (data->OsrPcOffset()->value() >= 0) {
8348 if (FLAG_trace_osr) {
8349 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008350 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008351 }
8352 ASSERT(data->OsrAstId()->value() == ast_id);
8353 } else {
8354 // We may never generate the desired OSR entry if we emit an
8355 // early deoptimize.
8356 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008357 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008358 } else {
8359 succeeded = false;
8360 }
8361 }
8362
8363 // Revert to the original stack checks in the original unoptimized code.
8364 if (FLAG_trace_osr) {
8365 PrintF("[restoring original stack checks in ");
8366 function->PrintName();
8367 PrintF("]\n");
8368 }
8369 StackCheckStub check_stub;
8370 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008371 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008372 Deoptimizer::RevertStackCheckCode(*unoptimized,
8373 *check_code,
8374 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008375
8376 // Allow OSR only at nesting level zero again.
8377 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8378
8379 // If the optimization attempt succeeded, return the AST id tagged as a
8380 // smi. This tells the builtin that we need to translate the unoptimized
8381 // frame to an optimized one.
8382 if (succeeded) {
8383 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8384 return Smi::FromInt(ast_id);
8385 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008386 if (function->IsMarkedForLazyRecompilation()) {
8387 function->ReplaceCode(function->shared()->code());
8388 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008389 return Smi::FromInt(-1);
8390 }
8391}
8392
8393
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008394RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8395 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8396 return isolate->heap()->undefined_value();
8397}
8398
8399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008400RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008401 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008402 ASSERT(args.length() == 1);
8403 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8404 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8405}
8406
8407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008408RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008409 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008410 ASSERT(args.length() == 1);
8411 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8412 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8413}
8414
8415
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008416RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008417 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008418 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419
kasper.lund7276f142008-07-30 08:49:36 +00008420 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008421 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008422 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008423 { MaybeObject* maybe_result =
8424 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008425 if (!maybe_result->ToObject(&result)) return maybe_result;
8426 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008428 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008429
kasper.lund7276f142008-07-30 08:49:36 +00008430 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008431}
8432
lrn@chromium.org303ada72010-10-27 09:33:13 +00008433
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008434RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8435 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008436 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008437 JSObject* extension_object;
8438 if (args[0]->IsJSObject()) {
8439 extension_object = JSObject::cast(args[0]);
8440 } else {
8441 // Convert the object to a proper JavaScript object.
8442 MaybeObject* maybe_js_object = args[0]->ToObject();
8443 if (!maybe_js_object->To(&extension_object)) {
8444 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8445 HandleScope scope(isolate);
8446 Handle<Object> handle = args.at<Object>(0);
8447 Handle<Object> result =
8448 isolate->factory()->NewTypeError("with_expression",
8449 HandleVector(&handle, 1));
8450 return isolate->Throw(*result);
8451 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008452 return maybe_js_object;
8453 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008454 }
8455 }
8456
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008457 JSFunction* function;
8458 if (args[1]->IsSmi()) {
8459 // A smi sentinel indicates a context nested inside global code rather
8460 // than some function. There is a canonical empty function that can be
8461 // gotten from the global context.
8462 function = isolate->context()->global_context()->closure();
8463 } else {
8464 function = JSFunction::cast(args[1]);
8465 }
8466
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008467 Context* context;
8468 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008469 isolate->heap()->AllocateWithContext(function,
8470 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008471 extension_object);
8472 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008473 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008474 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008475}
8476
8477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008478RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008479 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008480 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008481 String* name = String::cast(args[0]);
8482 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008483 JSFunction* function;
8484 if (args[2]->IsSmi()) {
8485 // A smi sentinel indicates a context nested inside global code rather
8486 // than some function. There is a canonical empty function that can be
8487 // gotten from the global context.
8488 function = isolate->context()->global_context()->closure();
8489 } else {
8490 function = JSFunction::cast(args[2]);
8491 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008492 Context* context;
8493 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008494 isolate->heap()->AllocateCatchContext(function,
8495 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008496 name,
8497 thrown_object);
8498 if (!maybe_context->To(&context)) return maybe_context;
8499 isolate->set_context(context);
8500 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008501}
8502
8503
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008504RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8505 NoHandleAllocation ha;
8506 ASSERT(args.length() == 2);
8507 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8508 JSFunction* function;
8509 if (args[1]->IsSmi()) {
8510 // A smi sentinel indicates a context nested inside global code rather
8511 // than some function. There is a canonical empty function that can be
8512 // gotten from the global context.
8513 function = isolate->context()->global_context()->closure();
8514 } else {
8515 function = JSFunction::cast(args[1]);
8516 }
8517 Context* context;
8518 MaybeObject* maybe_context =
8519 isolate->heap()->AllocateBlockContext(function,
8520 isolate->context(),
8521 scope_info);
8522 if (!maybe_context->To(&context)) return maybe_context;
8523 isolate->set_context(context);
8524 return context;
8525}
8526
8527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008528RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008529 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008530 ASSERT(args.length() == 2);
8531
8532 CONVERT_ARG_CHECKED(Context, context, 0);
8533 CONVERT_ARG_CHECKED(String, name, 1);
8534
8535 int index;
8536 PropertyAttributes attributes;
8537 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008538 BindingFlags binding_flags;
8539 Handle<Object> holder = context->Lookup(name,
8540 flags,
8541 &index,
8542 &attributes,
8543 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008544
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008545 // If the slot was not found the result is true.
8546 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008547 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008548 }
8549
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008550 // If the slot was found in a context, it should be DONT_DELETE.
8551 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008552 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008553 }
8554
8555 // The slot was found in a JSObject, either a context extension object,
8556 // the global object, or an arguments object. Try to delete it
8557 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8558 // which allows deleting all parameters in functions that mention
8559 // 'arguments', we do this even for the case of slots found on an
8560 // arguments object. The slot was found on an arguments object if the
8561 // index is non-negative.
8562 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8563 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008564 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008565 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008566 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008567 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008568}
8569
8570
ager@chromium.orga1645e22009-09-09 19:27:10 +00008571// A mechanism to return a pair of Object pointers in registers (if possible).
8572// How this is achieved is calling convention-dependent.
8573// All currently supported x86 compiles uses calling conventions that are cdecl
8574// variants where a 64-bit value is returned in two 32-bit registers
8575// (edx:eax on ia32, r1:r0 on ARM).
8576// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8577// In Win64 calling convention, a struct of two pointers is returned in memory,
8578// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008579#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008580struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008581 MaybeObject* x;
8582 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008583};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008584
lrn@chromium.org303ada72010-10-27 09:33:13 +00008585static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008586 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008587 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8588 // In Win64 they are assigned to a hidden first argument.
8589 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008590}
8591#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008592typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008593static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008594 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008595 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008596}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008597#endif
8598
8599
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008600static inline MaybeObject* Unhole(Heap* heap,
8601 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008602 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008603 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8604 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008605 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008606}
8607
8608
danno@chromium.org40cb8782011-05-25 07:58:50 +00008609static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8610 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008611 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008612 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008613 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008614 JSFunction* context_extension_function =
8615 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008616 // If the holder isn't a context extension object, we just return it
8617 // as the receiver. This allows arguments objects to be used as
8618 // receivers, but only if they are put in the context scope chain
8619 // explicitly via a with-statement.
8620 Object* constructor = holder->map()->constructor();
8621 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008622 // Fall back to using the global object as the implicit receiver if
8623 // the property turns out to be a local variable allocated in a
8624 // context extension object - introduced via eval. Implicit global
8625 // receivers are indicated with the hole value.
8626 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008627}
8628
8629
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008630static ObjectPair LoadContextSlotHelper(Arguments args,
8631 Isolate* isolate,
8632 bool throw_error) {
8633 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008634 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008635
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008636 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008637 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008639 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008640 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008641
8642 int index;
8643 PropertyAttributes attributes;
8644 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008645 BindingFlags binding_flags;
8646 Handle<Object> holder = context->Lookup(name,
8647 flags,
8648 &index,
8649 &attributes,
8650 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008652 // If the index is non-negative, the slot has been found in a local
8653 // variable or a parameter. Read it from the context object or the
8654 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008655 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008656 // If the "property" we were looking for is a local variable or an
8657 // argument in a context, the receiver is the global object; see
8658 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008659 //
8660 // Use the hole as the receiver to signal that the receiver is
8661 // implicit and that the global receiver should be used.
8662 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008663 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008664 ? Context::cast(*holder)->get(index)
8665 : JSObject::cast(*holder)->GetElement(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008666 // Check for uninitialized bindings.
8667 if (holder->IsContext() &&
8668 binding_flags == MUTABLE_CHECK_INITIALIZED &&
8669 value->IsTheHole()) {
8670 Handle<Object> reference_error =
8671 isolate->factory()->NewReferenceError("not_defined",
8672 HandleVector(&name, 1));
8673 return MakePair(isolate->Throw(*reference_error), NULL);
8674 } else {
8675 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8676 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008677 }
8678
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008679 // If the holder is found, we read the property from it.
8680 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008681 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008682 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008683 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008684 if (object->IsGlobalObject()) {
8685 receiver = GlobalObject::cast(object)->global_receiver();
8686 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008687 // Use the hole as the receiver to signal that the receiver is
8688 // implicit and that the global receiver should be used.
8689 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008690 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008691 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008692 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008693
8694 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008695 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008696
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008697 // No need to unhole the value here. This is taken care of by the
8698 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008699 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008700 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008701 }
8702
8703 if (throw_error) {
8704 // The property doesn't exist - throw exception.
8705 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008706 isolate->factory()->NewReferenceError("not_defined",
8707 HandleVector(&name, 1));
8708 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008709 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008710 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008711 return MakePair(isolate->heap()->undefined_value(),
8712 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008713 }
8714}
8715
8716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008717RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008718 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008719}
8720
8721
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008722RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008723 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008724}
8725
8726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008727RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008728 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008729 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008730
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008731 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008732 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008733 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008734 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008735 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8736 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008737 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008738
8739 int index;
8740 PropertyAttributes attributes;
8741 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008742 BindingFlags binding_flags;
8743 Handle<Object> holder = context->Lookup(name,
8744 flags,
8745 &index,
8746 &attributes,
8747 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008748
8749 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008750 if (holder->IsContext()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008751 Handle<Context> context = Handle<Context>::cast(holder);
8752 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8753 context->get(index)->IsTheHole()) {
8754 Handle<Object> error =
8755 isolate->factory()->NewReferenceError("not_defined",
8756 HandleVector(&name, 1));
8757 return isolate->Throw(*error);
8758 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008759 // Ignore if read_only variable.
8760 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008761 // Context is a fixed array and set cannot fail.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008762 context->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008763 } else if (strict_mode == kStrictMode) {
8764 // Setting read only property in strict mode.
8765 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008766 isolate->factory()->NewTypeError("strict_cannot_assign",
8767 HandleVector(&name, 1));
8768 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008769 }
8770 } else {
8771 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008772 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008773 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008774 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008775 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008776 return Failure::Exception();
8777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008778 }
8779 return *value;
8780 }
8781
8782 // Slow case: The property is not in a FixedArray context.
8783 // It is either in an JSObject extension context or it was not found.
8784 Handle<JSObject> context_ext;
8785
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008786 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008787 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008788 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008789 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008790 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008791 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008792
8793 if (strict_mode == kStrictMode) {
8794 // Throw in strict mode (assignment to undefined variable).
8795 Handle<Object> error =
8796 isolate->factory()->NewReferenceError(
8797 "not_defined", HandleVector(&name, 1));
8798 return isolate->Throw(*error);
8799 }
8800 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008801 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008802 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803 }
8804
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008805 // Set the property, but ignore if read_only variable on the context
8806 // extension object itself.
8807 if ((attributes & READ_ONLY) == 0 ||
8808 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008809 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008810 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008811 SetProperty(context_ext, name, value, NONE, strict_mode));
8812 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008813 // Setting read only property in strict mode.
8814 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008815 isolate->factory()->NewTypeError(
8816 "strict_cannot_assign", HandleVector(&name, 1));
8817 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818 }
8819 return *value;
8820}
8821
8822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008823RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 ASSERT(args.length() == 1);
8826
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008827 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008828}
8829
8830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008831RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008832 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008833 ASSERT(args.length() == 1);
8834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836}
8837
8838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008839RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008840 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008841 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008842}
8843
8844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008845RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008846 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008847 ASSERT(args.length() == 1);
8848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008849 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008850 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008851 isolate->factory()->NewReferenceError("not_defined",
8852 HandleVector(&name, 1));
8853 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008854}
8855
8856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008857RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008858 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008859
8860 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008861 if (isolate->stack_guard()->IsStackOverflow()) {
8862 NoHandleAllocation na;
8863 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008864 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008865
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008866 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008867}
8868
8869
8870// NOTE: These PrintXXX functions are defined for all builds (not just
8871// DEBUG builds) because we may want to be able to trace function
8872// calls in all modes.
8873static void PrintString(String* str) {
8874 // not uncommon to have empty strings
8875 if (str->length() > 0) {
8876 SmartPointer<char> s =
8877 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8878 PrintF("%s", *s);
8879 }
8880}
8881
8882
8883static void PrintObject(Object* obj) {
8884 if (obj->IsSmi()) {
8885 PrintF("%d", Smi::cast(obj)->value());
8886 } else if (obj->IsString() || obj->IsSymbol()) {
8887 PrintString(String::cast(obj));
8888 } else if (obj->IsNumber()) {
8889 PrintF("%g", obj->Number());
8890 } else if (obj->IsFailure()) {
8891 PrintF("<failure>");
8892 } else if (obj->IsUndefined()) {
8893 PrintF("<undefined>");
8894 } else if (obj->IsNull()) {
8895 PrintF("<null>");
8896 } else if (obj->IsTrue()) {
8897 PrintF("<true>");
8898 } else if (obj->IsFalse()) {
8899 PrintF("<false>");
8900 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008901 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008902 }
8903}
8904
8905
8906static int StackSize() {
8907 int n = 0;
8908 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8909 return n;
8910}
8911
8912
8913static void PrintTransition(Object* result) {
8914 // indentation
8915 { const int nmax = 80;
8916 int n = StackSize();
8917 if (n <= nmax)
8918 PrintF("%4d:%*s", n, n, "");
8919 else
8920 PrintF("%4d:%*s", n, nmax, "...");
8921 }
8922
8923 if (result == NULL) {
8924 // constructor calls
8925 JavaScriptFrameIterator it;
8926 JavaScriptFrame* frame = it.frame();
8927 if (frame->IsConstructor()) PrintF("new ");
8928 // function name
8929 Object* fun = frame->function();
8930 if (fun->IsJSFunction()) {
8931 PrintObject(JSFunction::cast(fun)->shared()->name());
8932 } else {
8933 PrintObject(fun);
8934 }
8935 // function arguments
8936 // (we are intentionally only printing the actually
8937 // supplied parameters, not all parameters required)
8938 PrintF("(this=");
8939 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008940 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008941 for (int i = 0; i < length; i++) {
8942 PrintF(", ");
8943 PrintObject(frame->GetParameter(i));
8944 }
8945 PrintF(") {\n");
8946
8947 } else {
8948 // function result
8949 PrintF("} -> ");
8950 PrintObject(result);
8951 PrintF("\n");
8952 }
8953}
8954
8955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008956RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008957 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958 NoHandleAllocation ha;
8959 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008960 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008961}
8962
8963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008964RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965 NoHandleAllocation ha;
8966 PrintTransition(args[0]);
8967 return args[0]; // return TOS
8968}
8969
8970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008971RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972 NoHandleAllocation ha;
8973 ASSERT(args.length() == 1);
8974
8975#ifdef DEBUG
8976 if (args[0]->IsString()) {
8977 // If we have a string, assume it's a code "marker"
8978 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008979 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008980 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008981 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8982 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983 } else {
8984 PrintF("DebugPrint: ");
8985 }
8986 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008987 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008988 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008989 HeapObject::cast(args[0])->map()->Print();
8990 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008992 // ShortPrint is available in release mode. Print is not.
8993 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008994#endif
8995 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008996 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008997
8998 return args[0]; // return TOS
8999}
9000
9001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009002RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009003 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009005 isolate->PrintStack();
9006 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007}
9008
9009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009010RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009012 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013
9014 // According to ECMA-262, section 15.9.1, page 117, the precision of
9015 // the number in a Date object representing a particular instant in
9016 // time is milliseconds. Therefore, we floor the result of getting
9017 // the OS time.
9018 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009019 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009020}
9021
9022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009023RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009024 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009025 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009026
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009027 CONVERT_ARG_CHECKED(String, str, 0);
9028 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009030 CONVERT_ARG_CHECKED(JSArray, output, 1);
9031 RUNTIME_ASSERT(output->HasFastElements());
9032
9033 AssertNoAllocation no_allocation;
9034
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009035 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009036 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9037 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009038 String::FlatContent str_content = str->GetFlatContent();
9039 if (str_content.IsAscii()) {
9040 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009041 output_array,
9042 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009043 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009044 ASSERT(str_content.IsTwoByte());
9045 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009046 output_array,
9047 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009048 }
9049
9050 if (result) {
9051 return *output;
9052 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009054 }
9055}
9056
9057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009058RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059 NoHandleAllocation ha;
9060 ASSERT(args.length() == 1);
9061
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009062 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009063 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009064 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009065}
9066
9067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009068RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009070 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009072 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073}
9074
9075
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009076RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077 NoHandleAllocation ha;
9078 ASSERT(args.length() == 1);
9079
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009080 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009081 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082}
9083
9084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009085RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009086 ASSERT(args.length() == 1);
9087 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009088 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009089 return JSGlobalObject::cast(global)->global_receiver();
9090}
9091
9092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009093RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009094 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009095 ASSERT_EQ(1, args.length());
9096 CONVERT_ARG_CHECKED(String, source, 0);
9097
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009098 source = Handle<String>(source->TryFlattenGetString());
9099 // Optimized fast case where we only have ascii characters.
9100 Handle<Object> result;
9101 if (source->IsSeqAsciiString()) {
9102 result = JsonParser<true>::Parse(source);
9103 } else {
9104 result = JsonParser<false>::Parse(source);
9105 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009106 if (result.is_null()) {
9107 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009108 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009109 return Failure::Exception();
9110 }
9111 return *result;
9112}
9113
9114
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009115bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9116 Handle<Context> context) {
9117 if (context->allow_code_gen_from_strings()->IsFalse()) {
9118 // Check with callback if set.
9119 AllowCodeGenerationFromStringsCallback callback =
9120 isolate->allow_code_gen_callback();
9121 if (callback == NULL) {
9122 // No callback set and code generation disallowed.
9123 return false;
9124 } else {
9125 // Callback set. Let it decide if code generation is allowed.
9126 VMState state(isolate, EXTERNAL);
9127 return callback(v8::Utils::ToLocal(context));
9128 }
9129 }
9130 return true;
9131}
9132
9133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009134RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009135 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009136 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009137 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009138
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009139 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009140 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009141
9142 // Check if global context allows code generation from
9143 // strings. Throw an exception if it doesn't.
9144 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9145 return isolate->Throw(*isolate->factory()->NewError(
9146 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9147 }
9148
9149 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009150 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9151 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009152 true,
9153 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009154 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9157 context,
9158 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 return *fun;
9160}
9161
9162
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009163static ObjectPair CompileGlobalEval(Isolate* isolate,
9164 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009165 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009166 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009167 Handle<Context> context = Handle<Context>(isolate->context());
9168 Handle<Context> global_context = Handle<Context>(context->global_context());
9169
9170 // Check if global context allows code generation from
9171 // strings. Throw an exception if it doesn't.
9172 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9173 isolate->Throw(*isolate->factory()->NewError(
9174 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9175 return MakePair(Failure::Exception(), NULL);
9176 }
9177
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009178 // Deal with a normal eval call with a string argument. Compile it
9179 // and return the compiled function bound in the local context.
9180 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9181 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009182 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009183 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009184 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009185 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009186 Handle<JSFunction> compiled =
9187 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009188 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009189 return MakePair(*compiled, *receiver);
9190}
9191
9192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009193RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009194 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009195
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009197 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009198 Handle<Object> receiver; // Will be overwritten.
9199
9200 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009201 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009202#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009203 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009204 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009205 StackFrameLocator locator;
9206 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009207 ASSERT(Context::cast(frame->context()) == *context);
9208#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009209
9210 // Find where the 'eval' symbol is bound. It is unaliased only if
9211 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009212 int index = -1;
9213 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009214 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009215 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009216 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9217 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009218 &index,
9219 &attributes,
9220 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009221 // Stop search when eval is found or when the global context is
9222 // reached.
9223 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009224 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009225 }
9226
iposva@chromium.org245aa852009-02-10 00:49:54 +00009227 // If eval could not be resolved, it has been deleted and we need to
9228 // throw a reference error.
9229 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009231 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009232 isolate->factory()->NewReferenceError("not_defined",
9233 HandleVector(&name, 1));
9234 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009235 }
9236
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009237 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009238 // 'eval' is not bound in the global context. Just call the function
9239 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009240 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009241 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009242 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009243 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009244 }
9245
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009246 // 'eval' is bound in the global context, but it may have been overwritten.
9247 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009248 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009249 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009250 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009251 }
9252
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009253 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009254 return CompileGlobalEval(isolate,
9255 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009256 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009257 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009258}
9259
9260
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009261RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009262 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009263
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009264 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009265 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009266
9267 // 'eval' is bound in the global context, but it may have been overwritten.
9268 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009269 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009270 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009271 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009272 }
9273
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009274 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009275 return CompileGlobalEval(isolate,
9276 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009277 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009278 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009279}
9280
9281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009282RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283 // This utility adjusts the property attributes for newly created Function
9284 // object ("new Function(...)") by changing the map.
9285 // All it does is changing the prototype property to enumerable
9286 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009287 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009288 ASSERT(args.length() == 1);
9289 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009290
9291 Handle<Map> map = func->shared()->strict_mode()
9292 ? isolate->strict_mode_function_instance_map()
9293 : isolate->function_instance_map();
9294
9295 ASSERT(func->map()->instance_type() == map->instance_type());
9296 ASSERT(func->map()->instance_size() == map->instance_size());
9297 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298 return *func;
9299}
9300
9301
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009302RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009303 // Allocate a block of memory in NewSpace (filled with a filler).
9304 // Use as fallback for allocation in generated code when NewSpace
9305 // is full.
9306 ASSERT(args.length() == 1);
9307 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9308 int size = size_smi->value();
9309 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9310 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009311 Heap* heap = isolate->heap();
9312 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009313 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009314 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009315 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009316 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009317 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009318 }
9319 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009320 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009321}
9322
9323
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009324// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009325// array. Returns true if the element was pushed on the stack and
9326// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009327RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009328 ASSERT(args.length() == 2);
9329 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009330 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009331 RUNTIME_ASSERT(array->HasFastElements());
9332 int length = Smi::cast(array->length())->value();
9333 FixedArray* elements = FixedArray::cast(array->elements());
9334 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009335 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009336 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009337 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009338 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009339 { MaybeObject* maybe_obj =
9340 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009341 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9342 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009343 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009344}
9345
9346
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009347/**
9348 * A simple visitor visits every element of Array's.
9349 * The backend storage can be a fixed array for fast elements case,
9350 * or a dictionary for sparse array. Since Dictionary is a subtype
9351 * of FixedArray, the class can be used by both fast and slow cases.
9352 * The second parameter of the constructor, fast_elements, specifies
9353 * whether the storage is a FixedArray or Dictionary.
9354 *
9355 * An index limit is used to deal with the situation that a result array
9356 * length overflows 32-bit non-negative integer.
9357 */
9358class ArrayConcatVisitor {
9359 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009360 ArrayConcatVisitor(Isolate* isolate,
9361 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009362 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 isolate_(isolate),
9364 storage_(Handle<FixedArray>::cast(
9365 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009366 index_offset_(0u),
9367 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009368
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009369 ~ArrayConcatVisitor() {
9370 clear_storage();
9371 }
9372
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009373 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009374 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009375 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009376
9377 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009378 if (index < static_cast<uint32_t>(storage_->length())) {
9379 storage_->set(index, *elm);
9380 return;
9381 }
9382 // Our initial estimate of length was foiled, possibly by
9383 // getters on the arrays increasing the length of later arrays
9384 // during iteration.
9385 // This shouldn't happen in anything but pathological cases.
9386 SetDictionaryMode(index);
9387 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009388 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009389 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009390 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009391 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009392 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009393 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009394 // Dictionary needed to grow.
9395 clear_storage();
9396 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009397 }
9398}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009399
9400 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009401 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9402 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009403 } else {
9404 index_offset_ += delta;
9405 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009406 }
9407
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009408 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009409 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009410 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009411 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009412 Handle<Map> map;
9413 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009414 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009415 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009416 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009417 }
9418 array->set_map(*map);
9419 array->set_length(*length);
9420 array->set_elements(*storage_);
9421 return array;
9422 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009423
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009424 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009425 // Convert storage to dictionary mode.
9426 void SetDictionaryMode(uint32_t index) {
9427 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009428 Handle<FixedArray> current_storage(*storage_);
9429 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009430 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009431 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9432 for (uint32_t i = 0; i < current_length; i++) {
9433 HandleScope loop_scope;
9434 Handle<Object> element(current_storage->get(i));
9435 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009436 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009437 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009438 if (!new_storage.is_identical_to(slow_storage)) {
9439 slow_storage = loop_scope.CloseAndEscape(new_storage);
9440 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009441 }
9442 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009443 clear_storage();
9444 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009445 fast_elements_ = false;
9446 }
9447
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009448 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009449 isolate_->global_handles()->Destroy(
9450 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009451 }
9452
9453 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009454 storage_ = Handle<FixedArray>::cast(
9455 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009456 }
9457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009458 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009459 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009460 // Index after last seen index. Always less than or equal to
9461 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009462 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009463 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009464};
9465
9466
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009467static uint32_t EstimateElementCount(Handle<JSArray> array) {
9468 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9469 int element_count = 0;
9470 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009471 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009472 // Fast elements can't have lengths that are not representable by
9473 // a 32-bit signed integer.
9474 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9475 int fast_length = static_cast<int>(length);
9476 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9477 for (int i = 0; i < fast_length; i++) {
9478 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009479 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009480 break;
9481 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009482 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009483 Handle<NumberDictionary> dictionary(
9484 NumberDictionary::cast(array->elements()));
9485 int capacity = dictionary->Capacity();
9486 for (int i = 0; i < capacity; i++) {
9487 Handle<Object> key(dictionary->KeyAt(i));
9488 if (dictionary->IsKey(*key)) {
9489 element_count++;
9490 }
9491 }
9492 break;
9493 }
9494 default:
9495 // External arrays are always dense.
9496 return length;
9497 }
9498 // As an estimate, we assume that the prototype doesn't contain any
9499 // inherited elements.
9500 return element_count;
9501}
9502
9503
9504
9505template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009506static void IterateExternalArrayElements(Isolate* isolate,
9507 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009508 bool elements_are_ints,
9509 bool elements_are_guaranteed_smis,
9510 ArrayConcatVisitor* visitor) {
9511 Handle<ExternalArrayClass> array(
9512 ExternalArrayClass::cast(receiver->elements()));
9513 uint32_t len = static_cast<uint32_t>(array->length());
9514
9515 ASSERT(visitor != NULL);
9516 if (elements_are_ints) {
9517 if (elements_are_guaranteed_smis) {
9518 for (uint32_t j = 0; j < len; j++) {
9519 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009520 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009521 visitor->visit(j, e);
9522 }
9523 } else {
9524 for (uint32_t j = 0; j < len; j++) {
9525 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009526 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009527 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9528 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9529 visitor->visit(j, e);
9530 } else {
9531 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009532 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009533 visitor->visit(j, e);
9534 }
9535 }
9536 }
9537 } else {
9538 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009539 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009540 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009541 visitor->visit(j, e);
9542 }
9543 }
9544}
9545
9546
9547// Used for sorting indices in a List<uint32_t>.
9548static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9549 uint32_t a = *ap;
9550 uint32_t b = *bp;
9551 return (a == b) ? 0 : (a < b) ? -1 : 1;
9552}
9553
9554
9555static void CollectElementIndices(Handle<JSObject> object,
9556 uint32_t range,
9557 List<uint32_t>* indices) {
9558 JSObject::ElementsKind kind = object->GetElementsKind();
9559 switch (kind) {
9560 case JSObject::FAST_ELEMENTS: {
9561 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9562 uint32_t length = static_cast<uint32_t>(elements->length());
9563 if (range < length) length = range;
9564 for (uint32_t i = 0; i < length; i++) {
9565 if (!elements->get(i)->IsTheHole()) {
9566 indices->Add(i);
9567 }
9568 }
9569 break;
9570 }
9571 case JSObject::DICTIONARY_ELEMENTS: {
9572 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009573 uint32_t capacity = dict->Capacity();
9574 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009575 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009576 Handle<Object> k(dict->KeyAt(j));
9577 if (dict->IsKey(*k)) {
9578 ASSERT(k->IsNumber());
9579 uint32_t index = static_cast<uint32_t>(k->Number());
9580 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009581 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009582 }
9583 }
9584 }
9585 break;
9586 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009587 default: {
9588 int dense_elements_length;
9589 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009590 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009591 dense_elements_length =
9592 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009593 break;
9594 }
9595 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009596 dense_elements_length =
9597 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 break;
9599 }
9600 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009601 dense_elements_length =
9602 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009603 break;
9604 }
9605 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009606 dense_elements_length =
9607 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009608 break;
9609 }
9610 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009611 dense_elements_length =
9612 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009613 break;
9614 }
9615 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009616 dense_elements_length =
9617 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009618 break;
9619 }
9620 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009621 dense_elements_length =
9622 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009623 break;
9624 }
9625 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009626 dense_elements_length =
9627 ExternalFloatArray::cast(object->elements())->length();
9628 break;
9629 }
9630 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9631 dense_elements_length =
9632 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 break;
9634 }
9635 default:
9636 UNREACHABLE();
9637 dense_elements_length = 0;
9638 break;
9639 }
9640 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9641 if (range <= length) {
9642 length = range;
9643 // We will add all indices, so we might as well clear it first
9644 // and avoid duplicates.
9645 indices->Clear();
9646 }
9647 for (uint32_t i = 0; i < length; i++) {
9648 indices->Add(i);
9649 }
9650 if (length == range) return; // All indices accounted for already.
9651 break;
9652 }
9653 }
9654
9655 Handle<Object> prototype(object->GetPrototype());
9656 if (prototype->IsJSObject()) {
9657 // The prototype will usually have no inherited element indices,
9658 // but we have to check.
9659 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9660 }
9661}
9662
9663
9664/**
9665 * A helper function that visits elements of a JSArray in numerical
9666 * order.
9667 *
9668 * The visitor argument called for each existing element in the array
9669 * with the element index and the element's value.
9670 * Afterwards it increments the base-index of the visitor by the array
9671 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009672 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009673 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009674static bool IterateElements(Isolate* isolate,
9675 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009676 ArrayConcatVisitor* visitor) {
9677 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9678 switch (receiver->GetElementsKind()) {
9679 case JSObject::FAST_ELEMENTS: {
9680 // Run through the elements FixedArray and use HasElement and GetElement
9681 // to check the prototype for missing elements.
9682 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9683 int fast_length = static_cast<int>(length);
9684 ASSERT(fast_length <= elements->length());
9685 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009686 HandleScope loop_scope(isolate);
9687 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009688 if (!element_value->IsTheHole()) {
9689 visitor->visit(j, element_value);
9690 } else if (receiver->HasElement(j)) {
9691 // Call GetElement on receiver, not its prototype, or getters won't
9692 // have the correct receiver.
9693 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009694 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009695 visitor->visit(j, element_value);
9696 }
9697 }
9698 break;
9699 }
9700 case JSObject::DICTIONARY_ELEMENTS: {
9701 Handle<NumberDictionary> dict(receiver->element_dictionary());
9702 List<uint32_t> indices(dict->Capacity() / 2);
9703 // Collect all indices in the object and the prototypes less
9704 // than length. This might introduce duplicates in the indices list.
9705 CollectElementIndices(receiver, length, &indices);
9706 indices.Sort(&compareUInt32);
9707 int j = 0;
9708 int n = indices.length();
9709 while (j < n) {
9710 HandleScope loop_scope;
9711 uint32_t index = indices[j];
9712 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009713 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 visitor->visit(index, element);
9715 // Skip to next different index (i.e., omit duplicates).
9716 do {
9717 j++;
9718 } while (j < n && indices[j] == index);
9719 }
9720 break;
9721 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009722 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9723 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9724 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009725 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009726 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009727 visitor->visit(j, e);
9728 }
9729 break;
9730 }
9731 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9732 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009733 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009734 break;
9735 }
9736 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9737 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009738 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009739 break;
9740 }
9741 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9742 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009743 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009744 break;
9745 }
9746 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9747 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009748 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009749 break;
9750 }
9751 case JSObject::EXTERNAL_INT_ELEMENTS: {
9752 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009754 break;
9755 }
9756 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9757 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009758 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009759 break;
9760 }
9761 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9762 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009764 break;
9765 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009766 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9767 IterateExternalArrayElements<ExternalDoubleArray, double>(
9768 isolate, receiver, false, false, visitor);
9769 break;
9770 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009771 default:
9772 UNREACHABLE();
9773 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009774 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009775 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009776 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009777}
9778
9779
9780/**
9781 * Array::concat implementation.
9782 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009783 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009784 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009785 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009786RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009787 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009788 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009789
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009790 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9791 int argument_count = static_cast<int>(arguments->length()->Number());
9792 RUNTIME_ASSERT(arguments->HasFastElements());
9793 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009794
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009795 // Pass 1: estimate the length and number of elements of the result.
9796 // The actual length can be larger if any of the arguments have getters
9797 // that mutate other arguments (but will otherwise be precise).
9798 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009799
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009800 uint32_t estimate_result_length = 0;
9801 uint32_t estimate_nof_elements = 0;
9802 {
9803 for (int i = 0; i < argument_count; i++) {
9804 HandleScope loop_scope;
9805 Handle<Object> obj(elements->get(i));
9806 uint32_t length_estimate;
9807 uint32_t element_estimate;
9808 if (obj->IsJSArray()) {
9809 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9810 length_estimate =
9811 static_cast<uint32_t>(array->length()->Number());
9812 element_estimate =
9813 EstimateElementCount(array);
9814 } else {
9815 length_estimate = 1;
9816 element_estimate = 1;
9817 }
9818 // Avoid overflows by capping at kMaxElementCount.
9819 if (JSObject::kMaxElementCount - estimate_result_length <
9820 length_estimate) {
9821 estimate_result_length = JSObject::kMaxElementCount;
9822 } else {
9823 estimate_result_length += length_estimate;
9824 }
9825 if (JSObject::kMaxElementCount - estimate_nof_elements <
9826 element_estimate) {
9827 estimate_nof_elements = JSObject::kMaxElementCount;
9828 } else {
9829 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009830 }
9831 }
9832 }
9833
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009834 // If estimated number of elements is more than half of length, a
9835 // fixed array (fast case) is more time and space-efficient than a
9836 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009837 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009838
9839 Handle<FixedArray> storage;
9840 if (fast_case) {
9841 // The backing storage array must have non-existing elements to
9842 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009843 storage = isolate->factory()->NewFixedArrayWithHoles(
9844 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009845 } else {
9846 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9847 uint32_t at_least_space_for = estimate_nof_elements +
9848 (estimate_nof_elements >> 2);
9849 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009850 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009851 }
9852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009853 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009854
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009855 for (int i = 0; i < argument_count; i++) {
9856 Handle<Object> obj(elements->get(i));
9857 if (obj->IsJSArray()) {
9858 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009859 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009860 return Failure::Exception();
9861 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009862 } else {
9863 visitor.visit(0, obj);
9864 visitor.increase_index_offset(1);
9865 }
9866 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009867
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009868 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009869}
9870
9871
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872// This will not allocate (flatten the string), but it may run
9873// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009874RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 NoHandleAllocation ha;
9876 ASSERT(args.length() == 1);
9877
9878 CONVERT_CHECKED(String, string, args[0]);
9879 StringInputBuffer buffer(string);
9880 while (buffer.has_more()) {
9881 uint16_t character = buffer.GetNext();
9882 PrintF("%c", character);
9883 }
9884 return string;
9885}
9886
ager@chromium.org5ec48922009-05-05 07:25:34 +00009887// Moves all own elements of an object, that are below a limit, to positions
9888// starting at zero. All undefined values are placed after non-undefined values,
9889// and are followed by non-existing element. Does not change the length
9890// property.
9891// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009892RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009893 ASSERT(args.length() == 2);
9894 CONVERT_CHECKED(JSObject, object, args[0]);
9895 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9896 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009897}
9898
9899
9900// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009901RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009902 ASSERT(args.length() == 2);
9903 CONVERT_CHECKED(JSArray, from, args[0]);
9904 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009905 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009906 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009907 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9908 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009909 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009910 } else if (new_elements->map() ==
9911 isolate->heap()->fixed_double_array_map()) {
9912 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009913 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009914 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009915 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009916 Object* new_map;
9917 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009918 to->set_map(Map::cast(new_map));
9919 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009921 Object* obj;
9922 { MaybeObject* maybe_obj = from->ResetElements();
9923 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9924 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009925 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009926 return to;
9927}
9928
9929
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009930// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009931RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009933 CONVERT_CHECKED(JSObject, object, args[0]);
9934 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009935 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009936 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009937 } else if (object->IsJSArray()) {
9938 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009940 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009941 }
9942}
9943
9944
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009945RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009946 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009947
9948 ASSERT_EQ(3, args.length());
9949
ager@chromium.orgac091b72010-05-05 07:34:42 +00009950 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009951 Handle<Object> key1 = args.at<Object>(1);
9952 Handle<Object> key2 = args.at<Object>(2);
9953
9954 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009955 if (!key1->ToArrayIndex(&index1)
9956 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009957 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009958 }
9959
ager@chromium.orgac091b72010-05-05 07:34:42 +00009960 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9961 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009962 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009963 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009964 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009965
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009966 RETURN_IF_EMPTY_HANDLE(isolate,
9967 SetElement(jsobject, index1, tmp2, kStrictMode));
9968 RETURN_IF_EMPTY_HANDLE(isolate,
9969 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009970
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009971 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009972}
9973
9974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009976// might have elements. Can either return keys (positive integers) or
9977// intervals (pair of a negative integer (-start-1) followed by a
9978// positive (length)) or undefined values.
9979// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009980RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009981 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009982 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009983 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009984 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009985 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009986 // Create an array and get all the keys into it, then remove all the
9987 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009988 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 int keys_length = keys->length();
9990 for (int i = 0; i < keys_length; i++) {
9991 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009992 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009993 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009994 // Zap invalid keys.
9995 keys->set_undefined(i);
9996 }
9997 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009998 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009999 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010000 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010001 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010002 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010003 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010004 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010005 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010006 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010007 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010008 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010009 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010010 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010011 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010012 }
10013}
10014
10015
10016// DefineAccessor takes an optional final argument which is the
10017// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10018// to the way accessors are implemented, it is set for both the getter
10019// and setter on the first call to DefineAccessor and ignored on
10020// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010021RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010022 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10023 // Compute attributes.
10024 PropertyAttributes attributes = NONE;
10025 if (args.length() == 5) {
10026 CONVERT_CHECKED(Smi, attrs, args[4]);
10027 int value = attrs->value();
10028 // Only attribute bits should be set.
10029 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10030 attributes = static_cast<PropertyAttributes>(value);
10031 }
10032
10033 CONVERT_CHECKED(JSObject, obj, args[0]);
10034 CONVERT_CHECKED(String, name, args[1]);
10035 CONVERT_CHECKED(Smi, flag, args[2]);
10036 CONVERT_CHECKED(JSFunction, fun, args[3]);
10037 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10038}
10039
10040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010041RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010042 ASSERT(args.length() == 3);
10043 CONVERT_CHECKED(JSObject, obj, args[0]);
10044 CONVERT_CHECKED(String, name, args[1]);
10045 CONVERT_CHECKED(Smi, flag, args[2]);
10046 return obj->LookupAccessor(name, flag->value() == 0);
10047}
10048
10049
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010050#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010051RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010052 ASSERT(args.length() == 0);
10053 return Execution::DebugBreakHelper();
10054}
10055
10056
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010057// Helper functions for wrapping and unwrapping stack frame ids.
10058static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010059 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010060 return Smi::FromInt(id >> 2);
10061}
10062
10063
10064static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10065 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10066}
10067
10068
10069// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010070// args[0]: debug event listener function to set or null or undefined for
10071// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010072// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010073RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010074 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010075 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10076 args[0]->IsUndefined() ||
10077 args[0]->IsNull());
10078 Handle<Object> callback = args.at<Object>(0);
10079 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010080 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010081
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010083}
10084
10085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010086RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010087 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010088 isolate->stack_guard()->DebugBreak();
10089 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010090}
10091
10092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010093static MaybeObject* DebugLookupResultValue(Heap* heap,
10094 Object* receiver,
10095 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010096 LookupResult* result,
10097 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010098 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010099 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010100 case NORMAL:
10101 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010102 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010103 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 }
10105 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010106 case FIELD:
10107 value =
10108 JSObject::cast(
10109 result->holder())->FastPropertyAt(result->GetFieldIndex());
10110 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010111 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010112 }
10113 return value;
10114 case CONSTANT_FUNCTION:
10115 return result->GetConstantFunction();
10116 case CALLBACKS: {
10117 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010118 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010119 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010120 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010121 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010122 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010123 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010124 maybe_value = heap->isolate()->pending_exception();
10125 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010126 if (caught_exception != NULL) {
10127 *caught_exception = true;
10128 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010129 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010130 }
10131 return value;
10132 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010133 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010134 }
10135 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010136 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010137 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010138 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010139 case CONSTANT_TRANSITION:
10140 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010141 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010142 default:
10143 UNREACHABLE();
10144 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010145 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010146 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010147}
10148
10149
ager@chromium.org32912102009-01-16 10:38:43 +000010150// Get debugger related details for an object property.
10151// args[0]: object holding property
10152// args[1]: name of the property
10153//
10154// The array returned contains the following information:
10155// 0: Property value
10156// 1: Property details
10157// 2: Property value is exception
10158// 3: Getter function if defined
10159// 4: Setter function if defined
10160// Items 2-4 are only filled if the property has either a getter or a setter
10161// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010162RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010163 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010164
10165 ASSERT(args.length() == 2);
10166
10167 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10168 CONVERT_ARG_CHECKED(String, name, 1);
10169
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010170 // Make sure to set the current context to the context before the debugger was
10171 // entered (if the debugger is entered). The reason for switching context here
10172 // is that for some property lookups (accessors and interceptors) callbacks
10173 // into the embedding application can occour, and the embedding application
10174 // could have the assumption that its own global context is the current
10175 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 SaveContext save(isolate);
10177 if (isolate->debug()->InDebugger()) {
10178 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010179 }
10180
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010181 // Skip the global proxy as it has no properties and always delegates to the
10182 // real global object.
10183 if (obj->IsJSGlobalProxy()) {
10184 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10185 }
10186
10187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 // Check if the name is trivially convertible to an index and get the element
10189 // if so.
10190 uint32_t index;
10191 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010192 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010193 Object* element_or_char;
10194 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010195 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010196 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10197 return maybe_element_or_char;
10198 }
10199 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010200 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010201 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 }
10204
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010205 // Find the number of objects making up this.
10206 int length = LocalPrototypeChainLength(*obj);
10207
10208 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010209 Handle<JSObject> jsproto = obj;
10210 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010211 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010212 jsproto->LocalLookup(*name, &result);
10213 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010214 // LookupResult is not GC safe as it holds raw object pointers.
10215 // GC can happen later in this code so put the required fields into
10216 // local variables using handles when required for later use.
10217 PropertyType result_type = result.type();
10218 Handle<Object> result_callback_obj;
10219 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010220 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10221 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010222 }
10223 Smi* property_details = result.GetPropertyDetails().AsSmi();
10224 // DebugLookupResultValue can cause GC so details from LookupResult needs
10225 // to be copied to handles before this.
10226 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010227 Object* raw_value;
10228 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010229 DebugLookupResultValue(isolate->heap(), *obj, *name,
10230 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010231 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10232 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010233 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010234
10235 // If the callback object is a fixed array then it contains JavaScript
10236 // getter and/or setter.
10237 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10238 result_callback_obj->IsFixedArray();
10239 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010240 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010241 details->set(0, *value);
10242 details->set(1, property_details);
10243 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010244 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010245 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10246 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10247 }
10248
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010249 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010250 }
10251 if (i < length - 1) {
10252 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10253 }
10254 }
10255
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010256 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257}
10258
10259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010260RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262
10263 ASSERT(args.length() == 2);
10264
10265 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10266 CONVERT_ARG_CHECKED(String, name, 1);
10267
10268 LookupResult result;
10269 obj->Lookup(*name, &result);
10270 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010273 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274}
10275
10276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277// Return the property type calculated from the property details.
10278// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010279RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 ASSERT(args.length() == 1);
10281 CONVERT_CHECKED(Smi, details, args[0]);
10282 PropertyType type = PropertyDetails(details).type();
10283 return Smi::FromInt(static_cast<int>(type));
10284}
10285
10286
10287// Return the property attribute calculated from the property details.
10288// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010289RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290 ASSERT(args.length() == 1);
10291 CONVERT_CHECKED(Smi, details, args[0]);
10292 PropertyAttributes attributes = PropertyDetails(details).attributes();
10293 return Smi::FromInt(static_cast<int>(attributes));
10294}
10295
10296
10297// Return the property insertion index calculated from the property details.
10298// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010299RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010300 ASSERT(args.length() == 1);
10301 CONVERT_CHECKED(Smi, details, args[0]);
10302 int index = PropertyDetails(details).index();
10303 return Smi::FromInt(index);
10304}
10305
10306
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010307// Return property value from named interceptor.
10308// args[0]: object
10309// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010310RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010311 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312 ASSERT(args.length() == 2);
10313 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10314 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10315 CONVERT_ARG_CHECKED(String, name, 1);
10316
10317 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010318 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010319}
10320
10321
10322// Return element value from indexed interceptor.
10323// args[0]: object
10324// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010325RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010326 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327 ASSERT(args.length() == 2);
10328 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10329 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10330 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10331
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010332 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333}
10334
10335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010336RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337 ASSERT(args.length() >= 1);
10338 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010339 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010340 if (isolate->debug()->break_id() == 0 ||
10341 break_id != isolate->debug()->break_id()) {
10342 return isolate->Throw(
10343 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010344 }
10345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010346 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347}
10348
10349
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010350RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010351 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352 ASSERT(args.length() == 1);
10353
10354 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010355 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010356 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10357 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010358 if (!maybe_result->ToObject(&result)) return maybe_result;
10359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360
10361 // Count all frames which are relevant to debugging stack trace.
10362 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010363 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010364 if (id == StackFrame::NO_ID) {
10365 // If there is no JavaScript stack frame count is 0.
10366 return Smi::FromInt(0);
10367 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010368
10369 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10370 n += it.frame()->GetInlineCount();
10371 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010372 return Smi::FromInt(n);
10373}
10374
10375
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010376class FrameInspector {
10377 public:
10378 FrameInspector(JavaScriptFrame* frame,
10379 int inlined_frame_index,
10380 Isolate* isolate)
10381 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10382 // Calculate the deoptimized frame.
10383 if (frame->is_optimized()) {
10384 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10385 frame, inlined_frame_index, isolate);
10386 }
10387 has_adapted_arguments_ = frame_->has_adapted_arguments();
10388 is_optimized_ = frame_->is_optimized();
10389 }
10390
10391 ~FrameInspector() {
10392 // Get rid of the calculated deoptimized frame if any.
10393 if (deoptimized_frame_ != NULL) {
10394 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10395 isolate_);
10396 }
10397 }
10398
10399 int GetParametersCount() {
10400 return is_optimized_
10401 ? deoptimized_frame_->parameters_count()
10402 : frame_->ComputeParametersCount();
10403 }
10404 int expression_count() { return deoptimized_frame_->expression_count(); }
10405 Object* GetFunction() {
10406 return is_optimized_
10407 ? deoptimized_frame_->GetFunction()
10408 : frame_->function();
10409 }
10410 Object* GetParameter(int index) {
10411 return is_optimized_
10412 ? deoptimized_frame_->GetParameter(index)
10413 : frame_->GetParameter(index);
10414 }
10415 Object* GetExpression(int index) {
10416 return is_optimized_
10417 ? deoptimized_frame_->GetExpression(index)
10418 : frame_->GetExpression(index);
10419 }
10420
10421 // To inspect all the provided arguments the frame might need to be
10422 // replaced with the arguments frame.
10423 void SetArgumentsFrame(JavaScriptFrame* frame) {
10424 ASSERT(has_adapted_arguments_);
10425 frame_ = frame;
10426 is_optimized_ = frame_->is_optimized();
10427 ASSERT(!is_optimized_);
10428 }
10429
10430 private:
10431 JavaScriptFrame* frame_;
10432 DeoptimizedFrameInfo* deoptimized_frame_;
10433 Isolate* isolate_;
10434 bool is_optimized_;
10435 bool has_adapted_arguments_;
10436
10437 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10438};
10439
10440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010441static const int kFrameDetailsFrameIdIndex = 0;
10442static const int kFrameDetailsReceiverIndex = 1;
10443static const int kFrameDetailsFunctionIndex = 2;
10444static const int kFrameDetailsArgumentCountIndex = 3;
10445static const int kFrameDetailsLocalCountIndex = 4;
10446static const int kFrameDetailsSourcePositionIndex = 5;
10447static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010448static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010449static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010450static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451
10452// Return an array with frame details
10453// args[0]: number: break id
10454// args[1]: number: frame index
10455//
10456// The array returned contains the following information:
10457// 0: Frame id
10458// 1: Receiver
10459// 2: Function
10460// 3: Argument count
10461// 4: Local count
10462// 5: Source position
10463// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010464// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010465// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010466// Arguments name, value
10467// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010468// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010469RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471 ASSERT(args.length() == 2);
10472
10473 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010474 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010475 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10476 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010477 if (!maybe_check->ToObject(&check)) return maybe_check;
10478 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010479 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010480 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481
10482 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010483 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010484 if (id == StackFrame::NO_ID) {
10485 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010486 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010487 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010488
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010489 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010490
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010492 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010494 if (index < count + it.frame()->GetInlineCount()) break;
10495 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010497 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010498
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010499 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010500 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010501 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010502 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010503 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505 // Traverse the saved contexts chain to find the active context for the
10506 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010507 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010508 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010509 save = save->prev();
10510 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010511 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010512
10513 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010515
10516 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010518 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010520 // Check for constructor frame. Inlined frames cannot be construct calls.
10521 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010522 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010523 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010525 // Get scope info and read from it for local variable information.
10526 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010527 Handle<SharedFunctionInfo> shared(function->shared());
10528 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010529 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010530 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532 // Get the locals names and values into a temporary array.
10533 //
10534 // TODO(1240907): Hide compiler-introduced stack variables
10535 // (e.g. .result)? For users of the debugger, they will probably be
10536 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010537 Handle<FixedArray> locals =
10538 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010539
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010540 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010541 int i = 0;
10542 for (; i < info.number_of_stack_slots(); ++i) {
10543 // Use the value from the stack.
10544 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010545 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010546 }
10547 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010548 // Get the context containing declarations.
10549 Handle<Context> context(
10550 Context::cast(it.frame()->context())->declaration_context());
10551 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010552 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010553 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010554 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010555 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556 }
10557 }
10558
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010559 // Check whether this frame is positioned at return. If not top
10560 // frame or if the frame is optimized it cannot be at a return.
10561 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010562 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010563 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010564 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010565
10566 // If positioned just before return find the value to be returned and add it
10567 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010568 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010569 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010570 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010571 Address internal_frame_sp = NULL;
10572 while (!it2.done()) {
10573 if (it2.frame()->is_internal()) {
10574 internal_frame_sp = it2.frame()->sp();
10575 } else {
10576 if (it2.frame()->is_java_script()) {
10577 if (it2.frame()->id() == it.frame()->id()) {
10578 // The internal frame just before the JavaScript frame contains the
10579 // value to return on top. A debug break at return will create an
10580 // internal frame to store the return value (eax/rax/r0) before
10581 // entering the debug break exit frame.
10582 if (internal_frame_sp != NULL) {
10583 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010584 Handle<Object>(Memory::Object_at(internal_frame_sp),
10585 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010586 break;
10587 }
10588 }
10589 }
10590
10591 // Indicate that the previous frame was not an internal frame.
10592 internal_frame_sp = NULL;
10593 }
10594 it2.Advance();
10595 }
10596 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597
10598 // Now advance to the arguments adapter frame (if any). It contains all
10599 // the provided parameters whereas the function frame always have the number
10600 // of arguments matching the functions parameters. The rest of the
10601 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010602 if (it.frame()->has_adapted_arguments()) {
10603 it.AdvanceToArgumentsFrame();
10604 frame_inspector.SetArgumentsFrame(it.frame());
10605 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010606
10607 // Find the number of arguments to fill. At least fill the number of
10608 // parameters for the function and fill more if more parameters are provided.
10609 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010610 if (argument_count < frame_inspector.GetParametersCount()) {
10611 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010612 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010613#ifdef DEBUG
10614 if (it.frame()->is_optimized()) {
10615 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10616 }
10617#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618
10619 // Calculate the size of the result.
10620 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010621 2 * (argument_count + info.NumberOfLocals()) +
10622 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010623 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624
10625 // Add the frame id.
10626 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10627
10628 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010629 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010630
10631 // Add the arguments count.
10632 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10633
10634 // Add the locals count
10635 details->set(kFrameDetailsLocalCountIndex,
10636 Smi::FromInt(info.NumberOfLocals()));
10637
10638 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010639 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010640 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10641 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010642 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010643 }
10644
10645 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010646 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010647
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010648 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010649 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010650
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010651 // Add flags to indicate information on whether this frame is
10652 // bit 0: invoked in the debugger context.
10653 // bit 1: optimized frame.
10654 // bit 2: inlined in optimized frame
10655 int flags = 0;
10656 if (*save->context() == *isolate->debug()->debug_context()) {
10657 flags |= 1 << 0;
10658 }
10659 if (it.frame()->is_optimized()) {
10660 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010661 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010662 }
10663 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664
10665 // Fill the dynamic part.
10666 int details_index = kFrameDetailsFirstDynamicIndex;
10667
10668 // Add arguments name and value.
10669 for (int i = 0; i < argument_count; i++) {
10670 // Name of the argument.
10671 if (i < info.number_of_parameters()) {
10672 details->set(details_index++, *info.parameter_name(i));
10673 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010674 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010675 }
10676
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010677 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010678 if (i < it.frame()->ComputeParametersCount()) {
10679 // Get the value from the stack.
10680 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010681 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010682 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010683 }
10684 }
10685
10686 // Add locals name and value from the temporary copy from the function frame.
10687 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10688 details->set(details_index++, locals->get(i));
10689 }
10690
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010691 // Add the value being returned.
10692 if (at_return) {
10693 details->set(details_index++, *return_value);
10694 }
10695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010696 // Add the receiver (same as in function frame).
10697 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10698 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010699 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010700 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10701 // If the receiver is not a JSObject and the function is not a
10702 // builtin or strict-mode we have hit an optimization where a
10703 // value object is not converted into a wrapped JS objects. To
10704 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010705 // by creating correct wrapper object based on the calling frame's
10706 // global context.
10707 it.Advance();
10708 Handle<Context> calling_frames_global_context(
10709 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010710 receiver =
10711 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010712 }
10713 details->set(kFrameDetailsReceiverIndex, *receiver);
10714
10715 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010716 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717}
10718
10719
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010720// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010721static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010722 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010723 Handle<SerializedScopeInfo> serialized_scope_info,
10724 ScopeInfo<>& scope_info,
10725 Handle<Context> context,
10726 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010727 // Fill all context locals to the context extension.
10728 for (int i = Context::MIN_CONTEXT_SLOTS;
10729 i < scope_info.number_of_context_slots();
10730 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010731 int context_index = serialized_scope_info->ContextSlotIndex(
10732 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010733
whesse@chromium.org7b260152011-06-20 15:33:18 +000010734 RETURN_IF_EMPTY_HANDLE_VALUE(
10735 isolate,
10736 SetProperty(scope_object,
10737 scope_info.context_slot_name(i),
10738 Handle<Object>(context->get(context_index), isolate),
10739 NONE,
10740 kNonStrictMode),
10741 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010742 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010743
10744 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010745}
10746
10747
10748// Create a plain JSObject which materializes the local scope for the specified
10749// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010750static Handle<JSObject> MaterializeLocalScope(
10751 Isolate* isolate,
10752 JavaScriptFrame* frame,
10753 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010754 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010755 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010756 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10757 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010758 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010759
10760 // Allocate and initialize a JSObject with all the arguments, stack locals
10761 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010762 Handle<JSObject> local_scope =
10763 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010764
10765 // First fill all parameters.
10766 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010767 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010768 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010769 SetProperty(local_scope,
10770 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010771 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010772 NONE,
10773 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010774 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010775 }
10776
10777 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010778 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010779 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010780 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010781 SetProperty(local_scope,
10782 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010783 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010784 NONE,
10785 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010786 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010787 }
10788
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010789 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10790 // Third fill all context locals.
10791 Handle<Context> frame_context(Context::cast(frame->context()));
10792 Handle<Context> function_context(frame_context->declaration_context());
10793 if (!CopyContextLocalsToScopeObject(isolate,
10794 serialized_scope_info, scope_info,
10795 function_context, local_scope)) {
10796 return Handle<JSObject>();
10797 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010798
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010799 // Finally copy any properties from the function context extension.
10800 // These will be variables introduced by eval.
10801 if (function_context->closure() == *function) {
10802 if (function_context->has_extension() &&
10803 !function_context->IsGlobalContext()) {
10804 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10805 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10806 for (int i = 0; i < keys->length(); i++) {
10807 // Names of variables introduced by eval are strings.
10808 ASSERT(keys->get(i)->IsString());
10809 Handle<String> key(String::cast(keys->get(i)));
10810 RETURN_IF_EMPTY_HANDLE_VALUE(
10811 isolate,
10812 SetProperty(local_scope,
10813 key,
10814 GetProperty(ext, key),
10815 NONE,
10816 kNonStrictMode),
10817 Handle<JSObject>());
10818 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010819 }
10820 }
10821 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010822
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010823 return local_scope;
10824}
10825
10826
10827// Create a plain JSObject which materializes the closure content for the
10828// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010829static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10830 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010831 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010832
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010833 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010834 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10835 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010836
10837 // Allocate and initialize a JSObject with all the content of theis function
10838 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010839 Handle<JSObject> closure_scope =
10840 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010841
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010842 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 if (!CopyContextLocalsToScopeObject(isolate,
10844 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010845 context, closure_scope)) {
10846 return Handle<JSObject>();
10847 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010848
10849 // Finally copy any properties from the function context extension. This will
10850 // be variables introduced by eval.
10851 if (context->has_extension()) {
10852 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010853 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010854 for (int i = 0; i < keys->length(); i++) {
10855 // Names of variables introduced by eval are strings.
10856 ASSERT(keys->get(i)->IsString());
10857 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010858 RETURN_IF_EMPTY_HANDLE_VALUE(
10859 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010860 SetProperty(closure_scope,
10861 key,
10862 GetProperty(ext, key),
10863 NONE,
10864 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010865 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010866 }
10867 }
10868
10869 return closure_scope;
10870}
10871
10872
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010873// Create a plain JSObject which materializes the scope for the specified
10874// catch context.
10875static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10876 Handle<Context> context) {
10877 ASSERT(context->IsCatchContext());
10878 Handle<String> name(String::cast(context->extension()));
10879 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10880 Handle<JSObject> catch_scope =
10881 isolate->factory()->NewJSObject(isolate->object_function());
10882 RETURN_IF_EMPTY_HANDLE_VALUE(
10883 isolate,
10884 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10885 Handle<JSObject>());
10886 return catch_scope;
10887}
10888
10889
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010890// Create a plain JSObject which materializes the block scope for the specified
10891// block context.
10892static Handle<JSObject> MaterializeBlockScope(
10893 Isolate* isolate,
10894 Handle<Context> context) {
10895 ASSERT(context->IsBlockContext());
10896 Handle<SerializedScopeInfo> serialized_scope_info(
10897 SerializedScopeInfo::cast(context->extension()));
10898 ScopeInfo<> scope_info(*serialized_scope_info);
10899
10900 // Allocate and initialize a JSObject with all the arguments, stack locals
10901 // heap locals and extension properties of the debugged function.
10902 Handle<JSObject> block_scope =
10903 isolate->factory()->NewJSObject(isolate->object_function());
10904
10905 // Fill all context locals.
10906 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10907 if (!CopyContextLocalsToScopeObject(isolate,
10908 serialized_scope_info, scope_info,
10909 context, block_scope)) {
10910 return Handle<JSObject>();
10911 }
10912 }
10913
10914 return block_scope;
10915}
10916
10917
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010918// Iterate over the actual scopes visible from a stack frame. All scopes are
10919// backed by an actual context except the local scope, which is inserted
10920// "artifically" in the context chain.
10921class ScopeIterator {
10922 public:
10923 enum ScopeType {
10924 ScopeTypeGlobal = 0,
10925 ScopeTypeLocal,
10926 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010927 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010928 ScopeTypeCatch,
10929 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010930 };
10931
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010932 ScopeIterator(Isolate* isolate,
10933 JavaScriptFrame* frame,
10934 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010935 : isolate_(isolate),
10936 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010937 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010938 function_(JSFunction::cast(frame->function())),
10939 context_(Context::cast(frame->context())),
10940 local_done_(false),
10941 at_local_(false) {
10942
10943 // Check whether the first scope is actually a local scope.
10944 if (context_->IsGlobalContext()) {
10945 // If there is a stack slot for .result then this local scope has been
10946 // created for evaluating top level code and it is not a real local scope.
10947 // Checking for the existence of .result seems fragile, but the scope info
10948 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010949 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010950 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010951 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010952 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010953 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010954 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010955 // The context_ is a block or with or catch block from the outer function.
10956 ASSERT(context_->IsWithContext() ||
10957 context_->IsCatchContext() ||
10958 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010959 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010960 }
10961 }
10962
10963 // More scopes?
10964 bool Done() { return context_.is_null(); }
10965
10966 // Move to the next scope.
10967 void Next() {
10968 // If at a local scope mark the local scope as passed.
10969 if (at_local_) {
10970 at_local_ = false;
10971 local_done_ = true;
10972
10973 // If the current context is not associated with the local scope the
10974 // current context is the next real scope, so don't move to the next
10975 // context in this case.
10976 if (context_->closure() != *function_) {
10977 return;
10978 }
10979 }
10980
10981 // The global scope is always the last in the chain.
10982 if (context_->IsGlobalContext()) {
10983 context_ = Handle<Context>();
10984 return;
10985 }
10986
10987 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010988 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010989
10990 // If passing the local scope indicate that the current scope is now the
10991 // local scope.
10992 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010993 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010994 at_local_ = true;
10995 }
10996 }
10997
10998 // Return the type of the current scope.
10999 int Type() {
11000 if (at_local_) {
11001 return ScopeTypeLocal;
11002 }
11003 if (context_->IsGlobalContext()) {
11004 ASSERT(context_->global()->IsGlobalObject());
11005 return ScopeTypeGlobal;
11006 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011007 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011008 return ScopeTypeClosure;
11009 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011010 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011011 return ScopeTypeCatch;
11012 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011013 if (context_->IsBlockContext()) {
11014 return ScopeTypeBlock;
11015 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011016 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017 return ScopeTypeWith;
11018 }
11019
11020 // Return the JavaScript object with the content of the current scope.
11021 Handle<JSObject> ScopeObject() {
11022 switch (Type()) {
11023 case ScopeIterator::ScopeTypeGlobal:
11024 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011025 case ScopeIterator::ScopeTypeLocal:
11026 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011027 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011028 case ScopeIterator::ScopeTypeWith:
11029 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011030 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11031 case ScopeIterator::ScopeTypeCatch:
11032 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011033 case ScopeIterator::ScopeTypeClosure:
11034 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011035 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011036 case ScopeIterator::ScopeTypeBlock:
11037 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011038 }
11039 UNREACHABLE();
11040 return Handle<JSObject>();
11041 }
11042
11043 // Return the context for this scope. For the local context there might not
11044 // be an actual context.
11045 Handle<Context> CurrentContext() {
11046 if (at_local_ && context_->closure() != *function_) {
11047 return Handle<Context>();
11048 }
11049 return context_;
11050 }
11051
11052#ifdef DEBUG
11053 // Debug print of the content of the current scope.
11054 void DebugPrint() {
11055 switch (Type()) {
11056 case ScopeIterator::ScopeTypeGlobal:
11057 PrintF("Global:\n");
11058 CurrentContext()->Print();
11059 break;
11060
11061 case ScopeIterator::ScopeTypeLocal: {
11062 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011063 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011064 scope_info.Print();
11065 if (!CurrentContext().is_null()) {
11066 CurrentContext()->Print();
11067 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011068 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011069 if (extension->IsJSContextExtensionObject()) {
11070 extension->Print();
11071 }
11072 }
11073 }
11074 break;
11075 }
11076
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011077 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011078 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011079 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011080 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011081
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011082 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011083 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011084 CurrentContext()->extension()->Print();
11085 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011086 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011087
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011088 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011089 PrintF("Closure:\n");
11090 CurrentContext()->Print();
11091 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011092 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011093 if (extension->IsJSContextExtensionObject()) {
11094 extension->Print();
11095 }
11096 }
11097 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011098
11099 default:
11100 UNREACHABLE();
11101 }
11102 PrintF("\n");
11103 }
11104#endif
11105
11106 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011107 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011108 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011109 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011110 Handle<JSFunction> function_;
11111 Handle<Context> context_;
11112 bool local_done_;
11113 bool at_local_;
11114
11115 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11116};
11117
11118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011119RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011120 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121 ASSERT(args.length() == 2);
11122
11123 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011124 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011125 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11126 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011127 if (!maybe_check->ToObject(&check)) return maybe_check;
11128 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011129 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11130
11131 // Get the frame where the debugging is performed.
11132 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011133 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011134 JavaScriptFrame* frame = it.frame();
11135
11136 // Count the visible scopes.
11137 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011138 for (ScopeIterator it(isolate, frame, 0);
11139 !it.Done();
11140 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011141 n++;
11142 }
11143
11144 return Smi::FromInt(n);
11145}
11146
11147
11148static const int kScopeDetailsTypeIndex = 0;
11149static const int kScopeDetailsObjectIndex = 1;
11150static const int kScopeDetailsSize = 2;
11151
11152// Return an array with scope details
11153// args[0]: number: break id
11154// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011155// args[2]: number: inlined frame index
11156// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011157//
11158// The array returned contains the following information:
11159// 0: Scope type
11160// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011161RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011162 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011163 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011164
11165 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011166 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011167 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11168 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011169 if (!maybe_check->ToObject(&check)) return maybe_check;
11170 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011171 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011172 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11173 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011174
11175 // Get the frame where the debugging is performed.
11176 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011177 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011178 JavaScriptFrame* frame = frame_it.frame();
11179
11180 // Find the requested scope.
11181 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011182 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011183 for (; !it.Done() && n < index; it.Next()) {
11184 n++;
11185 }
11186 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011187 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011188 }
11189
11190 // Calculate the size of the result.
11191 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011192 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193
11194 // Fill in scope details.
11195 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011196 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011197 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011198 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011199
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011200 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011201}
11202
11203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011204RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011205 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011206 ASSERT(args.length() == 0);
11207
11208#ifdef DEBUG
11209 // Print the scopes for the top frame.
11210 StackFrameLocator locator;
11211 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011212 for (ScopeIterator it(isolate, frame, 0);
11213 !it.Done();
11214 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011215 it.DebugPrint();
11216 }
11217#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011218 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011219}
11220
11221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011222RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011223 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011224 ASSERT(args.length() == 1);
11225
11226 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011227 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011228 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11229 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011230 if (!maybe_result->ToObject(&result)) return maybe_result;
11231 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011232
11233 // Count all archived V8 threads.
11234 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011235 for (ThreadState* thread =
11236 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011237 thread != NULL;
11238 thread = thread->Next()) {
11239 n++;
11240 }
11241
11242 // Total number of threads is current thread and archived threads.
11243 return Smi::FromInt(n + 1);
11244}
11245
11246
11247static const int kThreadDetailsCurrentThreadIndex = 0;
11248static const int kThreadDetailsThreadIdIndex = 1;
11249static const int kThreadDetailsSize = 2;
11250
11251// Return an array with thread details
11252// args[0]: number: break id
11253// args[1]: number: thread index
11254//
11255// The array returned contains the following information:
11256// 0: Is current thread?
11257// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011258RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011259 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011260 ASSERT(args.length() == 2);
11261
11262 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011263 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011264 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11265 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011266 if (!maybe_check->ToObject(&check)) return maybe_check;
11267 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011268 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11269
11270 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011271 Handle<FixedArray> details =
11272 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011273
11274 // Thread index 0 is current thread.
11275 if (index == 0) {
11276 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011277 details->set(kThreadDetailsCurrentThreadIndex,
11278 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011279 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011280 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011281 } else {
11282 // Find the thread with the requested index.
11283 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011284 ThreadState* thread =
11285 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011286 while (index != n && thread != NULL) {
11287 thread = thread->Next();
11288 n++;
11289 }
11290 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011291 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011292 }
11293
11294 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011295 details->set(kThreadDetailsCurrentThreadIndex,
11296 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011297 details->set(kThreadDetailsThreadIdIndex,
11298 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011299 }
11300
11301 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011302 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011303}
11304
11305
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011306// Sets the disable break state
11307// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011308RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011309 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011310 ASSERT(args.length() == 1);
11311 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011312 isolate->debug()->set_disable_break(disable_break);
11313 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011314}
11315
11316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011317RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011318 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011319 ASSERT(args.length() == 1);
11320
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011321 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11322 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011323 // Find the number of break points
11324 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011325 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011326 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011327 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011328 Handle<FixedArray>::cast(break_locations));
11329}
11330
11331
11332// Set a break point in a function
11333// args[0]: function
11334// args[1]: number: break source position (within the function source)
11335// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011336RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011338 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011339 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11340 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011341 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11342 RUNTIME_ASSERT(source_position >= 0);
11343 Handle<Object> break_point_object_arg = args.at<Object>(2);
11344
11345 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011346 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11347 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011348
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011349 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011350}
11351
11352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011353Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11354 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011355 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356 // Iterate the heap looking for SharedFunctionInfo generated from the
11357 // script. The inner most SharedFunctionInfo containing the source position
11358 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011359 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011360 // which is found is not compiled it is compiled and the heap is iterated
11361 // again as the compilation might create inner functions from the newly
11362 // compiled function and the actual requested break point might be in one of
11363 // these functions.
11364 bool done = false;
11365 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011366 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011367 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011368 while (!done) {
11369 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011370 for (HeapObject* obj = iterator.next();
11371 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011372 if (obj->IsSharedFunctionInfo()) {
11373 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11374 if (shared->script() == *script) {
11375 // If the SharedFunctionInfo found has the requested script data and
11376 // contains the source position it is a candidate.
11377 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011378 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011379 start_position = shared->start_position();
11380 }
11381 if (start_position <= position &&
11382 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011383 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011384 // candidate this is the new candidate.
11385 if (target.is_null()) {
11386 target_start_position = start_position;
11387 target = shared;
11388 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011389 if (target_start_position == start_position &&
11390 shared->end_position() == target->end_position()) {
11391 // If a top-level function contain only one function
11392 // declartion the source for the top-level and the function is
11393 // the same. In that case prefer the non top-level function.
11394 if (!shared->is_toplevel()) {
11395 target_start_position = start_position;
11396 target = shared;
11397 }
11398 } else if (target_start_position <= start_position &&
11399 shared->end_position() <= target->end_position()) {
11400 // This containment check includes equality as a function inside
11401 // a top-level function can share either start or end position
11402 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011403 target_start_position = start_position;
11404 target = shared;
11405 }
11406 }
11407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011408 }
11409 }
11410 }
11411
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011412 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011413 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011414 }
11415
11416 // If the candidate found is compiled we are done. NOTE: when lazy
11417 // compilation of inner functions is introduced some additional checking
11418 // needs to be done here to compile inner functions.
11419 done = target->is_compiled();
11420 if (!done) {
11421 // If the candidate is not compiled compile it to reveal any inner
11422 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011423 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 }
11425 }
11426
11427 return *target;
11428}
11429
11430
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011431// Changes the state of a break point in a script and returns source position
11432// where break point was set. NOTE: Regarding performance see the NOTE for
11433// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011434// args[0]: script to set break point in
11435// args[1]: number: break source position (within the script source)
11436// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011437RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011439 ASSERT(args.length() == 3);
11440 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11441 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11442 RUNTIME_ASSERT(source_position >= 0);
11443 Handle<Object> break_point_object_arg = args.at<Object>(2);
11444
11445 // Get the script from the script wrapper.
11446 RUNTIME_ASSERT(wrapper->value()->IsScript());
11447 Handle<Script> script(Script::cast(wrapper->value()));
11448
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011449 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011450 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011451 if (!result->IsUndefined()) {
11452 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11453 // Find position within function. The script position might be before the
11454 // source position of the first function.
11455 int position;
11456 if (shared->start_position() > source_position) {
11457 position = 0;
11458 } else {
11459 position = source_position - shared->start_position();
11460 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011461 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011462 position += shared->start_position();
11463 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011464 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011465 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466}
11467
11468
11469// Clear a break point
11470// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011471RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011472 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011473 ASSERT(args.length() == 1);
11474 Handle<Object> break_point_object_arg = args.at<Object>(0);
11475
11476 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011477 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011479 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011480}
11481
11482
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011483// Change the state of break on exceptions.
11484// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11485// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011486RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011487 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011488 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011489 RUNTIME_ASSERT(args[0]->IsNumber());
11490 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011491
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011492 // If the number doesn't match an enum value, the ChangeBreakOnException
11493 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011494 ExceptionBreakType type =
11495 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011496 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011497 isolate->debug()->ChangeBreakOnException(type, enable);
11498 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011499}
11500
11501
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011502// Returns the state of break on exceptions
11503// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011504RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011505 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011506 ASSERT(args.length() == 1);
11507 RUNTIME_ASSERT(args[0]->IsNumber());
11508
11509 ExceptionBreakType type =
11510 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011511 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011512 return Smi::FromInt(result);
11513}
11514
11515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011516// Prepare for stepping
11517// args[0]: break id for checking execution state
11518// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011519// args[2]: number of times to perform the step, for step out it is the number
11520// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011521RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011522 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011523 ASSERT(args.length() == 3);
11524 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011525 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011526 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11527 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011528 if (!maybe_check->ToObject(&check)) return maybe_check;
11529 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011531 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011532 }
11533
11534 // Get the step action and check validity.
11535 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11536 if (step_action != StepIn &&
11537 step_action != StepNext &&
11538 step_action != StepOut &&
11539 step_action != StepInMin &&
11540 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011542 }
11543
11544 // Get the number of steps.
11545 int step_count = NumberToInt32(args[2]);
11546 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011547 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011548 }
11549
ager@chromium.orga1645e22009-09-09 19:27:10 +000011550 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011551 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011552
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011553 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11555 step_count);
11556 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011557}
11558
11559
11560// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011561RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011563 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011564 isolate->debug()->ClearStepping();
11565 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011566}
11567
11568
11569// Creates a copy of the with context chain. The copy of the context chain is
11570// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011571static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011572 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011573 Handle<Context> current,
11574 Handle<Context> base) {
11575 // At the end of the chain. Return the base context to link to.
11576 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11577 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011578 }
11579
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011580 // Recursively copy the with and catch contexts.
11581 HandleScope scope(isolate);
11582 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011583 Handle<Context> new_previous =
11584 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011585 Handle<Context> new_current;
11586 if (current->IsCatchContext()) {
11587 Handle<String> name(String::cast(current->extension()));
11588 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11589 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011590 isolate->factory()->NewCatchContext(function,
11591 new_previous,
11592 name,
11593 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011594 } else if (current->IsBlockContext()) {
11595 Handle<SerializedScopeInfo> scope_info(
11596 SerializedScopeInfo::cast(current->extension()));
11597 new_current =
11598 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011599 // Copy context slots.
11600 int num_context_slots = scope_info->NumberOfContextSlots();
11601 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11602 new_current->set(i, current->get(i));
11603 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011604 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011605 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011606 Handle<JSObject> extension(JSObject::cast(current->extension()));
11607 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011608 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011609 }
11610 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011611}
11612
11613
11614// Helper function to find or create the arguments object for
11615// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616static Handle<Object> GetArgumentsObject(Isolate* isolate,
11617 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011618 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011619 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011620 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011621 const ScopeInfo<>* sinfo,
11622 Handle<Context> function_context) {
11623 // Try to find the value of 'arguments' to pass as parameter. If it is not
11624 // found (that is the debugged function does not reference 'arguments' and
11625 // does not support eval) then create an 'arguments' object.
11626 int index;
11627 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011629 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011631 }
11632 }
11633
11634 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011635 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11636 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011639 }
11640 }
11641
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011642 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11643
11644 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011645 Handle<JSObject> arguments =
11646 isolate->factory()->NewArgumentsObject(function, length);
11647 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011648
11649 AssertNoAllocation no_gc;
11650 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011651 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011652 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011653 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011654 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011655 return arguments;
11656}
11657
11658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011659static const char kSourceStr[] =
11660 "(function(arguments,__source__){return eval(__source__);})";
11661
11662
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011663// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011664// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011665// extension part has all the parameters and locals of the function on the
11666// stack frame. A function which calls eval with the code to evaluate is then
11667// compiled in this context and called in this context. As this context
11668// replaces the context of the function on the stack frame a new (empty)
11669// function is created as well to be used as the closure for the context.
11670// This function and the context acts as replacements for the function on the
11671// stack frame presenting the same view of the values of parameters and
11672// local variables as if the piece of JavaScript was evaluated at the point
11673// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011674RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011676
11677 // Check the execution state and decode arguments frame and source to be
11678 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011679 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011680 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011681 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11682 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011683 if (!maybe_check_result->ToObject(&check_result)) {
11684 return maybe_check_result;
11685 }
11686 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011687 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011688 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11689 CONVERT_ARG_CHECKED(String, source, 3);
11690 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11691 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011692
11693 // Handle the processing of break.
11694 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011695
11696 // Get the frame where the debugging is performed.
11697 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011698 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011699 JavaScriptFrame* frame = it.frame();
11700 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011701 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011702 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011703
11704 // Traverse the saved contexts chain to find the active context for the
11705 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011706 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011707 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011708 save = save->prev();
11709 }
11710 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011711 SaveContext savex(isolate);
11712 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011713
11714 // Create the (empty) function replacing the function on the stack frame for
11715 // the purpose of evaluating in the context created below. It is important
11716 // that this function does not describe any parameters and local variables
11717 // in the context. If it does then this will cause problems with the lookup
11718 // in Context::Lookup, where context slots for parameters and local variables
11719 // are looked at before the extension object.
11720 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011721 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11722 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011723 go_between->set_context(function->context());
11724#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011725 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011726 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11727 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11728#endif
11729
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011730 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011731 Handle<JSObject> local_scope = MaterializeLocalScope(
11732 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011733 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011734
11735 // Allocate a new context for the debug evaluation and set the extension
11736 // object build.
11737 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011738 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11739 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011740 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011741 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011742 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011743 Handle<Context> function_context;
11744 // Get the function's context if it has one.
11745 if (scope_info->HasHeapAllocatedLocals()) {
11746 function_context = Handle<Context>(frame_context->declaration_context());
11747 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011748 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011749
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011750 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011751 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011752 context =
11753 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011754 }
11755
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756 // Wrap the evaluation statement in a new function compiled in the newly
11757 // created context. The function has one parameter which has to be called
11758 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011759 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011763 isolate->factory()->NewStringFromAscii(
11764 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011765
11766 // Currently, the eval code will be executed in non-strict mode,
11767 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011768 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011769 Compiler::CompileEval(function_source,
11770 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011771 context->IsGlobalContext(),
11772 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011773 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011775 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011776
11777 // Invoke the result of the compilation to get the evaluation function.
11778 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011779 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011780 Handle<Object> evaluation_function =
11781 Execution::Call(compiled_function, receiver, 0, NULL,
11782 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011783 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011785 Handle<Object> arguments = GetArgumentsObject(isolate,
11786 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011787 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011788 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789
11790 // Invoke the evaluation function and return the result.
11791 const int argc = 2;
11792 Object** argv[argc] = { arguments.location(),
11793 Handle<Object>::cast(source).location() };
11794 Handle<Object> result =
11795 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11796 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011797 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011798
11799 // Skip the global proxy as it has no properties and always delegates to the
11800 // real global object.
11801 if (result->IsJSGlobalProxy()) {
11802 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11803 }
11804
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011805 return *result;
11806}
11807
11808
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011809RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011810 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811
11812 // Check the execution state and decode arguments frame and source to be
11813 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011814 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011815 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011816 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11817 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011818 if (!maybe_check_result->ToObject(&check_result)) {
11819 return maybe_check_result;
11820 }
11821 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011822 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011823 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011824 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011825
11826 // Handle the processing of break.
11827 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011828
11829 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011830 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011831 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011833 top = top->prev();
11834 }
11835 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011836 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011837 }
11838
11839 // Get the global context now set to the top context from before the
11840 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011841 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011842
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011843 bool is_global = true;
11844
11845 if (additional_context->IsJSObject()) {
11846 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011847 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11848 isolate->factory()->empty_string(),
11849 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011850 go_between->set_context(*context);
11851 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011852 isolate->factory()->NewFunctionContext(
11853 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011854 context->set_extension(JSObject::cast(*additional_context));
11855 is_global = false;
11856 }
11857
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011858 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011859 // Currently, the eval code will be executed in non-strict mode,
11860 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011861 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011862 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011863 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011864 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011865 Handle<JSFunction>(
11866 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11867 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011868
11869 // Invoke the result of the compilation to get the evaluation function.
11870 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011871 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011872 Handle<Object> result =
11873 Execution::Call(compiled_function, receiver, 0, NULL,
11874 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011875 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011876 return *result;
11877}
11878
11879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011880RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011881 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011882 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011884 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011885 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011886
11887 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011888 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011889 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11890 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11891 // because using
11892 // instances->set(i, *GetScriptWrapper(script))
11893 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11894 // already have deferenced the instances handle.
11895 Handle<JSValue> wrapper = GetScriptWrapper(script);
11896 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897 }
11898
11899 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011900 Handle<JSObject> result =
11901 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902 Handle<JSArray>::cast(result)->SetContent(*instances);
11903 return *result;
11904}
11905
11906
11907// Helper function used by Runtime_DebugReferencedBy below.
11908static int DebugReferencedBy(JSObject* target,
11909 Object* instance_filter, int max_references,
11910 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911 JSFunction* arguments_function) {
11912 NoHandleAllocation ha;
11913 AssertNoAllocation no_alloc;
11914
11915 // Iterate the heap.
11916 int count = 0;
11917 JSObject* last = NULL;
11918 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011919 HeapObject* heap_obj = NULL;
11920 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921 (max_references == 0 || count < max_references)) {
11922 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011923 if (heap_obj->IsJSObject()) {
11924 // Skip context extension objects and argument arrays as these are
11925 // checked in the context of functions using them.
11926 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011927 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928 obj->map()->constructor() == arguments_function) {
11929 continue;
11930 }
11931
11932 // Check if the JS object has a reference to the object looked for.
11933 if (obj->ReferencesObject(target)) {
11934 // Check instance filter if supplied. This is normally used to avoid
11935 // references from mirror objects (see Runtime_IsInPrototypeChain).
11936 if (!instance_filter->IsUndefined()) {
11937 Object* V = obj;
11938 while (true) {
11939 Object* prototype = V->GetPrototype();
11940 if (prototype->IsNull()) {
11941 break;
11942 }
11943 if (instance_filter == prototype) {
11944 obj = NULL; // Don't add this object.
11945 break;
11946 }
11947 V = prototype;
11948 }
11949 }
11950
11951 if (obj != NULL) {
11952 // Valid reference found add to instance array if supplied an update
11953 // count.
11954 if (instances != NULL && count < instances_size) {
11955 instances->set(count, obj);
11956 }
11957 last = obj;
11958 count++;
11959 }
11960 }
11961 }
11962 }
11963
11964 // Check for circular reference only. This can happen when the object is only
11965 // referenced from mirrors and has a circular reference in which case the
11966 // object is not really alive and would have been garbage collected if not
11967 // referenced from the mirror.
11968 if (count == 1 && last == target) {
11969 count = 0;
11970 }
11971
11972 // Return the number of referencing objects found.
11973 return count;
11974}
11975
11976
11977// Scan the heap for objects with direct references to an object
11978// args[0]: the object to find references to
11979// args[1]: constructor function for instances to exclude (Mirror)
11980// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011981RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011982 ASSERT(args.length() == 3);
11983
11984 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011985 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986
11987 // Check parameters.
11988 CONVERT_CHECKED(JSObject, target, args[0]);
11989 Object* instance_filter = args[1];
11990 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11991 instance_filter->IsJSObject());
11992 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11993 RUNTIME_ASSERT(max_references >= 0);
11994
11995 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011997 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998 JSFunction* arguments_function =
11999 JSFunction::cast(arguments_boilerplate->map()->constructor());
12000
12001 // Get the number of referencing objects.
12002 int count;
12003 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012004 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005
12006 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012007 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012008 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012009 if (!maybe_object->ToObject(&object)) return maybe_object;
12010 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012011 FixedArray* instances = FixedArray::cast(object);
12012
12013 // Fill the referencing objects.
12014 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012015 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012016
12017 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012018 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012019 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12020 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012021 if (!maybe_result->ToObject(&result)) return maybe_result;
12022 }
12023 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012024 return result;
12025}
12026
12027
12028// Helper function used by Runtime_DebugConstructedBy below.
12029static int DebugConstructedBy(JSFunction* constructor, int max_references,
12030 FixedArray* instances, int instances_size) {
12031 AssertNoAllocation no_alloc;
12032
12033 // Iterate the heap.
12034 int count = 0;
12035 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012036 HeapObject* heap_obj = NULL;
12037 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012038 (max_references == 0 || count < max_references)) {
12039 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012040 if (heap_obj->IsJSObject()) {
12041 JSObject* obj = JSObject::cast(heap_obj);
12042 if (obj->map()->constructor() == constructor) {
12043 // Valid reference found add to instance array if supplied an update
12044 // count.
12045 if (instances != NULL && count < instances_size) {
12046 instances->set(count, obj);
12047 }
12048 count++;
12049 }
12050 }
12051 }
12052
12053 // Return the number of referencing objects found.
12054 return count;
12055}
12056
12057
12058// Scan the heap for objects constructed by a specific function.
12059// args[0]: the constructor to find instances of
12060// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012061RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012062 ASSERT(args.length() == 2);
12063
12064 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012065 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012066
12067 // Check parameters.
12068 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12069 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12070 RUNTIME_ASSERT(max_references >= 0);
12071
12072 // Get the number of referencing objects.
12073 int count;
12074 count = DebugConstructedBy(constructor, max_references, NULL, 0);
12075
12076 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012077 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012078 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012079 if (!maybe_object->ToObject(&object)) return maybe_object;
12080 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012081 FixedArray* instances = FixedArray::cast(object);
12082
12083 // Fill the referencing objects.
12084 count = DebugConstructedBy(constructor, max_references, instances, count);
12085
12086 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012087 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012088 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12089 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012090 if (!maybe_result->ToObject(&result)) return maybe_result;
12091 }
12092 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012093 return result;
12094}
12095
12096
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012097// Find the effective prototype object as returned by __proto__.
12098// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012099RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012100 ASSERT(args.length() == 1);
12101
12102 CONVERT_CHECKED(JSObject, obj, args[0]);
12103
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012104 // Use the __proto__ accessor.
12105 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106}
12107
12108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012109RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012110 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012111 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012112 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012113}
12114
12115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012116RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012117#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012118 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012119 ASSERT(args.length() == 1);
12120 // Get the function and make sure it is compiled.
12121 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012122 Handle<SharedFunctionInfo> shared(func->shared());
12123 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012124 return Failure::Exception();
12125 }
12126 func->code()->PrintLn();
12127#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012128 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012129}
ager@chromium.org9085a012009-05-11 19:22:57 +000012130
12131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012132RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012133#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012134 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012135 ASSERT(args.length() == 1);
12136 // Get the function and make sure it is compiled.
12137 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012138 Handle<SharedFunctionInfo> shared(func->shared());
12139 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012140 return Failure::Exception();
12141 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012142 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012143#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012144 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012145}
12146
12147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012148RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012149 NoHandleAllocation ha;
12150 ASSERT(args.length() == 1);
12151
12152 CONVERT_CHECKED(JSFunction, f, args[0]);
12153 return f->shared()->inferred_name();
12154}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012155
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012156
12157static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012158 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012159 AssertNoAllocation no_allocations;
12160
12161 int counter = 0;
12162 int buffer_size = buffer->length();
12163 HeapIterator iterator;
12164 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
12165 ASSERT(obj != NULL);
12166 if (!obj->IsSharedFunctionInfo()) {
12167 continue;
12168 }
12169 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12170 if (shared->script() != script) {
12171 continue;
12172 }
12173 if (counter < buffer_size) {
12174 buffer->set(counter, shared);
12175 }
12176 counter++;
12177 }
12178 return counter;
12179}
12180
12181// For a script finds all SharedFunctionInfo's in the heap that points
12182// to this script. Returns JSArray of SharedFunctionInfo wrapped
12183// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012184RUNTIME_FUNCTION(MaybeObject*,
12185 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012186 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012187 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012188 CONVERT_CHECKED(JSValue, script_value, args[0]);
12189
12190 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12191
12192 const int kBufferSize = 32;
12193
12194 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012195 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012196 int number = FindSharedFunctionInfosForScript(*script, *array);
12197 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012198 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012199 FindSharedFunctionInfosForScript(*script, *array);
12200 }
12201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012202 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012203 result->set_length(Smi::FromInt(number));
12204
12205 LiveEdit::WrapSharedFunctionInfos(result);
12206
12207 return *result;
12208}
12209
12210// For a script calculates compilation information about all its functions.
12211// The script source is explicitly specified by the second argument.
12212// The source of the actual script is not used, however it is important that
12213// all generated code keeps references to this particular instance of script.
12214// Returns a JSArray of compilation infos. The array is ordered so that
12215// each function with all its descendant is always stored in a continues range
12216// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012217RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012218 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012219 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012220 CONVERT_CHECKED(JSValue, script, args[0]);
12221 CONVERT_ARG_CHECKED(String, source, 1);
12222 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12223
12224 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12225
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012226 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012227 return Failure::Exception();
12228 }
12229
12230 return result;
12231}
12232
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012233// Changes the source of the script to a new_source.
12234// If old_script_name is provided (i.e. is a String), also creates a copy of
12235// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012236RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012237 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012238 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012239 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12240 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012241 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012242
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012243 CONVERT_CHECKED(Script, original_script_pointer,
12244 original_script_value->value());
12245 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012246
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012247 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12248 new_source,
12249 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012250
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012251 if (old_script->IsScript()) {
12252 Handle<Script> script_handle(Script::cast(old_script));
12253 return *(GetScriptWrapper(script_handle));
12254 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012255 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012256 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012257}
12258
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012260RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012261 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012262 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012263 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12264 return LiveEdit::FunctionSourceUpdated(shared_info);
12265}
12266
12267
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012268// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012269RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012270 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012271 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012272 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12273 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12274
ager@chromium.orgac091b72010-05-05 07:34:42 +000012275 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012276}
12277
12278// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012279RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012280 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012281 HandleScope scope(isolate);
12282 Handle<Object> function_object(args[0], isolate);
12283 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012284
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012285 if (function_object->IsJSValue()) {
12286 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12287 if (script_object->IsJSValue()) {
12288 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012289 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012290 }
12291
12292 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12293 } else {
12294 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12295 // and we check it in this function.
12296 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012298 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012299}
12300
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012301
12302// In a code of a parent function replaces original function as embedded object
12303// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012304RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012305 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012306 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012307
12308 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12309 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12310 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12311
12312 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12313 subst_wrapper);
12314
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012315 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012316}
12317
12318
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012319// Updates positions of a shared function info (first parameter) according
12320// to script source change. Text change is described in second parameter as
12321// array of groups of 3 numbers:
12322// (change_begin, change_end, change_end_new_position).
12323// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012324RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012325 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012326 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012327 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12328 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12329
ager@chromium.orgac091b72010-05-05 07:34:42 +000012330 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012331}
12332
12333
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012334// For array of SharedFunctionInfo's (each wrapped in JSValue)
12335// checks that none of them have activations on stacks (of any thread).
12336// Returns array of the same length with corresponding results of
12337// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012338RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012339 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012340 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012341 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012342 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012343
ager@chromium.org357bf652010-04-12 11:30:10 +000012344 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012345}
12346
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012347// Compares 2 strings line-by-line, then token-wise and returns diff in form
12348// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12349// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012350RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012351 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012352 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012353 CONVERT_ARG_CHECKED(String, s1, 0);
12354 CONVERT_ARG_CHECKED(String, s2, 1);
12355
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012356 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012357}
12358
12359
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012360// A testing entry. Returns statement position which is the closest to
12361// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012362RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012363 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012364 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012365 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12366 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012368 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012369
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012370 if (code->kind() != Code::FUNCTION &&
12371 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012372 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012373 }
12374
12375 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012376 int closest_pc = 0;
12377 int distance = kMaxInt;
12378 while (!it.done()) {
12379 int statement_position = static_cast<int>(it.rinfo()->data());
12380 // Check if this break point is closer that what was previously found.
12381 if (source_position <= statement_position &&
12382 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012383 closest_pc =
12384 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012385 distance = statement_position - source_position;
12386 // Check whether we can't get any closer.
12387 if (distance == 0) break;
12388 }
12389 it.next();
12390 }
12391
12392 return Smi::FromInt(closest_pc);
12393}
12394
12395
ager@chromium.org357bf652010-04-12 11:30:10 +000012396// Calls specified function with or without entering the debugger.
12397// This is used in unit tests to run code as if debugger is entered or simply
12398// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012399RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012400 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012401 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012402 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12403 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12404
12405 Handle<Object> result;
12406 bool pending_exception;
12407 {
12408 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012409 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012410 &pending_exception);
12411 } else {
12412 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012413 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012414 &pending_exception);
12415 }
12416 }
12417 if (!pending_exception) {
12418 return *result;
12419 } else {
12420 return Failure::Exception();
12421 }
12422}
12423
12424
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012425// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012426RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012427 CONVERT_CHECKED(String, arg, args[0]);
12428 SmartPointer<char> flags =
12429 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12430 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012431 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012432}
12433
12434
12435// Performs a GC.
12436// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012437RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012438 isolate->heap()->CollectAllGarbage(true);
12439 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012440}
12441
12442
12443// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012444RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012445 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012446 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012447 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012448 }
12449 return Smi::FromInt(usage);
12450}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012451
12452
12453// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012454RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012455#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012456 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012457#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012458 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012459#endif
12460}
12461
12462
12463// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012464RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012465#ifdef LIVE_OBJECT_LIST
12466 return LiveObjectList::Capture();
12467#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012468 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012469#endif
12470}
12471
12472
12473// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012474RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012475#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012476 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012477 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012478 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012479#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012481#endif
12482}
12483
12484
12485// Generates the response to a debugger request for a dump of the objects
12486// contained in the difference between the captured live object lists
12487// specified by id1 and id2.
12488// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12489// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012490RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012491#ifdef LIVE_OBJECT_LIST
12492 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012493 CONVERT_SMI_ARG_CHECKED(id1, 0);
12494 CONVERT_SMI_ARG_CHECKED(id2, 1);
12495 CONVERT_SMI_ARG_CHECKED(start, 2);
12496 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012497 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12498 EnterDebugger enter_debugger;
12499 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12500#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012501 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012502#endif
12503}
12504
12505
12506// Gets the specified object as requested by the debugger.
12507// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012508RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012509#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012510 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012511 Object* result = LiveObjectList::GetObj(obj_id);
12512 return result;
12513#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012514 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012515#endif
12516}
12517
12518
12519// Gets the obj id for the specified address if valid.
12520// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012521RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012522#ifdef LIVE_OBJECT_LIST
12523 HandleScope scope;
12524 CONVERT_ARG_CHECKED(String, address, 0);
12525 Object* result = LiveObjectList::GetObjId(address);
12526 return result;
12527#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012528 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012529#endif
12530}
12531
12532
12533// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012534RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012535#ifdef LIVE_OBJECT_LIST
12536 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012537 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012538 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12539 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12540 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12541 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12542 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12543
12544 Handle<JSObject> instance_filter;
12545 if (args[1]->IsJSObject()) {
12546 instance_filter = args.at<JSObject>(1);
12547 }
12548 bool verbose = false;
12549 if (args[2]->IsBoolean()) {
12550 verbose = args[2]->IsTrue();
12551 }
12552 int start = 0;
12553 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012554 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012555 }
12556 int limit = Smi::kMaxValue;
12557 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012558 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012559 }
12560
12561 return LiveObjectList::GetObjRetainers(obj_id,
12562 instance_filter,
12563 verbose,
12564 start,
12565 limit,
12566 filter_obj);
12567#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012568 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012569#endif
12570}
12571
12572
12573// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012574RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012575#ifdef LIVE_OBJECT_LIST
12576 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012577 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12578 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012579 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12580
12581 Handle<JSObject> instance_filter;
12582 if (args[2]->IsJSObject()) {
12583 instance_filter = args.at<JSObject>(2);
12584 }
12585
12586 Object* result =
12587 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12588 return result;
12589#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012590 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012591#endif
12592}
12593
12594
12595// Generates the response to a debugger request for a list of all
12596// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012597RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012598#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012599 CONVERT_SMI_ARG_CHECKED(start, 0);
12600 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012601 return LiveObjectList::Info(start, count);
12602#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012603 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012604#endif
12605}
12606
12607
12608// Gets a dump of the specified object as requested by the debugger.
12609// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012610RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012611#ifdef LIVE_OBJECT_LIST
12612 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012613 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012614 Object* result = LiveObjectList::PrintObj(obj_id);
12615 return result;
12616#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012617 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012618#endif
12619}
12620
12621
12622// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012623RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012624#ifdef LIVE_OBJECT_LIST
12625 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012626 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012627#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012628 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012629#endif
12630}
12631
12632
12633// Generates the response to a debugger request for a summary of the types
12634// of objects in the difference between the captured live object lists
12635// specified by id1 and id2.
12636// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12637// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012638RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012639#ifdef LIVE_OBJECT_LIST
12640 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012641 CONVERT_SMI_ARG_CHECKED(id1, 0);
12642 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012643 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12644
12645 EnterDebugger enter_debugger;
12646 return LiveObjectList::Summarize(id1, id2, filter_obj);
12647#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012648 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012649#endif
12650}
12651
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012652#endif // ENABLE_DEBUGGER_SUPPORT
12653
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012655RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012656 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012657 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012658 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012659}
12660
12661
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012662RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012663 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012664 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012665 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012666}
12667
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012669// Finds the script object from the script data. NOTE: This operation uses
12670// heap traversal to find the function generated for the source position
12671// for the requested break point. For lazily compiled functions several heap
12672// traversals might be required rendering this operation as a rather slow
12673// operation. However for setting break points which is normally done through
12674// some kind of user interaction the performance is not crucial.
12675static Handle<Object> Runtime_GetScriptFromScriptName(
12676 Handle<String> script_name) {
12677 // Scan the heap for Script objects to find the script with the requested
12678 // script data.
12679 Handle<Script> script;
12680 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012681 HeapObject* obj = NULL;
12682 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012683 // If a script is found check if it has the script data requested.
12684 if (obj->IsScript()) {
12685 if (Script::cast(obj)->name()->IsString()) {
12686 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12687 script = Handle<Script>(Script::cast(obj));
12688 }
12689 }
12690 }
12691 }
12692
12693 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012694 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012695
12696 // Return the script found.
12697 return GetScriptWrapper(script);
12698}
12699
12700
12701// Get the script object from script data. NOTE: Regarding performance
12702// see the NOTE for GetScriptFromScriptData.
12703// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012704RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012705 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012706
12707 ASSERT(args.length() == 1);
12708
12709 CONVERT_CHECKED(String, script_name, args[0]);
12710
12711 // Find the requested script.
12712 Handle<Object> result =
12713 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12714 return *result;
12715}
12716
12717
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012718// Determines whether the given stack frame should be displayed in
12719// a stack trace. The caller is the error constructor that asked
12720// for the stack trace to be collected. The first time a construct
12721// call to this function is encountered it is skipped. The seen_caller
12722// in/out parameter is used to remember if the caller has been seen
12723// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012724static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12725 Object* caller,
12726 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012727 // Only display JS frames.
12728 if (!raw_frame->is_java_script())
12729 return false;
12730 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12731 Object* raw_fun = frame->function();
12732 // Not sure when this can happen but skip it just in case.
12733 if (!raw_fun->IsJSFunction())
12734 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012735 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012736 *seen_caller = true;
12737 return false;
12738 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012739 // Skip all frames until we've seen the caller.
12740 if (!(*seen_caller)) return false;
12741 // Also, skip the most obvious builtin calls. We recognize builtins
12742 // as (1) functions called with the builtins object as the receiver and
12743 // as (2) functions from native scripts called with undefined as the
12744 // receiver (direct calls to helper functions in the builtins
12745 // code). Some builtin calls (such as Number.ADD which is invoked
12746 // using 'call') are very difficult to recognize so we're leaving
12747 // them in for now.
12748 if (frame->receiver()->IsJSBuiltinsObject()) {
12749 return false;
12750 }
12751 JSFunction* fun = JSFunction::cast(raw_fun);
12752 Object* raw_script = fun->shared()->script();
12753 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12754 int script_type = Script::cast(raw_script)->type()->value();
12755 return script_type != Script::TYPE_NATIVE;
12756 }
12757 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012758}
12759
12760
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012761// Collect the raw data for a stack trace. Returns an array of 4
12762// element segments each containing a receiver, function, code and
12763// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012764RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012765 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012766 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012767 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12768
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012769 HandleScope scope(isolate);
12770 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012771
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012772 limit = Max(limit, 0); // Ensure that limit is not negative.
12773 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012774 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012775 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012776
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012777 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012778 // If the caller parameter is a function we skip frames until we're
12779 // under it before starting to collect.
12780 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012781 int cursor = 0;
12782 int frames_seen = 0;
12783 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012784 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012785 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012786 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012787 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012788 // Set initial size to the maximum inlining level + 1 for the outermost
12789 // function.
12790 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012791 frame->Summarize(&frames);
12792 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012793 if (cursor + 4 > elements->length()) {
12794 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12795 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012796 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012797 for (int i = 0; i < cursor; i++) {
12798 new_elements->set(i, elements->get(i));
12799 }
12800 elements = new_elements;
12801 }
12802 ASSERT(cursor + 4 <= elements->length());
12803
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012804 Handle<Object> recv = frames[i].receiver();
12805 Handle<JSFunction> fun = frames[i].function();
12806 Handle<Code> code = frames[i].code();
12807 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012808 elements->set(cursor++, *recv);
12809 elements->set(cursor++, *fun);
12810 elements->set(cursor++, *code);
12811 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012812 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012813 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012814 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012815 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012816 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012817 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012818 return *result;
12819}
12820
12821
ager@chromium.org3811b432009-10-28 14:53:37 +000012822// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012823RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012824 ASSERT_EQ(args.length(), 0);
12825
12826 NoHandleAllocation ha;
12827
12828 const char* version_string = v8::V8::GetVersion();
12829
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012830 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12831 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012832}
12833
12834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012835RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012836 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012837 OS::PrintError("abort: %s\n",
12838 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012839 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012840 OS::Abort();
12841 UNREACHABLE();
12842 return NULL;
12843}
12844
12845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012846RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012847 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012848 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012849 Object* key = args[1];
12850
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012851 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012852 Object* o = cache->get(finger_index);
12853 if (o == key) {
12854 // The fastest case: hit the same place again.
12855 return cache->get(finger_index + 1);
12856 }
12857
12858 for (int i = finger_index - 2;
12859 i >= JSFunctionResultCache::kEntriesIndex;
12860 i -= 2) {
12861 o = cache->get(i);
12862 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012863 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012864 return cache->get(i + 1);
12865 }
12866 }
12867
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012868 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012869 ASSERT(size <= cache->length());
12870
12871 for (int i = size - 2; i > finger_index; i -= 2) {
12872 o = cache->get(i);
12873 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012874 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012875 return cache->get(i + 1);
12876 }
12877 }
12878
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012879 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012880 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012881
12882 Handle<JSFunctionResultCache> cache_handle(cache);
12883 Handle<Object> key_handle(key);
12884 Handle<Object> value;
12885 {
12886 Handle<JSFunction> factory(JSFunction::cast(
12887 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12888 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012889 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012890 // This handle is nor shared, nor used later, so it's safe.
12891 Object** argv[] = { key_handle.location() };
12892 bool pending_exception = false;
12893 value = Execution::Call(factory,
12894 receiver,
12895 1,
12896 argv,
12897 &pending_exception);
12898 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012899 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012900
12901#ifdef DEBUG
12902 cache_handle->JSFunctionResultCacheVerify();
12903#endif
12904
12905 // Function invocation may have cleared the cache. Reread all the data.
12906 finger_index = cache_handle->finger_index();
12907 size = cache_handle->size();
12908
12909 // If we have spare room, put new data into it, otherwise evict post finger
12910 // entry which is likely to be the least recently used.
12911 int index = -1;
12912 if (size < cache_handle->length()) {
12913 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12914 index = size;
12915 } else {
12916 index = finger_index + JSFunctionResultCache::kEntrySize;
12917 if (index == cache_handle->length()) {
12918 index = JSFunctionResultCache::kEntriesIndex;
12919 }
12920 }
12921
12922 ASSERT(index % 2 == 0);
12923 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12924 ASSERT(index < cache_handle->length());
12925
12926 cache_handle->set(index, *key_handle);
12927 cache_handle->set(index + 1, *value);
12928 cache_handle->set_finger_index(index);
12929
12930#ifdef DEBUG
12931 cache_handle->JSFunctionResultCacheVerify();
12932#endif
12933
12934 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012935}
12936
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012938RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012939 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012940 CONVERT_ARG_CHECKED(String, type, 0);
12941 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012942 return *isolate->factory()->NewJSMessageObject(
12943 type,
12944 arguments,
12945 0,
12946 0,
12947 isolate->factory()->undefined_value(),
12948 isolate->factory()->undefined_value(),
12949 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012950}
12951
12952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012953RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012954 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12955 return message->type();
12956}
12957
12958
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012959RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012960 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12961 return message->arguments();
12962}
12963
12964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012965RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012966 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12967 return Smi::FromInt(message->start_position());
12968}
12969
12970
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012971RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012972 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12973 return message->script();
12974}
12975
12976
kasper.lund44510672008-07-25 07:37:58 +000012977#ifdef DEBUG
12978// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12979// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012980RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012981 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012982 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012983#define COUNT_ENTRY(Name, argc, ressize) + 1
12984 int entry_count = 0
12985 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12986 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12987 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12988#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012989 Factory* factory = isolate->factory();
12990 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012991 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012992 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012993#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012994 { \
12995 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012996 Handle<String> name; \
12997 /* Inline runtime functions have an underscore in front of the name. */ \
12998 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012999 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013000 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13001 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013002 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013003 Vector<const char>(#Name, StrLength(#Name))); \
13004 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013005 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013006 pair_elements->set(0, *name); \
13007 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013008 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013009 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013010 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013011 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013012 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013013 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013014 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013015 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013016#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013017 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013018 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013019 return *result;
13020}
kasper.lund44510672008-07-25 07:37:58 +000013021#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013022
13023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013024RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013025 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013026 CONVERT_CHECKED(String, format, args[0]);
13027 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013028 String::FlatContent format_content = format->GetFlatContent();
13029 RUNTIME_ASSERT(format_content.IsAscii());
13030 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013031 LOGGER->LogRuntime(chars, elms);
13032 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013033}
13034
13035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013036RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013037 UNREACHABLE(); // implemented as macro in the parser
13038 return NULL;
13039}
13040
13041
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013042#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13043 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13044 CONVERT_CHECKED(JSObject, obj, args[0]); \
13045 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13046 }
13047
13048ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13049ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13050ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13051ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13052ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13053ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13054ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13055ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13056ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13057ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13058ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13059ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13060ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13061
13062#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013064// ----------------------------------------------------------------------------
13065// Implementation of Runtime
13066
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013067#define F(name, number_of_args, result_size) \
13068 { Runtime::k##name, Runtime::RUNTIME, #name, \
13069 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013070
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013071
13072#define I(name, number_of_args, result_size) \
13073 { Runtime::kInline##name, Runtime::INLINE, \
13074 "_" #name, NULL, number_of_args, result_size },
13075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013076static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013077 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013078 INLINE_FUNCTION_LIST(I)
13079 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013080};
13081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013083MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13084 Object* dictionary) {
13085 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013086 ASSERT(dictionary != NULL);
13087 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13088 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013089 Object* name_symbol;
13090 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013091 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013092 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13093 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013094 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013095 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13096 String::cast(name_symbol),
13097 Smi::FromInt(i),
13098 PropertyDetails(NONE, NORMAL));
13099 if (!maybe_dictionary->ToObject(&dictionary)) {
13100 // Non-recoverable failure. Calling code must restart heap
13101 // initialization.
13102 return maybe_dictionary;
13103 }
13104 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013105 }
13106 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013107}
13108
13109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013110const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13111 Heap* heap = name->GetHeap();
13112 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013113 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013114 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013115 int function_index = Smi::cast(smi_index)->value();
13116 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013117 }
13118 return NULL;
13119}
13120
13121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013122const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013123 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13124}
13125
13126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013127void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013128 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013129 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013130 if (failure->IsRetryAfterGC()) {
13131 // Try to do a garbage collection; ignore it if it fails. The C
13132 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013133 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013134 } else {
13135 // Handle last resort GC and make sure to allow future allocations
13136 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013137 isolate->counters()->gc_last_resort_from_js()->Increment();
13138 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013139 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013140}
13141
13142
13143} } // namespace v8::internal