blob: 53c048e9a786fa9d4cb0e3c11412fd96f5cc56a6 [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"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000045#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000046#include "liveobjectlist-inl.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000047#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "platform.h"
49#include "runtime.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "runtime-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000052#include "smart-pointer.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000053#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000054#include "v8threads.h"
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000055#include "string-search.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
60
ager@chromium.org3e875802009-06-29 08:26:34 +000061#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000062 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64// Cast the given object to a value of the specified type and store
65// it in a variable with the given name. If the object is not of the
66// expected type call IllegalOperation and return.
67#define CONVERT_CHECKED(Type, name, obj) \
68 RUNTIME_ASSERT(obj->Is##Type()); \
69 Type* name = Type::cast(obj);
70
71#define CONVERT_ARG_CHECKED(Type, name, index) \
72 RUNTIME_ASSERT(args[index]->Is##Type()); \
73 Handle<Type> name = args.at<Type>(index);
74
kasper.lundbd3ec4e2008-07-09 11:06:54 +000075// Cast the given object to a boolean and store it in a variable with
76// the given name. If the object is not a boolean call IllegalOperation
77// and return.
78#define CONVERT_BOOLEAN_CHECKED(name, obj) \
79 RUNTIME_ASSERT(obj->IsBoolean()); \
80 bool name = (obj)->IsTrue();
81
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000082// Cast the given object to a Smi and store its value in an int variable
83// with the given name. If the object is not a Smi call IllegalOperation
84// and return.
85#define CONVERT_SMI_CHECKED(name, obj) \
86 RUNTIME_ASSERT(obj->IsSmi()); \
87 int name = Smi::cast(obj)->value();
88
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000089// Cast the given object to a double and store it in a variable with
90// the given name. If the object is not a number (as opposed to
91// the number not-a-number) call IllegalOperation and return.
92#define CONVERT_DOUBLE_CHECKED(name, obj) \
93 RUNTIME_ASSERT(obj->IsNumber()); \
94 double name = (obj)->Number();
95
96// Call the specified converter on the object *comand store the result in
97// a variable of the specified type with the given name. If the
98// object is not a Number call IllegalOperation and return.
99#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
100 RUNTIME_ASSERT(obj->IsNumber()); \
101 type name = NumberTo##Type(obj);
102
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
105 JSObject* boilerplate) {
106 StackLimitCheck check(isolate);
107 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000110 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000112 if (!maybe_result->ToObject(&result)) return maybe_result;
113 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000114 JSObject* copy = JSObject::cast(result);
115
116 // Deep copy local properties.
117 if (copy->HasFastProperties()) {
118 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 for (int i = 0; i < properties->length(); i++) {
120 Object* value = properties->get(i);
121 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000122 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000123 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 if (!maybe_result->ToObject(&result)) return maybe_result;
125 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000127 }
128 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000129 int nof = copy->map()->inobject_properties();
130 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 Object* value = copy->InObjectPropertyAt(i);
132 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000133 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000134 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000135 if (!maybe_result->ToObject(&result)) return maybe_result;
136 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000138 }
139 }
140 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000141 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000142 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000143 if (!maybe_result->ToObject(&result)) return maybe_result;
144 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 FixedArray* names = FixedArray::cast(result);
146 copy->GetLocalPropertyNames(names, 0);
147 for (int i = 0; i < names->length(); i++) {
148 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000149 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000151 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000152 // Only deep copy fields from the object literal expression.
153 // In particular, don't try to copy the length attribute of
154 // an array.
155 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 Object* value =
157 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
163 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000164 // Creating object copy for literals. No strict mode needed.
165 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000168 }
169 }
170 }
171
172 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000173 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000174 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000175 switch (copy->GetElementsKind()) {
176 case JSObject::FAST_ELEMENTS: {
177 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 if (elements->map() == heap->fixed_cow_array_map()) {
179 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000180#ifdef DEBUG
181 for (int i = 0; i < elements->length(); i++) {
182 ASSERT(!elements->get(i)->IsJSObject());
183 }
184#endif
185 } else {
186 for (int i = 0; i < elements->length(); i++) {
187 Object* value = elements->get(i);
188 if (value->IsJSObject()) {
189 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
191 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000194 elements->set(i, result);
195 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000196 }
197 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000198 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000200 case JSObject::DICTIONARY_ELEMENTS: {
201 NumberDictionary* element_dictionary = copy->element_dictionary();
202 int capacity = element_dictionary->Capacity();
203 for (int i = 0; i < capacity; i++) {
204 Object* k = element_dictionary->KeyAt(i);
205 if (element_dictionary->IsKey(k)) {
206 Object* value = element_dictionary->ValueAt(i);
207 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000213 element_dictionary->ValueAtPut(i, result);
214 }
215 }
216 }
217 break;
218 }
219 default:
220 UNREACHABLE();
221 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000222 }
223 return copy;
224}
225
226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000227RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000228 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000230}
231
232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000233RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000234 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236}
237
238
ager@chromium.org236ad962008-09-25 09:45:57 +0000239static Handle<Map> ComputeObjectLiteralMap(
240 Handle<Context> context,
241 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000242 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000244 int properties_length = constant_properties->length();
245 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000246 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000248 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000249 for (int p = 0; p != properties_length; p += 2) {
250 Object* key = constant_properties->get(p);
251 uint32_t element_index = 0;
252 if (key->IsSymbol()) {
253 number_of_symbol_keys++;
254 } else if (key->ToArrayIndex(&element_index)) {
255 // An index key does not require space in the property backing store.
256 number_of_properties--;
257 } else {
258 // Bail out as a non-symbol non-index key makes caching impossible.
259 // ASSERT to make sure that the if condition after the loop is false.
260 ASSERT(number_of_symbol_keys != number_of_properties);
261 break;
262 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 // If we only have symbols and array indices among keys then we can
265 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000267 if ((number_of_symbol_keys == number_of_properties) &&
268 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000270 Handle<FixedArray> keys =
271 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000272 if (number_of_symbol_keys > 0) {
273 int index = 0;
274 for (int p = 0; p < properties_length; p += 2) {
275 Object* key = constant_properties->get(p);
276 if (key->IsSymbol()) {
277 keys->set(index++, key);
278 }
279 }
280 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
285 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000286 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000287 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000288 Handle<Map>(context->object_function()->initial_map()),
289 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000290}
291
292
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000293static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000295 Handle<FixedArray> literals,
296 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000297
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298
299static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000302 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 bool should_have_fast_elements,
304 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000305 // Get the global context from the literals array. This is the
306 // context in which the function was created and we use the object
307 // function from this context to create the object literal. We do
308 // not use the object function from the current global context
309 // because this might be the object function from another context
310 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 Handle<Context> context =
312 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
313
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 // In case we have function literals, we want the object to be in
315 // slow properties mode for now. We don't go in the map cache because
316 // maps with constant functions can't be shared if the functions are
317 // not the same (which is the common case).
318 bool is_result_from_cache = false;
319 Handle<Map> map = has_function_literal
320 ? Handle<Map>(context->object_function()->initial_map())
321 : ComputeObjectLiteralMap(context,
322 constant_properties,
323 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000326
327 // Normalize the elements of the boilerplate to save space if needed.
328 if (!should_have_fast_elements) NormalizeElements(boilerplate);
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // Add the constant properties to the boilerplate.
331 int length = constant_properties->length();
332 bool should_transform =
333 !is_result_from_cache && boilerplate->HasFastProperties();
334 if (should_transform || has_function_literal) {
335 // Normalize the properties of object to avoid n^2 behavior
336 // when extending the object multiple properties. Indicate the number of
337 // properties to be added.
338 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
339 }
340
341 for (int index = 0; index < length; index +=2) {
342 Handle<Object> key(constant_properties->get(index+0), isolate);
343 Handle<Object> value(constant_properties->get(index+1), isolate);
344 if (value->IsFixedArray()) {
345 // The value contains the constant_properties of a
346 // simple object or array literal.
347 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
348 value = CreateLiteralBoilerplate(isolate, literals, array);
349 if (value.is_null()) return value;
350 }
351 Handle<Object> result;
352 uint32_t element_index = 0;
353 if (key->IsSymbol()) {
354 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
355 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000356 result = SetOwnElement(boilerplate,
357 element_index,
358 value,
359 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000360 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 Handle<String> name(String::cast(*key));
362 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000363 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
364 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000366 } else if (key->ToArrayIndex(&element_index)) {
367 // Array index (uint32).
368 result = SetOwnElement(boilerplate,
369 element_index,
370 value,
371 kNonStrictMode);
372 } else {
373 // Non-uint32 number.
374 ASSERT(key->IsNumber());
375 double num = key->Number();
376 char arr[100];
377 Vector<char> buffer(arr, ARRAY_SIZE(arr));
378 const char* str = DoubleToCString(num, buffer);
379 Handle<String> name =
380 isolate->factory()->NewStringFromAscii(CStrVector(str));
381 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
382 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 // If setting the property on the boilerplate throws an
385 // exception, the exception is converted to an empty handle in
386 // the handle based operations. In that case, we need to
387 // convert back to an exception.
388 if (result.is_null()) return result;
389 }
390
391 // Transform to fast properties if necessary. For object literals with
392 // containing function literals we defer this operation until after all
393 // computed properties have been assigned so that we can generate
394 // constant function properties.
395 if (should_transform && !has_function_literal) {
396 TransformToFastProperties(boilerplate,
397 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000400 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000401}
402
403
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000404static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000406 Handle<FixedArray> literals,
407 Handle<FixedArray> elements) {
408 // Create the JSArray.
409 Handle<JSFunction> constructor(
410 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 const bool is_cow =
414 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000415 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000417
418 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000419 if (is_cow) {
420#ifdef DEBUG
421 // Copy-on-write arrays must be shallow (and simple).
422 for (int i = 0; i < content->length(); i++) {
423 ASSERT(!content->get(i)->IsFixedArray());
424 }
425#endif
426 } else {
427 for (int i = 0; i < content->length(); i++) {
428 if (content->get(i)->IsFixedArray()) {
429 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
432 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (result.is_null()) return result;
435 content->set(i, *result);
436 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000437 }
438 }
439
440 // Set the elements.
441 Handle<JSArray>::cast(object)->SetContent(*content);
442 return object;
443}
444
445
446static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000448 Handle<FixedArray> literals,
449 Handle<FixedArray> array) {
450 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000451 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000453 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 return CreateObjectLiteralBoilerplate(isolate,
455 literals,
456 elements,
457 true,
458 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000459 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 return CreateObjectLiteralBoilerplate(isolate,
461 literals,
462 elements,
463 false,
464 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000465 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 default:
468 UNREACHABLE();
469 return Handle<Object>::null();
470 }
471}
472
473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000474RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000475 // Takes a FixedArray of elements containing the literal elements of
476 // the array literal and produces JSArray with those elements.
477 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000478 // which contains the context from which to get the Array function
479 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000480 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 ASSERT(args.length() == 3);
482 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
483 CONVERT_SMI_CHECKED(literals_index, args[1]);
484 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000486 Handle<Object> object =
487 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000488 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000490 // Update the functions literal and return the boilerplate.
491 literals->set(literals_index, *object);
492 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000493}
494
495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000496RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000498 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000499 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
500 CONVERT_SMI_CHECKED(literals_index, args[1]);
501 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 CONVERT_SMI_CHECKED(flags, args[3]);
503 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
504 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000505
506 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 Handle<Object> boilerplate(literals->get(literals_index), isolate);
508 if (*boilerplate == isolate->heap()->undefined_value()) {
509 boilerplate = CreateObjectLiteralBoilerplate(isolate,
510 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000511 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 should_have_fast_elements,
513 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 if (boilerplate.is_null()) return Failure::Exception();
515 // Update the functions literal and return the boilerplate.
516 literals->set(literals_index, *boilerplate);
517 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000519}
520
521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000522RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000524 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
526 CONVERT_SMI_CHECKED(literals_index, args[1]);
527 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 CONVERT_SMI_CHECKED(flags, args[3]);
529 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
530 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000531
532 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 Handle<Object> boilerplate(literals->get(literals_index), isolate);
534 if (*boilerplate == isolate->heap()->undefined_value()) {
535 boilerplate = CreateObjectLiteralBoilerplate(isolate,
536 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000537 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 should_have_fast_elements,
539 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 if (boilerplate.is_null()) return Failure::Exception();
541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *boilerplate);
543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 ASSERT(args.length() == 3);
551 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
552 CONVERT_SMI_CHECKED(literals_index, args[1]);
553 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000559 if (boilerplate.is_null()) return Failure::Exception();
560 // Update the functions literal and return the boilerplate.
561 literals->set(literals_index, *boilerplate);
562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000564}
565
566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000567RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 ASSERT(args.length() == 3);
570 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
571 CONVERT_SMI_CHECKED(literals_index, args[1]);
572 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
573
574 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 Handle<Object> boilerplate(literals->get(literals_index), isolate);
576 if (*boilerplate == isolate->heap()->undefined_value()) {
577 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000582 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000584 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587}
588
589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000590RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateCatchExtensionObject) {
ager@chromium.org32912102009-01-16 10:38:43 +0000591 ASSERT(args.length() == 2);
592 CONVERT_CHECKED(String, key, args[0]);
593 Object* value = args[1];
594 // Create a catch context extension object.
595 JSFunction* constructor =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000596 isolate->context()->global_context()->
597 context_extension_function();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000598 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 { MaybeObject* maybe_object = isolate->heap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000600 if (!maybe_object->ToObject(&object)) return maybe_object;
601 }
ager@chromium.org32912102009-01-16 10:38:43 +0000602 // Assign the exception value to the catch variable and make sure
603 // that the catch variable is DontDelete.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000604 { MaybeObject* maybe_value =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000605 // Passing non-strict per ECMA-262 5th Ed. 12.14. Catch, bullet #4.
606 JSObject::cast(object)->SetProperty(
607 key, value, DONT_DELETE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000608 if (!maybe_value->ToObject(&value)) return maybe_value;
609 }
ager@chromium.org32912102009-01-16 10:38:43 +0000610 return object;
611}
612
613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000614RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615 NoHandleAllocation ha;
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 return JSObject::cast(obj)->class_name();
620}
621
ager@chromium.org7c537e22008-10-16 08:43:32 +0000622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000623RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 NoHandleAllocation ha;
625 ASSERT(args.length() == 2);
626 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
627 Object* O = args[0];
628 Object* V = args[1];
629 while (true) {
630 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 if (prototype->IsNull()) return isolate->heap()->false_value();
632 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000633 V = prototype;
634 }
635}
636
637
ager@chromium.org9085a012009-05-11 19:22:57 +0000638// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 CONVERT_CHECKED(JSObject, jsobject, args[0]);
643 CONVERT_CHECKED(JSObject, proto, args[1]);
644
645 // Sanity checks. The old prototype (that we are replacing) could
646 // theoretically be null, but if it is not null then check that we
647 // didn't already install a hidden prototype here.
648 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
649 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
650 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
651
652 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000653 Object* map_or_failure;
654 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
655 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
656 return maybe_map_or_failure;
657 }
658 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000659 Map* new_proto_map = Map::cast(map_or_failure);
660
lrn@chromium.org303ada72010-10-27 09:33:13 +0000661 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
662 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
663 return maybe_map_or_failure;
664 }
665 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000666 Map* new_map = Map::cast(map_or_failure);
667
668 // Set proto's prototype to be the old prototype of the object.
669 new_proto_map->set_prototype(jsobject->GetPrototype());
670 proto->set_map(new_proto_map);
671 new_proto_map->set_is_hidden_prototype();
672
673 // Set the object's prototype to proto.
674 new_map->set_prototype(proto);
675 jsobject->set_map(new_map);
676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000678}
679
680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000681RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000683 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000684 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686}
687
688
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000689// Recursively traverses hidden prototypes if property is not found
690static void GetOwnPropertyImplementation(JSObject* obj,
691 String* name,
692 LookupResult* result) {
693 obj->LocalLookupRealNamedProperty(name, result);
694
695 if (!result->IsProperty()) {
696 Object* proto = obj->GetPrototype();
697 if (proto->IsJSObject() &&
698 JSObject::cast(proto)->map()->is_hidden_prototype())
699 GetOwnPropertyImplementation(JSObject::cast(proto),
700 name, result);
701 }
702}
703
704
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000705static bool CheckAccessException(LookupResult* result,
706 v8::AccessType access_type) {
707 if (result->type() == CALLBACKS) {
708 Object* callback = result->GetCallbackObject();
709 if (callback->IsAccessorInfo()) {
710 AccessorInfo* info = AccessorInfo::cast(callback);
711 bool can_access =
712 (access_type == v8::ACCESS_HAS &&
713 (info->all_can_read() || info->all_can_write())) ||
714 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
715 (access_type == v8::ACCESS_SET && info->all_can_write());
716 return can_access;
717 }
718 }
719
720 return false;
721}
722
723
724static bool CheckAccess(JSObject* obj,
725 String* name,
726 LookupResult* result,
727 v8::AccessType access_type) {
728 ASSERT(result->IsProperty());
729
730 JSObject* holder = result->holder();
731 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000733 while (true) {
734 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000736 // Access check callback denied the access, but some properties
737 // can have a special permissions which override callbacks descision
738 // (currently see v8::AccessControl).
739 break;
740 }
741
742 if (current == holder) {
743 return true;
744 }
745
746 current = JSObject::cast(current->GetPrototype());
747 }
748
749 // API callbacks can have per callback access exceptions.
750 switch (result->type()) {
751 case CALLBACKS: {
752 if (CheckAccessException(result, access_type)) {
753 return true;
754 }
755 break;
756 }
757 case INTERCEPTOR: {
758 // If the object has an interceptor, try real named properties.
759 // Overwrite the result to fetch the correct property later.
760 holder->LookupRealNamedProperty(name, result);
761 if (result->IsProperty()) {
762 if (CheckAccessException(result, access_type)) {
763 return true;
764 }
765 }
766 break;
767 }
768 default:
769 break;
770 }
771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000773 return false;
774}
775
776
777// TODO(1095): we should traverse hidden prototype hierachy as well.
778static bool CheckElementAccess(JSObject* obj,
779 uint32_t index,
780 v8::AccessType access_type) {
781 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000783 return false;
784 }
785
786 return true;
787}
788
789
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000790// Enumerator used as indices into the array returned from GetOwnProperty
791enum PropertyDescriptorIndices {
792 IS_ACCESSOR_INDEX,
793 VALUE_INDEX,
794 GETTER_INDEX,
795 SETTER_INDEX,
796 WRITABLE_INDEX,
797 ENUMERABLE_INDEX,
798 CONFIGURABLE_INDEX,
799 DESCRIPTOR_SIZE
800};
801
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000802// Returns an array with the property description:
803// if args[1] is not a property on args[0]
804// returns undefined
805// if args[1] is a data property on args[0]
806// [false, value, Writeable, Enumerable, Configurable]
807// if args[1] is an accessor on args[0]
808// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000809RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000810 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000811 Heap* heap = isolate->heap();
812 HandleScope scope(isolate);
813 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
814 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000815 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000816 CONVERT_ARG_CHECKED(JSObject, obj, 0);
817 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000819 // This could be an element.
820 uint32_t index;
821 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000822 switch (obj->HasLocalElement(index)) {
823 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000825
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000826 case JSObject::STRING_CHARACTER_ELEMENT: {
827 // Special handling of string objects according to ECMAScript 5
828 // 15.5.5.2. Note that this might be a string object with elements
829 // other than the actual string value. This is covered by the
830 // subsequent cases.
831 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
832 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000833 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000836 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 elms->set(WRITABLE_INDEX, heap->false_value());
838 elms->set(ENUMERABLE_INDEX, heap->false_value());
839 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000840 return *desc;
841 }
842
843 case JSObject::INTERCEPTED_ELEMENT:
844 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000845 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000846 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000847 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000848 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000849 elms->set(WRITABLE_INDEX, heap->true_value());
850 elms->set(ENUMERABLE_INDEX, heap->true_value());
851 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 return *desc;
853 }
854
855 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 Handle<JSObject> holder = obj;
857 if (obj->IsJSGlobalProxy()) {
858 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000860 ASSERT(proto->IsJSGlobalObject());
861 holder = Handle<JSObject>(JSObject::cast(proto));
862 }
863 NumberDictionary* dictionary = holder->element_dictionary();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000864 int entry = dictionary->FindEntry(index);
865 ASSERT(entry != NumberDictionary::kNotFound);
866 PropertyDetails details = dictionary->DetailsAt(entry);
867 switch (details.type()) {
868 case CALLBACKS: {
869 // This is an accessor property with getter and/or setter.
870 FixedArray* callbacks =
871 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
874 elms->set(GETTER_INDEX, callbacks->get(0));
875 }
876 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
877 elms->set(SETTER_INDEX, callbacks->get(1));
878 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000879 break;
880 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000881 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000882 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000885 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000886 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000888 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000889 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000890 default:
891 UNREACHABLE();
892 break;
893 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
895 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000896 return *desc;
897 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000898 }
899 }
900
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000903
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000904 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000906 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000907
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000908 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000910 }
911
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000912 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
913 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000914
915 bool is_js_accessor = (result.type() == CALLBACKS) &&
916 (result.GetCallbackObject()->IsFixedArray());
917
918 if (is_js_accessor) {
919 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000921
922 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
923 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
924 elms->set(GETTER_INDEX, structure->get(0));
925 }
926 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
927 elms->set(SETTER_INDEX, structure->get(1));
928 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000929 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
931 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000932
933 PropertyAttributes attrs;
934 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000935 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
937 if (!maybe_value->ToObject(&value)) return maybe_value;
938 }
939 elms->set(VALUE_INDEX, value);
940 }
941
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000942 return *desc;
943}
944
945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000946RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000947 ASSERT(args.length() == 1);
948 CONVERT_CHECKED(JSObject, obj, args[0]);
949 return obj->PreventExtensions();
950}
951
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000953RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000954 ASSERT(args.length() == 1);
955 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000956 if (obj->IsJSGlobalProxy()) {
957 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000959 ASSERT(proto->IsJSGlobalObject());
960 obj = JSObject::cast(proto);
961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 return obj->map()->is_extensible() ? isolate->heap()->true_value()
963 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000964}
965
966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000967RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000970 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
971 CONVERT_ARG_CHECKED(String, pattern, 1);
972 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000973 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
974 if (result.is_null()) return Failure::Exception();
975 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976}
977
978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000979RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000982 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984}
985
986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000987RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988 ASSERT(args.length() == 1);
989 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000990 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992}
993
994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 ASSERT(args.length() == 2);
997 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000999 int index = field->value();
1000 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1001 InstanceType type = templ->map()->instance_type();
1002 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1003 type == OBJECT_TEMPLATE_INFO_TYPE);
1004 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001005 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001006 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1007 } else {
1008 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1009 }
1010 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001015 ASSERT(args.length() == 1);
1016 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001017 Map* old_map = object->map();
1018 bool needs_access_checks = old_map->is_access_check_needed();
1019 if (needs_access_checks) {
1020 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001021 Object* new_map;
1022 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1023 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1024 }
ager@chromium.org32912102009-01-16 10:38:43 +00001025
1026 Map::cast(new_map)->set_is_access_check_needed(false);
1027 object->set_map(Map::cast(new_map));
1028 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001029 return needs_access_checks ? isolate->heap()->true_value()
1030 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001031}
1032
1033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001034RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001037 Map* old_map = object->map();
1038 if (!old_map->is_access_check_needed()) {
1039 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001040 Object* new_map;
1041 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1042 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1043 }
ager@chromium.org32912102009-01-16 10:38:43 +00001044
1045 Map::cast(new_map)->set_is_access_check_needed(true);
1046 object->set_map(Map::cast(new_map));
1047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001048 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001049}
1050
1051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052static Failure* ThrowRedeclarationError(Isolate* isolate,
1053 const char* type,
1054 Handle<String> name) {
1055 HandleScope scope(isolate);
1056 Handle<Object> type_handle =
1057 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 Handle<Object> args[2] = { type_handle, name };
1059 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1061 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001062}
1063
1064
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001065RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001066 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HandleScope scope(isolate);
1068 Handle<GlobalObject> global = Handle<GlobalObject>(
1069 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001070
ager@chromium.org3811b432009-10-28 14:53:37 +00001071 Handle<Context> context = args.at<Context>(0);
1072 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073 bool is_eval = Smi::cast(args[2])->value() == 1;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001074 StrictModeFlag strict_mode =
1075 static_cast<StrictModeFlag>(Smi::cast(args[3])->value());
1076 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077
1078 // Compute the property attributes. According to ECMA-262, section
1079 // 13, page 71, the property must be read-only and
1080 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1081 // property as read-only, so we don't either.
1082 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1083
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 // Traverse the name/value pairs and set the properties.
1085 int length = pairs->length();
1086 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001090
1091 // We have to declare a global const property. To capture we only
1092 // assign to it when evaluating the assignment for "const x =
1093 // <expr>" the initial value is the hole.
1094 bool is_const_property = value->IsTheHole();
1095
1096 if (value->IsUndefined() || is_const_property) {
1097 // Lookup the property in the global object, and don't set the
1098 // value of the variable if the property is already there.
1099 LookupResult lookup;
1100 global->Lookup(*name, &lookup);
1101 if (lookup.IsProperty()) {
1102 // Determine if the property is local by comparing the holder
1103 // against the global object. The information will be used to
1104 // avoid throwing re-declaration errors when declaring
1105 // variables or constants that exist in the prototype chain.
1106 bool is_local = (*global == lookup.holder());
1107 // Get the property attributes and determine if the property is
1108 // read-only.
1109 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1110 bool is_read_only = (attributes & READ_ONLY) != 0;
1111 if (lookup.type() == INTERCEPTOR) {
1112 // If the interceptor says the property is there, we
1113 // just return undefined without overwriting the property.
1114 // Otherwise, we continue to setting the property.
1115 if (attributes != ABSENT) {
1116 // Check if the existing property conflicts with regards to const.
1117 if (is_local && (is_read_only || is_const_property)) {
1118 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 };
1121 // The property already exists without conflicting: Go to
1122 // the next declaration.
1123 continue;
1124 }
1125 // Fall-through and introduce the absent property by using
1126 // SetProperty.
1127 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001128 // For const properties, we treat a callback with this name
1129 // even in the prototype as a conflicting declaration.
1130 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001131 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001132 }
1133 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001134 if (is_local && (is_read_only || is_const_property)) {
1135 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001136 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 }
1138 // The property already exists without conflicting: Go to
1139 // the next declaration.
1140 continue;
1141 }
1142 }
1143 } else {
1144 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001145 Handle<SharedFunctionInfo> shared =
1146 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1149 context,
1150 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 value = function;
1152 }
1153
1154 LookupResult lookup;
1155 global->LocalLookup(*name, &lookup);
1156
1157 PropertyAttributes attributes = is_const_property
1158 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1159 : base;
1160
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001161 // There's a local property that we need to overwrite because
1162 // we're either declaring a function or there's an interceptor
1163 // that claims the property is absent.
1164 //
1165 // Check for conflicting re-declarations. We cannot have
1166 // conflicting types in case of intercepted properties because
1167 // they are absent.
1168 if (lookup.IsProperty() &&
1169 (lookup.type() != INTERCEPTOR) &&
1170 (lookup.IsReadOnly() || is_const_property)) {
1171 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001175 // Safari does not allow the invocation of callback setters for
1176 // function declarations. To mimic this behavior, we do not allow
1177 // the invocation of setters for function values. This makes a
1178 // difference for global functions with the same names as event
1179 // handlers such as "function onload() {}". Firefox does call the
1180 // onload setter in those case and Safari does not. We follow
1181 // Safari for compatibility.
1182 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001183 // Do not change DONT_DELETE to false from true.
1184 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1185 attributes = static_cast<PropertyAttributes>(
1186 attributes | (lookup.GetAttributes() & DONT_DELETE));
1187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001188 RETURN_IF_EMPTY_HANDLE(isolate,
1189 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001190 name,
1191 value,
1192 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 RETURN_IF_EMPTY_HANDLE(isolate,
1195 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001196 name,
1197 value,
1198 attributes,
1199 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001200 }
1201 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 ASSERT(!isolate->has_pending_exception());
1204 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205}
1206
1207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001208RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001210 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211
ager@chromium.org7c537e22008-10-16 08:43:32 +00001212 CONVERT_ARG_CHECKED(Context, context, 0);
1213 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +00001215 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001216 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001217 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218
1219 // Declarations are always done in the function context.
1220 context = Handle<Context>(context->fcontext());
1221
1222 int index;
1223 PropertyAttributes attributes;
1224 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001225 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 context->Lookup(name, flags, &index, &attributes);
1227
1228 if (attributes != ABSENT) {
1229 // The name was declared before; check for conflicting
1230 // re-declarations: This is similar to the code in parser.cc in
1231 // the AstBuildingParser::Declare function.
1232 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1233 // Functions are not read-only.
1234 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1235 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 }
1238
1239 // Initialize it if necessary.
1240 if (*initial_value != NULL) {
1241 if (index >= 0) {
1242 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001243 // the function context or the arguments object.
1244 if (holder->IsContext()) {
1245 ASSERT(holder.is_identical_to(context));
1246 if (((attributes & READ_ONLY) == 0) ||
1247 context->get(index)->IsTheHole()) {
1248 context->set(index, *initial_value);
1249 }
1250 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001251 // The holder is an arguments object.
1252 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001253 Handle<Object> result = SetElement(arguments, index, initial_value,
1254 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001255 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 }
1257 } else {
1258 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001259 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001260 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001262 SetProperty(context_ext, name, initial_value,
1263 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 }
1265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001268 // The property is not in the function context. It needs to be
1269 // "declared" in the function context's extension context, or in the
1270 // global context.
1271 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001272 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001273 // The function context's extension context exists - use it.
1274 context_ext = Handle<JSObject>(context->extension());
1275 } else {
1276 // The function context's extension context does not exists - allocate
1277 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 context_ext = isolate->factory()->NewJSObject(
1279 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001280 // And store it in the extension slot.
1281 context->set_extension(*context_ext);
1282 }
1283 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284
ager@chromium.org7c537e22008-10-16 08:43:32 +00001285 // Declare the property by setting it to the initial value if provided,
1286 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1287 // constant declarations).
1288 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001290 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001291 // Declaring a const context slot is a conflicting declaration if
1292 // there is a callback with that name in a prototype. It is
1293 // allowed to introduce const variables in
1294 // JSContextExtensionObjects. They are treated specially in
1295 // SetProperty and no setters are invoked for those since they are
1296 // not real JSObjects.
1297 if (initial_value->IsTheHole() &&
1298 !context_ext->IsJSContextExtensionObject()) {
1299 LookupResult lookup;
1300 context_ext->Lookup(*name, &lookup);
1301 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001302 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001303 }
1304 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001305 RETURN_IF_EMPTY_HANDLE(isolate,
1306 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001307 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001308 }
1309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001314RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001316 // args[0] == name
1317 // args[1] == strict_mode
1318 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 // Determine if we need to assign to the variable if it already
1321 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001322 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1323 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324
1325 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 RUNTIME_ASSERT(args[1]->IsSmi());
1328 StrictModeFlag strict_mode =
1329 static_cast<StrictModeFlag>(Smi::cast(args[1])->value());
1330 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
1332 // According to ECMA-262, section 12.2, page 62, the property must
1333 // not be deletable.
1334 PropertyAttributes attributes = DONT_DELETE;
1335
1336 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001337 // there, there is a property with this name in the prototype chain.
1338 // We follow Safari and Firefox behavior and only set the property
1339 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001340 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001341 // Note that objects can have hidden prototypes, so we need to traverse
1342 // the whole chain of hidden prototypes to do a 'local' lookup.
1343 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001345 while (true) {
1346 real_holder->LocalLookup(*name, &lookup);
1347 if (lookup.IsProperty()) {
1348 // Determine if this is a redeclaration of something read-only.
1349 if (lookup.IsReadOnly()) {
1350 // If we found readonly property on one of hidden prototypes,
1351 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001352 if (real_holder != isolate->context()->global()) break;
1353 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001354 }
1355
1356 // Determine if this is a redeclaration of an intercepted read-only
1357 // property and figure out if the property exists at all.
1358 bool found = true;
1359 PropertyType type = lookup.type();
1360 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001361 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001362 Handle<JSObject> holder(real_holder);
1363 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1364 real_holder = *holder;
1365 if (intercepted == ABSENT) {
1366 // The interceptor claims the property isn't there. We need to
1367 // make sure to introduce it.
1368 found = false;
1369 } else if ((intercepted & READ_ONLY) != 0) {
1370 // The property is present, but read-only. Since we're trying to
1371 // overwrite it with a variable declaration we must throw a
1372 // re-declaration error. However if we found readonly property
1373 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 if (real_holder != isolate->context()->global()) break;
1375 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001376 }
1377 }
1378
1379 if (found && !assign) {
1380 // The global property is there and we're not assigning any value
1381 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001382 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001383 }
1384
1385 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001387 return real_holder->SetProperty(
1388 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001389 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001390
1391 Object* proto = real_holder->GetPrototype();
1392 if (!proto->IsJSObject())
1393 break;
1394
1395 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1396 break;
1397
1398 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001402 if (assign) {
1403 return global->SetProperty(*name, args[2], attributes, strict_mode);
1404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406}
1407
1408
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001409RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 // All constants are declared with an initial value. The name
1411 // of the constant is the first argument and the initial value
1412 // is the second.
1413 RUNTIME_ASSERT(args.length() == 2);
1414 CONVERT_ARG_CHECKED(String, name, 0);
1415 Handle<Object> value = args.at<Object>(1);
1416
1417 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
1420 // According to ECMA-262, section 12.2, page 62, the property must
1421 // not be deletable. Since it's a const, it must be READ_ONLY too.
1422 PropertyAttributes attributes =
1423 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1424
1425 // Lookup the property locally in the global object. If it isn't
1426 // there, we add the property and take special precautions to always
1427 // add it as a local property even in case of callbacks in the
1428 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001429 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 LookupResult lookup;
1431 global->LocalLookup(*name, &lookup);
1432 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001433 return global->SetLocalPropertyIgnoreAttributes(*name,
1434 *value,
1435 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436 }
1437
1438 // Determine if this is a redeclaration of something not
1439 // read-only. In case the result is hidden behind an interceptor we
1440 // need to ask it for the property attributes.
1441 if (!lookup.IsReadOnly()) {
1442 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 }
1445
1446 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1447
1448 // Throw re-declaration error if the intercepted property is present
1449 // but not read-only.
1450 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 }
1453
1454 // Restore global object from context (in case of GC) and continue
1455 // with setting the value because the property is either absent or
1456 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001457 HandleScope handle_scope(isolate);
1458 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001460 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001461 // property through an interceptor and only do it if it's
1462 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 RETURN_IF_EMPTY_HANDLE(isolate,
1465 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001466 name,
1467 value,
1468 attributes,
1469 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 return *value;
1471 }
1472
1473 // Set the value, but only we're assigning the initial value to a
1474 // constant. For now, we determine this by checking if the
1475 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477 PropertyType type = lookup.type();
1478 if (type == FIELD) {
1479 FixedArray* properties = global->properties();
1480 int index = lookup.GetFieldIndex();
1481 if (properties->get(index)->IsTheHole()) {
1482 properties->set(index, *value);
1483 }
1484 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001485 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1486 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487 }
1488 } else {
1489 // Ignore re-initialization of constants that have already been
1490 // assigned a function value.
1491 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1492 }
1493
1494 // Use the set value as the result of the operation.
1495 return *value;
1496}
1497
1498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001499RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001500 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 ASSERT(args.length() == 3);
1502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504 ASSERT(!value->IsTheHole());
1505 CONVERT_ARG_CHECKED(Context, context, 1);
1506 Handle<String> name(String::cast(args[2]));
1507
1508 // Initializations are always done in the function context.
1509 context = Handle<Context>(context->fcontext());
1510
1511 int index;
1512 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001513 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001514 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 context->Lookup(name, flags, &index, &attributes);
1516
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001517 // In most situations, the property introduced by the const
1518 // declaration should be present in the context extension object.
1519 // However, because declaration and initialization are separate, the
1520 // property might have been deleted (if it was introduced by eval)
1521 // before we reach the initialization point.
1522 //
1523 // Example:
1524 //
1525 // function f() { eval("delete x; const x;"); }
1526 //
1527 // In that case, the initialization behaves like a normal assignment
1528 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001530 // Property was found in a context.
1531 if (holder->IsContext()) {
1532 // The holder cannot be the function context. If it is, there
1533 // should have been a const redeclaration error when declaring
1534 // the const property.
1535 ASSERT(!holder.is_identical_to(context));
1536 if ((attributes & READ_ONLY) == 0) {
1537 Handle<Context>::cast(holder)->set(index, *value);
1538 }
1539 } else {
1540 // The holder is an arguments object.
1541 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001542 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001543 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001544 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001545 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001546 }
1547 return *value;
1548 }
1549
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 // The property could not be found, we introduce it in the global
1551 // context.
1552 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001553 Handle<JSObject> global = Handle<JSObject>(
1554 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001555 // Strict mode not needed (const disallowed in strict mode).
1556 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001557 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001558 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001559 return *value;
1560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001562 // The property was present in a context extension object.
1563 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001565 if (*context_ext == context->extension()) {
1566 // This is the property that was introduced by the const
1567 // declaration. Set it if it hasn't been set before. NOTE: We
1568 // cannot use GetProperty() to get the current value as it
1569 // 'unholes' the value.
1570 LookupResult lookup;
1571 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1572 ASSERT(lookup.IsProperty()); // the property was declared
1573 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1574
1575 PropertyType type = lookup.type();
1576 if (type == FIELD) {
1577 FixedArray* properties = context_ext->properties();
1578 int index = lookup.GetFieldIndex();
1579 if (properties->get(index)->IsTheHole()) {
1580 properties->set(index, *value);
1581 }
1582 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001583 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1584 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001585 }
1586 } else {
1587 // We should not reach here. Any real, named property should be
1588 // either a field or a dictionary slot.
1589 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590 }
1591 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001592 // The property was found in a different context extension object.
1593 // Set it if it is not a read-only property.
1594 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001595 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001596 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001597 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001598 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 return *value;
1603}
1604
1605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001606RUNTIME_FUNCTION(MaybeObject*,
1607 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001608 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001609 ASSERT(args.length() == 2);
1610 CONVERT_ARG_CHECKED(JSObject, object, 0);
1611 CONVERT_SMI_CHECKED(properties, args[1]);
1612 if (object->HasFastProperties()) {
1613 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1614 }
1615 return *object;
1616}
1617
1618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001619RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001621 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001622 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1623 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001624 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001625 // length of a string, i.e. it is always a Smi. We check anyway for security.
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001626 CONVERT_SMI_CHECKED(index, args[2]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001627 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001628 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001629 RUNTIME_ASSERT(index >= 0);
1630 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001631 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001632 Handle<Object> result = RegExpImpl::Exec(regexp,
1633 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001634 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001635 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001636 if (result.is_null()) return Failure::Exception();
1637 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638}
1639
1640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001641RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001642 ASSERT(args.length() == 3);
1643 CONVERT_SMI_CHECKED(elements_count, args[0]);
1644 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001645 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001646 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001647 Object* new_object;
1648 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001650 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1651 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001652 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001653 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1654 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001655 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1656 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001657 {
1658 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001659 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001661 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 }
1663 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001664 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001665 array->set_elements(elements);
1666 array->set_length(Smi::FromInt(elements_count));
1667 // Write in-object properties after the length of the array.
1668 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1669 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1670 return array;
1671}
1672
1673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001674RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001675 AssertNoAllocation no_alloc;
1676 ASSERT(args.length() == 5);
1677 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1678 CONVERT_CHECKED(String, source, args[1]);
1679
1680 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001682
1683 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001685
1686 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001688
1689 Map* map = regexp->map();
1690 Object* constructor = map->constructor();
1691 if (constructor->IsJSFunction() &&
1692 JSFunction::cast(constructor)->initial_map() == map) {
1693 // If we still have the original map, set in-object properties directly.
1694 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1695 // TODO(lrn): Consider skipping write barrier on booleans as well.
1696 // Both true and false should be in oldspace at all times.
1697 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1698 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1699 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1700 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1701 Smi::FromInt(0),
1702 SKIP_WRITE_BARRIER);
1703 return regexp;
1704 }
1705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001706 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001707 PropertyAttributes final =
1708 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1709 PropertyAttributes writable =
1710 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001714 source,
1715 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001716 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001717 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001718 global,
1719 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720 ASSERT(!result->IsFailure());
1721 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001722 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001723 ignoreCase,
1724 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001725 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001727 multiline,
1728 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 ASSERT(!result->IsFailure());
1730 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 Smi::FromInt(0),
1733 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
1735 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001736 return regexp;
1737}
1738
1739
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001740RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001742 ASSERT(args.length() == 1);
1743 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1744 // This is necessary to enable fast checks for absence of elements
1745 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001747 return Smi::FromInt(0);
1748}
1749
1750
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1752 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001753 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001754 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001755 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1756 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1757 Handle<JSFunction> optimized =
1758 isolate->factory()->NewFunction(key,
1759 JS_OBJECT_TYPE,
1760 JSObject::kHeaderSize,
1761 code,
1762 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001763 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001764 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001765 return optimized;
1766}
1767
1768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001769RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001770 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 ASSERT(args.length() == 1);
1772 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1773
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001774 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1775 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1776 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1777 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1778 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1779 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1780 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781
1782 return *holder;
1783}
1784
1785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001787 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 Context* global_context =
1789 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001790 return global_context->global()->global_receiver();
1791}
1792
1793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001794RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001795 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 ASSERT(args.length() == 4);
1797 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
1798 int index = Smi::cast(args[1])->value();
1799 Handle<String> pattern = args.at<String>(2);
1800 Handle<String> flags = args.at<String>(3);
1801
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 // Get the RegExp function from the context in the literals array.
1803 // This is the RegExp function from the context in which the
1804 // function was created. We do not use the RegExp function from the
1805 // current global context because this might be the RegExp function
1806 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001807 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001808 Handle<JSFunction>(
1809 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001810 // Compute the regular expression literal.
1811 bool has_pending_exception;
1812 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001813 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1814 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 return Failure::Exception();
1818 }
1819 literals->set(index, *regexp);
1820 return *regexp;
1821}
1822
1823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001824RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001825 NoHandleAllocation ha;
1826 ASSERT(args.length() == 1);
1827
1828 CONVERT_CHECKED(JSFunction, f, args[0]);
1829 return f->shared()->name();
1830}
1831
1832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001833RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001834 NoHandleAllocation ha;
1835 ASSERT(args.length() == 2);
1836
1837 CONVERT_CHECKED(JSFunction, f, args[0]);
1838 CONVERT_CHECKED(String, name, args[1]);
1839 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001841}
1842
1843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001844RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001845 NoHandleAllocation ha;
1846 ASSERT(args.length() == 1);
1847
1848 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849 Object* obj = f->RemovePrototype();
1850 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001853}
1854
1855
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001856RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001858 ASSERT(args.length() == 1);
1859
1860 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001861 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1862 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863
1864 return *GetScriptWrapper(Handle<Script>::cast(script));
1865}
1866
1867
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001868RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 NoHandleAllocation ha;
1870 ASSERT(args.length() == 1);
1871
1872 CONVERT_CHECKED(JSFunction, f, args[0]);
1873 return f->shared()->GetSourceCode();
1874}
1875
1876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001877RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 NoHandleAllocation ha;
1879 ASSERT(args.length() == 1);
1880
1881 CONVERT_CHECKED(JSFunction, fun, args[0]);
1882 int pos = fun->shared()->start_position();
1883 return Smi::FromInt(pos);
1884}
1885
1886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001887RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001888 ASSERT(args.length() == 2);
1889
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001890 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001891 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1892
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001893 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1894
1895 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001896 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001897}
1898
1899
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001900RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901 NoHandleAllocation ha;
1902 ASSERT(args.length() == 2);
1903
1904 CONVERT_CHECKED(JSFunction, fun, args[0]);
1905 CONVERT_CHECKED(String, name, args[1]);
1906 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908}
1909
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912 NoHandleAllocation ha;
1913 ASSERT(args.length() == 2);
1914
1915 CONVERT_CHECKED(JSFunction, fun, args[0]);
1916 CONVERT_CHECKED(Smi, length, args[1]);
1917 fun->shared()->set_length(length->value());
1918 return length;
1919}
1920
1921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001922RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001923 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924 ASSERT(args.length() == 2);
1925
1926 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001927 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001928 Object* obj;
1929 { MaybeObject* maybe_obj =
1930 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1931 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001933 return args[0]; // return TOS
1934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 1);
1940
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1943 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001944}
1945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950
1951 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001952 return f->IsBuiltin() ? isolate->heap()->true_value() :
1953 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001954}
1955
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001957RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001958 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 ASSERT(args.length() == 2);
1960
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001961 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001962 Handle<Object> code = args.at<Object>(1);
1963
1964 Handle<Context> context(target->context());
1965
1966 if (!code->IsNull()) {
1967 RUNTIME_ASSERT(code->IsJSFunction());
1968 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001969 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001970
1971 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 return Failure::Exception();
1973 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001974 // Since we don't store the source for this we should never
1975 // optimize this.
1976 shared->code()->set_optimizable(false);
1977
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001978 // Set the code, scope info, formal parameter count,
1979 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001980 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001981 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001982 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001983 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001985 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001986 // Set the source code of the target function to undefined.
1987 // SetCode is only used for built-in constructors like String,
1988 // Array, and Object, and some web code
1989 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001990 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00001991 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001992 // Clear the optimization hints related to the compiled code as these are no
1993 // longer valid when the code is overwritten.
1994 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 context = Handle<Context>(fun->context());
1996
1997 // Make sure we get a fresh copy of the literal vector to avoid
1998 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001999 int number_of_literals = fun->NumberOfLiterals();
2000 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002001 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002002 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002003 // Insert the object, regexp and array functions in the literals
2004 // array prefix. These are the functions that will be used when
2005 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002006 literals->set(JSFunction::kLiteralGlobalContextIndex,
2007 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002008 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002009 // It's okay to skip the write barrier here because the literals
2010 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002011 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002012 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 }
2014
2015 target->set_context(*context);
2016 return *target;
2017}
2018
2019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002020RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002022 ASSERT(args.length() == 2);
2023 CONVERT_ARG_CHECKED(JSFunction, function, 0);
2024 CONVERT_SMI_CHECKED(num, args[1]);
2025 RUNTIME_ASSERT(num >= 0);
2026 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002028}
2029
2030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002031MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2032 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002033 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002034 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002035 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002036 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002037 }
2038 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002040}
2041
2042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002043RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044 NoHandleAllocation ha;
2045 ASSERT(args.length() == 2);
2046
2047 CONVERT_CHECKED(String, subject, args[0]);
2048 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002049 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002051 uint32_t i = 0;
2052 if (index->IsSmi()) {
2053 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002055 i = value;
2056 } else {
2057 ASSERT(index->IsHeapNumber());
2058 double value = HeapNumber::cast(index)->value();
2059 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002060 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002061
2062 // Flatten the string. If someone wants to get a char at an index
2063 // in a cons string, it is likely that more indices will be
2064 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002065 Object* flat;
2066 { MaybeObject* maybe_flat = subject->TryFlatten();
2067 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2068 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002069 subject = String::cast(flat);
2070
2071 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002072 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002073 }
2074
2075 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002076}
2077
2078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002079RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080 NoHandleAllocation ha;
2081 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002082 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002083}
2084
lrn@chromium.org25156de2010-04-06 13:10:27 +00002085
2086class FixedArrayBuilder {
2087 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002088 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2089 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002090 length_(0) {
2091 // Require a non-zero initial size. Ensures that doubling the size to
2092 // extend the array will work.
2093 ASSERT(initial_capacity > 0);
2094 }
2095
2096 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2097 : array_(backing_store),
2098 length_(0) {
2099 // Require a non-zero initial size. Ensures that doubling the size to
2100 // extend the array will work.
2101 ASSERT(backing_store->length() > 0);
2102 }
2103
2104 bool HasCapacity(int elements) {
2105 int length = array_->length();
2106 int required_length = length_ + elements;
2107 return (length >= required_length);
2108 }
2109
2110 void EnsureCapacity(int elements) {
2111 int length = array_->length();
2112 int required_length = length_ + elements;
2113 if (length < required_length) {
2114 int new_length = length;
2115 do {
2116 new_length *= 2;
2117 } while (new_length < required_length);
2118 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002119 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002120 array_->CopyTo(0, *extended_array, 0, length_);
2121 array_ = extended_array;
2122 }
2123 }
2124
2125 void Add(Object* value) {
2126 ASSERT(length_ < capacity());
2127 array_->set(length_, value);
2128 length_++;
2129 }
2130
2131 void Add(Smi* value) {
2132 ASSERT(length_ < capacity());
2133 array_->set(length_, value);
2134 length_++;
2135 }
2136
2137 Handle<FixedArray> array() {
2138 return array_;
2139 }
2140
2141 int length() {
2142 return length_;
2143 }
2144
2145 int capacity() {
2146 return array_->length();
2147 }
2148
2149 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002150 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002151 result_array->set_length(Smi::FromInt(length_));
2152 return result_array;
2153 }
2154
2155 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2156 target_array->set_elements(*array_);
2157 target_array->set_length(Smi::FromInt(length_));
2158 return target_array;
2159 }
2160
2161 private:
2162 Handle<FixedArray> array_;
2163 int length_;
2164};
2165
2166
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002167// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002168const int kStringBuilderConcatHelperLengthBits = 11;
2169const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002170
2171template <typename schar>
2172static inline void StringBuilderConcatHelper(String*,
2173 schar*,
2174 FixedArray*,
2175 int);
2176
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2178 StringBuilderSubstringLength;
2179typedef BitField<int,
2180 kStringBuilderConcatHelperLengthBits,
2181 kStringBuilderConcatHelperPositionBits>
2182 StringBuilderSubstringPosition;
2183
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002184
2185class ReplacementStringBuilder {
2186 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002187 ReplacementStringBuilder(Heap* heap,
2188 Handle<String> subject,
2189 int estimated_part_count)
2190 : heap_(heap),
2191 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002192 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002194 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002195 // Require a non-zero initial size. Ensures that doubling the size to
2196 // extend the array will work.
2197 ASSERT(estimated_part_count > 0);
2198 }
2199
lrn@chromium.org25156de2010-04-06 13:10:27 +00002200 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2201 int from,
2202 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002203 ASSERT(from >= 0);
2204 int length = to - from;
2205 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002206 if (StringBuilderSubstringLength::is_valid(length) &&
2207 StringBuilderSubstringPosition::is_valid(from)) {
2208 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2209 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002210 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002212 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002213 builder->Add(Smi::FromInt(-length));
2214 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002215 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002216 }
2217
2218
2219 void EnsureCapacity(int elements) {
2220 array_builder_.EnsureCapacity(elements);
2221 }
2222
2223
2224 void AddSubjectSlice(int from, int to) {
2225 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002227 }
2228
2229
2230 void AddString(Handle<String> string) {
2231 int length = string->length();
2232 ASSERT(length > 0);
2233 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002234 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002235 is_ascii_ = false;
2236 }
2237 IncrementCharacterCount(length);
2238 }
2239
2240
2241 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002243 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002244 }
2245
2246 Handle<String> joined_string;
2247 if (is_ascii_) {
2248 joined_string = NewRawAsciiString(character_count_);
2249 AssertNoAllocation no_alloc;
2250 SeqAsciiString* seq = SeqAsciiString::cast(*joined_string);
2251 char* char_buffer = seq->GetChars();
2252 StringBuilderConcatHelper(*subject_,
2253 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002254 *array_builder_.array(),
2255 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002256 } else {
2257 // Non-ASCII.
2258 joined_string = NewRawTwoByteString(character_count_);
2259 AssertNoAllocation no_alloc;
2260 SeqTwoByteString* seq = SeqTwoByteString::cast(*joined_string);
2261 uc16* char_buffer = seq->GetChars();
2262 StringBuilderConcatHelper(*subject_,
2263 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 *array_builder_.array(),
2265 array_builder_.length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002266 }
2267 return joined_string;
2268 }
2269
2270
2271 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002272 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002273 V8::FatalProcessOutOfMemory("String.replace result too large.");
2274 }
2275 character_count_ += by;
2276 }
2277
lrn@chromium.org25156de2010-04-06 13:10:27 +00002278 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002279 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002281
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 private:
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 Handle<String> NewRawAsciiString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002284 CALL_HEAP_FUNCTION(heap_->isolate(),
2285 heap_->AllocateRawAsciiString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 }
2287
2288
2289 Handle<String> NewRawTwoByteString(int size) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002290 CALL_HEAP_FUNCTION(heap_->isolate(),
2291 heap_->AllocateRawTwoByteString(size), String);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 }
2293
2294
2295 void AddElement(Object* element) {
2296 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002297 ASSERT(array_builder_.capacity() > array_builder_.length());
2298 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 }
2300
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002301 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002302 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002303 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002304 int character_count_;
2305 bool is_ascii_;
2306};
2307
2308
2309class CompiledReplacement {
2310 public:
2311 CompiledReplacement()
2312 : parts_(1), replacement_substrings_(0) {}
2313
2314 void Compile(Handle<String> replacement,
2315 int capture_count,
2316 int subject_length);
2317
2318 void Apply(ReplacementStringBuilder* builder,
2319 int match_from,
2320 int match_to,
2321 Handle<JSArray> last_match_info);
2322
2323 // Number of distinct parts of the replacement pattern.
2324 int parts() {
2325 return parts_.length();
2326 }
2327 private:
2328 enum PartType {
2329 SUBJECT_PREFIX = 1,
2330 SUBJECT_SUFFIX,
2331 SUBJECT_CAPTURE,
2332 REPLACEMENT_SUBSTRING,
2333 REPLACEMENT_STRING,
2334
2335 NUMBER_OF_PART_TYPES
2336 };
2337
2338 struct ReplacementPart {
2339 static inline ReplacementPart SubjectMatch() {
2340 return ReplacementPart(SUBJECT_CAPTURE, 0);
2341 }
2342 static inline ReplacementPart SubjectCapture(int capture_index) {
2343 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2344 }
2345 static inline ReplacementPart SubjectPrefix() {
2346 return ReplacementPart(SUBJECT_PREFIX, 0);
2347 }
2348 static inline ReplacementPart SubjectSuffix(int subject_length) {
2349 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2350 }
2351 static inline ReplacementPart ReplacementString() {
2352 return ReplacementPart(REPLACEMENT_STRING, 0);
2353 }
2354 static inline ReplacementPart ReplacementSubString(int from, int to) {
2355 ASSERT(from >= 0);
2356 ASSERT(to > from);
2357 return ReplacementPart(-from, to);
2358 }
2359
2360 // If tag <= 0 then it is the negation of a start index of a substring of
2361 // the replacement pattern, otherwise it's a value from PartType.
2362 ReplacementPart(int tag, int data)
2363 : tag(tag), data(data) {
2364 // Must be non-positive or a PartType value.
2365 ASSERT(tag < NUMBER_OF_PART_TYPES);
2366 }
2367 // Either a value of PartType or a non-positive number that is
2368 // the negation of an index into the replacement string.
2369 int tag;
2370 // The data value's interpretation depends on the value of tag:
2371 // tag == SUBJECT_PREFIX ||
2372 // tag == SUBJECT_SUFFIX: data is unused.
2373 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2374 // tag == REPLACEMENT_SUBSTRING ||
2375 // tag == REPLACEMENT_STRING: data is index into array of substrings
2376 // of the replacement string.
2377 // tag <= 0: Temporary representation of the substring of the replacement
2378 // string ranging over -tag .. data.
2379 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2380 // substring objects.
2381 int data;
2382 };
2383
2384 template<typename Char>
2385 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2386 Vector<Char> characters,
2387 int capture_count,
2388 int subject_length) {
2389 int length = characters.length();
2390 int last = 0;
2391 for (int i = 0; i < length; i++) {
2392 Char c = characters[i];
2393 if (c == '$') {
2394 int next_index = i + 1;
2395 if (next_index == length) { // No next character!
2396 break;
2397 }
2398 Char c2 = characters[next_index];
2399 switch (c2) {
2400 case '$':
2401 if (i > last) {
2402 // There is a substring before. Include the first "$".
2403 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2404 last = next_index + 1; // Continue after the second "$".
2405 } else {
2406 // Let the next substring start with the second "$".
2407 last = next_index;
2408 }
2409 i = next_index;
2410 break;
2411 case '`':
2412 if (i > last) {
2413 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2414 }
2415 parts->Add(ReplacementPart::SubjectPrefix());
2416 i = next_index;
2417 last = i + 1;
2418 break;
2419 case '\'':
2420 if (i > last) {
2421 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2422 }
2423 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2424 i = next_index;
2425 last = i + 1;
2426 break;
2427 case '&':
2428 if (i > last) {
2429 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2430 }
2431 parts->Add(ReplacementPart::SubjectMatch());
2432 i = next_index;
2433 last = i + 1;
2434 break;
2435 case '0':
2436 case '1':
2437 case '2':
2438 case '3':
2439 case '4':
2440 case '5':
2441 case '6':
2442 case '7':
2443 case '8':
2444 case '9': {
2445 int capture_ref = c2 - '0';
2446 if (capture_ref > capture_count) {
2447 i = next_index;
2448 continue;
2449 }
2450 int second_digit_index = next_index + 1;
2451 if (second_digit_index < length) {
2452 // Peek ahead to see if we have two digits.
2453 Char c3 = characters[second_digit_index];
2454 if ('0' <= c3 && c3 <= '9') { // Double digits.
2455 int double_digit_ref = capture_ref * 10 + c3 - '0';
2456 if (double_digit_ref <= capture_count) {
2457 next_index = second_digit_index;
2458 capture_ref = double_digit_ref;
2459 }
2460 }
2461 }
2462 if (capture_ref > 0) {
2463 if (i > last) {
2464 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2465 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002466 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002467 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2468 last = next_index + 1;
2469 }
2470 i = next_index;
2471 break;
2472 }
2473 default:
2474 i = next_index;
2475 break;
2476 }
2477 }
2478 }
2479 if (length > last) {
2480 if (last == 0) {
2481 parts->Add(ReplacementPart::ReplacementString());
2482 } else {
2483 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2484 }
2485 }
2486 }
2487
2488 ZoneList<ReplacementPart> parts_;
2489 ZoneList<Handle<String> > replacement_substrings_;
2490};
2491
2492
2493void CompiledReplacement::Compile(Handle<String> replacement,
2494 int capture_count,
2495 int subject_length) {
2496 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002497 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 AssertNoAllocation no_alloc;
2499 ParseReplacementPattern(&parts_,
2500 replacement->ToAsciiVector(),
2501 capture_count,
2502 subject_length);
2503 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002504 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002505 AssertNoAllocation no_alloc;
2506
2507 ParseReplacementPattern(&parts_,
2508 replacement->ToUC16Vector(),
2509 capture_count,
2510 subject_length);
2511 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002512 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002513 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002514 int substring_index = 0;
2515 for (int i = 0, n = parts_.length(); i < n; i++) {
2516 int tag = parts_[i].tag;
2517 if (tag <= 0) { // A replacement string slice.
2518 int from = -tag;
2519 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520 replacement_substrings_.Add(
2521 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002522 parts_[i].tag = REPLACEMENT_SUBSTRING;
2523 parts_[i].data = substring_index;
2524 substring_index++;
2525 } else if (tag == REPLACEMENT_STRING) {
2526 replacement_substrings_.Add(replacement);
2527 parts_[i].data = substring_index;
2528 substring_index++;
2529 }
2530 }
2531}
2532
2533
2534void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2535 int match_from,
2536 int match_to,
2537 Handle<JSArray> last_match_info) {
2538 for (int i = 0, n = parts_.length(); i < n; i++) {
2539 ReplacementPart part = parts_[i];
2540 switch (part.tag) {
2541 case SUBJECT_PREFIX:
2542 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2543 break;
2544 case SUBJECT_SUFFIX: {
2545 int subject_length = part.data;
2546 if (match_to < subject_length) {
2547 builder->AddSubjectSlice(match_to, subject_length);
2548 }
2549 break;
2550 }
2551 case SUBJECT_CAPTURE: {
2552 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002553 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002554 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2555 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2556 if (from >= 0 && to > from) {
2557 builder->AddSubjectSlice(from, to);
2558 }
2559 break;
2560 }
2561 case REPLACEMENT_SUBSTRING:
2562 case REPLACEMENT_STRING:
2563 builder->AddString(replacement_substrings_[part.data]);
2564 break;
2565 default:
2566 UNREACHABLE();
2567 }
2568 }
2569}
2570
2571
2572
lrn@chromium.org303ada72010-10-27 09:33:13 +00002573MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002574 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002575 String* subject,
2576 JSRegExp* regexp,
2577 String* replacement,
2578 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 ASSERT(subject->IsFlat());
2580 ASSERT(replacement->IsFlat());
2581
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002582 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002583
2584 int length = subject->length();
2585 Handle<String> subject_handle(subject);
2586 Handle<JSRegExp> regexp_handle(regexp);
2587 Handle<String> replacement_handle(replacement);
2588 Handle<JSArray> last_match_info_handle(last_match_info);
2589 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2590 subject_handle,
2591 0,
2592 last_match_info_handle);
2593 if (match.is_null()) {
2594 return Failure::Exception();
2595 }
2596 if (match->IsNull()) {
2597 return *subject_handle;
2598 }
2599
2600 int capture_count = regexp_handle->CaptureCount();
2601
2602 // CompiledReplacement uses zone allocation.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002603 CompilationZoneScope zone(DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002604 CompiledReplacement compiled_replacement;
2605 compiled_replacement.Compile(replacement_handle,
2606 capture_count,
2607 length);
2608
2609 bool is_global = regexp_handle->GetFlags().is_global();
2610
2611 // Guessing the number of parts that the final result string is built
2612 // from. Global regexps can match any number of times, so we guess
2613 // conservatively.
2614 int expected_parts =
2615 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 ReplacementStringBuilder builder(isolate->heap(),
2617 subject_handle,
2618 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002619
2620 // Index of end of last match.
2621 int prev = 0;
2622
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002623 // Number of parts added by compiled replacement plus preceeding
2624 // string and possibly suffix after last match. It is possible for
2625 // all components to use two elements when encoded as two smis.
2626 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002627 bool matched = true;
2628 do {
2629 ASSERT(last_match_info_handle->HasFastElements());
2630 // Increase the capacity of the builder before entering local handle-scope,
2631 // so its internal buffer can safely allocate a new handle if it grows.
2632 builder.EnsureCapacity(parts_added_per_loop);
2633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002634 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002635 int start, end;
2636 {
2637 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002638 FixedArray* match_info_array =
2639 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002640
2641 ASSERT_EQ(capture_count * 2 + 2,
2642 RegExpImpl::GetLastCaptureCount(match_info_array));
2643 start = RegExpImpl::GetCapture(match_info_array, 0);
2644 end = RegExpImpl::GetCapture(match_info_array, 1);
2645 }
2646
2647 if (prev < start) {
2648 builder.AddSubjectSlice(prev, start);
2649 }
2650 compiled_replacement.Apply(&builder,
2651 start,
2652 end,
2653 last_match_info_handle);
2654 prev = end;
2655
2656 // Only continue checking for global regexps.
2657 if (!is_global) break;
2658
2659 // Continue from where the match ended, unless it was an empty match.
2660 int next = end;
2661 if (start == end) {
2662 next = end + 1;
2663 if (next > length) break;
2664 }
2665
2666 match = RegExpImpl::Exec(regexp_handle,
2667 subject_handle,
2668 next,
2669 last_match_info_handle);
2670 if (match.is_null()) {
2671 return Failure::Exception();
2672 }
2673 matched = !match->IsNull();
2674 } while (matched);
2675
2676 if (prev < length) {
2677 builder.AddSubjectSlice(prev, length);
2678 }
2679
2680 return *(builder.ToString());
2681}
2682
2683
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002684template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002685MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002686 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002687 String* subject,
2688 JSRegExp* regexp,
2689 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002690 ASSERT(subject->IsFlat());
2691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002693
2694 Handle<String> subject_handle(subject);
2695 Handle<JSRegExp> regexp_handle(regexp);
2696 Handle<JSArray> last_match_info_handle(last_match_info);
2697 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2698 subject_handle,
2699 0,
2700 last_match_info_handle);
2701 if (match.is_null()) return Failure::Exception();
2702 if (match->IsNull()) return *subject_handle;
2703
2704 ASSERT(last_match_info_handle->HasFastElements());
2705
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002706 int start, end;
2707 {
2708 AssertNoAllocation match_info_array_is_not_in_a_handle;
2709 FixedArray* match_info_array =
2710 FixedArray::cast(last_match_info_handle->elements());
2711
2712 start = RegExpImpl::GetCapture(match_info_array, 0);
2713 end = RegExpImpl::GetCapture(match_info_array, 1);
2714 }
2715
2716 int length = subject->length();
2717 int new_length = length - (end - start);
2718 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002719 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002720 }
2721 Handle<ResultSeqString> answer;
2722 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002723 answer = Handle<ResultSeqString>::cast(
2724 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002725 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002726 answer = Handle<ResultSeqString>::cast(
2727 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002728 }
2729
2730 // If the regexp isn't global, only match once.
2731 if (!regexp_handle->GetFlags().is_global()) {
2732 if (start > 0) {
2733 String::WriteToFlat(*subject_handle,
2734 answer->GetChars(),
2735 0,
2736 start);
2737 }
2738 if (end < length) {
2739 String::WriteToFlat(*subject_handle,
2740 answer->GetChars() + start,
2741 end,
2742 length);
2743 }
2744 return *answer;
2745 }
2746
2747 int prev = 0; // Index of end of last match.
2748 int next = 0; // Start of next search (prev unless last match was empty).
2749 int position = 0;
2750
2751 do {
2752 if (prev < start) {
2753 // Add substring subject[prev;start] to answer string.
2754 String::WriteToFlat(*subject_handle,
2755 answer->GetChars() + position,
2756 prev,
2757 start);
2758 position += start - prev;
2759 }
2760 prev = end;
2761 next = end;
2762 // Continue from where the match ended, unless it was an empty match.
2763 if (start == end) {
2764 next++;
2765 if (next > length) break;
2766 }
2767 match = RegExpImpl::Exec(regexp_handle,
2768 subject_handle,
2769 next,
2770 last_match_info_handle);
2771 if (match.is_null()) return Failure::Exception();
2772 if (match->IsNull()) break;
2773
2774 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002775 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002776 {
2777 AssertNoAllocation match_info_array_is_not_in_a_handle;
2778 FixedArray* match_info_array =
2779 FixedArray::cast(last_match_info_handle->elements());
2780 start = RegExpImpl::GetCapture(match_info_array, 0);
2781 end = RegExpImpl::GetCapture(match_info_array, 1);
2782 }
2783 } while (true);
2784
2785 if (prev < length) {
2786 // Add substring subject[prev;length] to answer string.
2787 String::WriteToFlat(*subject_handle,
2788 answer->GetChars() + position,
2789 prev,
2790 length);
2791 position += length - prev;
2792 }
2793
2794 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002795 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002796 }
2797
2798 // Shorten string and fill
2799 int string_size = ResultSeqString::SizeFor(position);
2800 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2801 int delta = allocated_string_size - string_size;
2802
2803 answer->set_length(position);
2804 if (delta == 0) return *answer;
2805
2806 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002807 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002808
2809 return *answer;
2810}
2811
2812
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002813RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002814 ASSERT(args.length() == 4);
2815
2816 CONVERT_CHECKED(String, subject, args[0]);
2817 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002818 Object* flat_subject;
2819 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2820 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2821 return maybe_flat_subject;
2822 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002823 }
2824 subject = String::cast(flat_subject);
2825 }
2826
2827 CONVERT_CHECKED(String, replacement, args[2]);
2828 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002829 Object* flat_replacement;
2830 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2831 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2832 return maybe_flat_replacement;
2833 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002834 }
2835 replacement = String::cast(flat_replacement);
2836 }
2837
2838 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2839 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2840
2841 ASSERT(last_match_info->HasFastElements());
2842
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002843 if (replacement->length() == 0) {
2844 if (subject->HasOnlyAsciiChars()) {
2845 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002846 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002847 } else {
2848 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002849 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002850 }
2851 }
2852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002853 return StringReplaceRegExpWithString(isolate,
2854 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002855 regexp,
2856 replacement,
2857 last_match_info);
2858}
2859
2860
ager@chromium.org7c537e22008-10-16 08:43:32 +00002861// Perform string match of pattern on subject, starting at start index.
2862// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002863// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002864int Runtime::StringMatch(Isolate* isolate,
2865 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002866 Handle<String> pat,
2867 int start_index) {
2868 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002869 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002870
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002871 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002872 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002874 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002875 if (start_index + pattern_length > subject_length) return -1;
2876
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002877 if (!sub->IsFlat()) FlattenString(sub);
2878 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002879
ager@chromium.org7c537e22008-10-16 08:43:32 +00002880 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002881 // Extract flattened substrings of cons strings before determining asciiness.
2882 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002883 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002884 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002885 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002886
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002888 if (seq_pat->IsAsciiRepresentation()) {
2889 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2890 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002891 return SearchString(isolate,
2892 seq_sub->ToAsciiVector(),
2893 pat_vector,
2894 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002896 return SearchString(isolate,
2897 seq_sub->ToUC16Vector(),
2898 pat_vector,
2899 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002900 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002901 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2902 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002903 return SearchString(isolate,
2904 seq_sub->ToAsciiVector(),
2905 pat_vector,
2906 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002907 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002908 return SearchString(isolate,
2909 seq_sub->ToUC16Vector(),
2910 pat_vector,
2911 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002912}
2913
2914
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002915RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002917 ASSERT(args.length() == 3);
2918
ager@chromium.org7c537e22008-10-16 08:43:32 +00002919 CONVERT_ARG_CHECKED(String, sub, 0);
2920 CONVERT_ARG_CHECKED(String, pat, 1);
2921
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002922 Object* index = args[2];
2923 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002924 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002925
ager@chromium.org870a0b62008-11-04 11:43:05 +00002926 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002927 int position =
2928 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002929 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002930}
2931
2932
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002933template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002934static int StringMatchBackwards(Vector<const schar> subject,
2935 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002936 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002937 int pattern_length = pattern.length();
2938 ASSERT(pattern_length >= 1);
2939 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002940
2941 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002942 for (int i = 0; i < pattern_length; i++) {
2943 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002944 if (c > String::kMaxAsciiCharCode) {
2945 return -1;
2946 }
2947 }
2948 }
2949
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002950 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002951 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002952 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002953 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002954 while (j < pattern_length) {
2955 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002956 break;
2957 }
2958 j++;
2959 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002960 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961 return i;
2962 }
2963 }
2964 return -1;
2965}
2966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002968 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002969 ASSERT(args.length() == 3);
2970
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002971 CONVERT_ARG_CHECKED(String, sub, 0);
2972 CONVERT_ARG_CHECKED(String, pat, 1);
2973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002974 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002975 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002976 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002977
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002979 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002980
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 if (start_index + pat_length > sub_length) {
2982 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002985 if (pat_length == 0) {
2986 return Smi::FromInt(start_index);
2987 }
2988
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002989 if (!sub->IsFlat()) FlattenString(sub);
2990 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002991
2992 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
2993
2994 int position = -1;
2995
2996 if (pat->IsAsciiRepresentation()) {
2997 Vector<const char> pat_vector = pat->ToAsciiVector();
2998 if (sub->IsAsciiRepresentation()) {
2999 position = StringMatchBackwards(sub->ToAsciiVector(),
3000 pat_vector,
3001 start_index);
3002 } else {
3003 position = StringMatchBackwards(sub->ToUC16Vector(),
3004 pat_vector,
3005 start_index);
3006 }
3007 } else {
3008 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3009 if (sub->IsAsciiRepresentation()) {
3010 position = StringMatchBackwards(sub->ToAsciiVector(),
3011 pat_vector,
3012 start_index);
3013 } else {
3014 position = StringMatchBackwards(sub->ToUC16Vector(),
3015 pat_vector,
3016 start_index);
3017 }
3018 }
3019
3020 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003021}
3022
3023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003024RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003025 NoHandleAllocation ha;
3026 ASSERT(args.length() == 2);
3027
3028 CONVERT_CHECKED(String, str1, args[0]);
3029 CONVERT_CHECKED(String, str2, args[1]);
3030
3031 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003032 int str1_length = str1->length();
3033 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003034
3035 // Decide trivial cases without flattening.
3036 if (str1_length == 0) {
3037 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3038 return Smi::FromInt(-str2_length);
3039 } else {
3040 if (str2_length == 0) return Smi::FromInt(str1_length);
3041 }
3042
3043 int end = str1_length < str2_length ? str1_length : str2_length;
3044
3045 // No need to flatten if we are going to find the answer on the first
3046 // character. At this point we know there is at least one character
3047 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003048 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003049 if (d != 0) return Smi::FromInt(d);
3050
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003051 str1->TryFlatten();
3052 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003054 StringInputBuffer& buf1 =
3055 *isolate->runtime_state()->string_locale_compare_buf1();
3056 StringInputBuffer& buf2 =
3057 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058
3059 buf1.Reset(str1);
3060 buf2.Reset(str2);
3061
3062 for (int i = 0; i < end; i++) {
3063 uint16_t char1 = buf1.GetNext();
3064 uint16_t char2 = buf2.GetNext();
3065 if (char1 != char2) return Smi::FromInt(char1 - char2);
3066 }
3067
3068 return Smi::FromInt(str1_length - str2_length);
3069}
3070
3071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003072RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073 NoHandleAllocation ha;
3074 ASSERT(args.length() == 3);
3075
3076 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003077 Object* from = args[1];
3078 Object* to = args[2];
3079 int start, end;
3080 // We have a fast integer-only case here to avoid a conversion to double in
3081 // the common case where from and to are Smis.
3082 if (from->IsSmi() && to->IsSmi()) {
3083 start = Smi::cast(from)->value();
3084 end = Smi::cast(to)->value();
3085 } else {
3086 CONVERT_DOUBLE_CHECKED(from_number, from);
3087 CONVERT_DOUBLE_CHECKED(to_number, to);
3088 start = FastD2I(from_number);
3089 end = FastD2I(to_number);
3090 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091 RUNTIME_ASSERT(end >= start);
3092 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003093 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003095 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096}
3097
3098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003099RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003100 ASSERT_EQ(3, args.length());
3101
3102 CONVERT_ARG_CHECKED(String, subject, 0);
3103 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3104 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3105 HandleScope handles;
3106
3107 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3108
3109 if (match.is_null()) {
3110 return Failure::Exception();
3111 }
3112 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003113 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003114 }
3115 int length = subject->length();
3116
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003117 CompilationZoneScope zone_space(DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003118 ZoneList<int> offsets(8);
3119 do {
3120 int start;
3121 int end;
3122 {
3123 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003124 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3126 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3127 }
3128 offsets.Add(start);
3129 offsets.Add(end);
3130 int index = start < end ? end : end + 1;
3131 if (index > length) break;
3132 match = RegExpImpl::Exec(regexp, subject, index, regexp_info);
3133 if (match.is_null()) {
3134 return Failure::Exception();
3135 }
3136 } while (!match->IsNull());
3137 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 for (int i = 0; i < matches ; i++) {
3140 int from = offsets.at(i * 2);
3141 int to = offsets.at(i * 2 + 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003142 Handle<String> match = isolate->factory()->NewSubString(subject, from, to);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 elements->set(i, *match);
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003145 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 result->set_length(Smi::FromInt(matches));
3147 return *result;
3148}
3149
3150
lrn@chromium.org25156de2010-04-06 13:10:27 +00003151// Two smis before and after the match, for very long strings.
3152const int kMaxBuilderEntriesPerRegExpMatch = 5;
3153
3154
3155static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3156 Handle<JSArray> last_match_info,
3157 int match_start,
3158 int match_end) {
3159 // Fill last_match_info with a single capture.
3160 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3161 AssertNoAllocation no_gc;
3162 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3163 RegExpImpl::SetLastCaptureCount(elements, 2);
3164 RegExpImpl::SetLastInput(elements, *subject);
3165 RegExpImpl::SetLastSubject(elements, *subject);
3166 RegExpImpl::SetCapture(elements, 0, match_start);
3167 RegExpImpl::SetCapture(elements, 1, match_end);
3168}
3169
3170
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003171template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172static bool SearchStringMultiple(Isolate* isolate,
3173 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003174 Vector<const PatternChar> pattern,
3175 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003176 FixedArrayBuilder* builder,
3177 int* match_pos) {
3178 int pos = *match_pos;
3179 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003180 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003181 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003182 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003183 while (pos <= max_search_start) {
3184 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3185 *match_pos = pos;
3186 return false;
3187 }
3188 // Position of end of previous match.
3189 int match_end = pos + pattern_length;
3190 int new_pos = search.Search(subject, match_end);
3191 if (new_pos >= 0) {
3192 // A match.
3193 if (new_pos > match_end) {
3194 ReplacementStringBuilder::AddSubjectSlice(builder,
3195 match_end,
3196 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003197 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003198 pos = new_pos;
3199 builder->Add(pattern_string);
3200 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003201 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003203 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003204
lrn@chromium.org25156de2010-04-06 13:10:27 +00003205 if (pos < max_search_start) {
3206 ReplacementStringBuilder::AddSubjectSlice(builder,
3207 pos + pattern_length,
3208 subject_length);
3209 }
3210 *match_pos = pos;
3211 return true;
3212}
3213
3214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003215static bool SearchStringMultiple(Isolate* isolate,
3216 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003217 Handle<String> pattern,
3218 Handle<JSArray> last_match_info,
3219 FixedArrayBuilder* builder) {
3220 ASSERT(subject->IsFlat());
3221 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003222
3223 // Treating as if a previous match was before first character.
3224 int match_pos = -pattern->length();
3225
3226 for (;;) { // Break when search complete.
3227 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3228 AssertNoAllocation no_gc;
3229 if (subject->IsAsciiRepresentation()) {
3230 Vector<const char> subject_vector = subject->ToAsciiVector();
3231 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003232 if (SearchStringMultiple(isolate,
3233 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003235 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003236 builder,
3237 &match_pos)) break;
3238 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 if (SearchStringMultiple(isolate,
3240 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003241 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003242 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003243 builder,
3244 &match_pos)) break;
3245 }
3246 } else {
3247 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3248 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003249 if (SearchStringMultiple(isolate,
3250 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003252 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003253 builder,
3254 &match_pos)) break;
3255 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003256 if (SearchStringMultiple(isolate,
3257 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003258 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003259 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003260 builder,
3261 &match_pos)) break;
3262 }
3263 }
3264 }
3265
3266 if (match_pos >= 0) {
3267 SetLastMatchInfoNoCaptures(subject,
3268 last_match_info,
3269 match_pos,
3270 match_pos + pattern->length());
3271 return true;
3272 }
3273 return false; // No matches at all.
3274}
3275
3276
3277static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 Handle<String> subject,
3280 Handle<JSRegExp> regexp,
3281 Handle<JSArray> last_match_array,
3282 FixedArrayBuilder* builder) {
3283 ASSERT(subject->IsFlat());
3284 int match_start = -1;
3285 int match_end = 0;
3286 int pos = 0;
3287 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3288 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3289
3290 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003291 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003292 int subject_length = subject->length();
3293
3294 for (;;) { // Break on failure, return on exception.
3295 RegExpImpl::IrregexpResult result =
3296 RegExpImpl::IrregexpExecOnce(regexp,
3297 subject,
3298 pos,
3299 register_vector);
3300 if (result == RegExpImpl::RE_SUCCESS) {
3301 match_start = register_vector[0];
3302 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3303 if (match_end < match_start) {
3304 ReplacementStringBuilder::AddSubjectSlice(builder,
3305 match_end,
3306 match_start);
3307 }
3308 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003309 HandleScope loop_scope(isolate);
3310 builder->Add(*isolate->factory()->NewSubString(subject,
3311 match_start,
3312 match_end));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003313 if (match_start != match_end) {
3314 pos = match_end;
3315 } else {
3316 pos = match_end + 1;
3317 if (pos > subject_length) break;
3318 }
3319 } else if (result == RegExpImpl::RE_FAILURE) {
3320 break;
3321 } else {
3322 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3323 return result;
3324 }
3325 }
3326
3327 if (match_start >= 0) {
3328 if (match_end < subject_length) {
3329 ReplacementStringBuilder::AddSubjectSlice(builder,
3330 match_end,
3331 subject_length);
3332 }
3333 SetLastMatchInfoNoCaptures(subject,
3334 last_match_array,
3335 match_start,
3336 match_end);
3337 return RegExpImpl::RE_SUCCESS;
3338 } else {
3339 return RegExpImpl::RE_FAILURE; // No matches at all.
3340 }
3341}
3342
3343
3344static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003345 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346 Handle<String> subject,
3347 Handle<JSRegExp> regexp,
3348 Handle<JSArray> last_match_array,
3349 FixedArrayBuilder* builder) {
3350
3351 ASSERT(subject->IsFlat());
3352 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3353 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3354
3355 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003356 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003357
3358 RegExpImpl::IrregexpResult result =
3359 RegExpImpl::IrregexpExecOnce(regexp,
3360 subject,
3361 0,
3362 register_vector);
3363
3364 int capture_count = regexp->CaptureCount();
3365 int subject_length = subject->length();
3366
3367 // Position to search from.
3368 int pos = 0;
3369 // End of previous match. Differs from pos if match was empty.
3370 int match_end = 0;
3371 if (result == RegExpImpl::RE_SUCCESS) {
3372 // Need to keep a copy of the previous match for creating last_match_info
3373 // at the end, so we have two vectors that we swap between.
3374 OffsetsVector registers2(required_registers);
3375 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
3376
3377 do {
3378 int match_start = register_vector[0];
3379 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3380 if (match_end < match_start) {
3381 ReplacementStringBuilder::AddSubjectSlice(builder,
3382 match_end,
3383 match_start);
3384 }
3385 match_end = register_vector[1];
3386
3387 {
3388 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003389 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003390 // Arguments array to replace function is match, captures, index and
3391 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 Handle<FixedArray> elements =
3393 isolate->factory()->NewFixedArray(3 + capture_count);
3394 Handle<String> match = isolate->factory()->NewSubString(subject,
3395 match_start,
3396 match_end);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003397 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398 for (int i = 1; i <= capture_count; i++) {
3399 int start = register_vector[i * 2];
3400 if (start >= 0) {
3401 int end = register_vector[i * 2 + 1];
3402 ASSERT(start <= end);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003403 Handle<String> substring = isolate->factory()->NewSubString(subject,
3404 start,
3405 end);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003406 elements->set(i, *substring);
3407 } else {
3408 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003409 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003410 }
3411 }
3412 elements->set(capture_count + 1, Smi::FromInt(match_start));
3413 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003414 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003415 }
3416 // Swap register vectors, so the last successful match is in
3417 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003418 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003419 prev_register_vector = register_vector;
3420 register_vector = tmp;
3421
3422 if (match_end > match_start) {
3423 pos = match_end;
3424 } else {
3425 pos = match_end + 1;
3426 if (pos > subject_length) {
3427 break;
3428 }
3429 }
3430
3431 result = RegExpImpl::IrregexpExecOnce(regexp,
3432 subject,
3433 pos,
3434 register_vector);
3435 } while (result == RegExpImpl::RE_SUCCESS);
3436
3437 if (result != RegExpImpl::RE_EXCEPTION) {
3438 // Finished matching, with at least one match.
3439 if (match_end < subject_length) {
3440 ReplacementStringBuilder::AddSubjectSlice(builder,
3441 match_end,
3442 subject_length);
3443 }
3444
3445 int last_match_capture_count = (capture_count + 1) * 2;
3446 int last_match_array_size =
3447 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3448 last_match_array->EnsureSize(last_match_array_size);
3449 AssertNoAllocation no_gc;
3450 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3451 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3452 RegExpImpl::SetLastSubject(elements, *subject);
3453 RegExpImpl::SetLastInput(elements, *subject);
3454 for (int i = 0; i < last_match_capture_count; i++) {
3455 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3456 }
3457 return RegExpImpl::RE_SUCCESS;
3458 }
3459 }
3460 // No matches at all, return failure or exception result directly.
3461 return result;
3462}
3463
3464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003465RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003466 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003467 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468
3469 CONVERT_ARG_CHECKED(String, subject, 1);
3470 if (!subject->IsFlat()) { FlattenString(subject); }
3471 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3472 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3473 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3474
3475 ASSERT(last_match_info->HasFastElements());
3476 ASSERT(regexp->GetFlags().is_global());
3477 Handle<FixedArray> result_elements;
3478 if (result_array->HasFastElements()) {
3479 result_elements =
3480 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
3481 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003482 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003483 }
3484 FixedArrayBuilder builder(result_elements);
3485
3486 if (regexp->TypeTag() == JSRegExp::ATOM) {
3487 Handle<String> pattern(
3488 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003489 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003490 if (SearchStringMultiple(isolate, subject, pattern,
3491 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003492 return *builder.ToJSArray(result_array);
3493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003494 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003495 }
3496
3497 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3498
3499 RegExpImpl::IrregexpResult result;
3500 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003501 result = SearchRegExpNoCaptureMultiple(isolate,
3502 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003503 regexp,
3504 last_match_info,
3505 &builder);
3506 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 result = SearchRegExpMultiple(isolate,
3508 subject,
3509 regexp,
3510 last_match_info,
3511 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003512 }
3513 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003514 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3516 return Failure::Exception();
3517}
3518
3519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003520RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 NoHandleAllocation ha;
3522 ASSERT(args.length() == 2);
3523
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003524 // Fast case where the result is a one character string.
3525 if (args[0]->IsSmi() && args[1]->IsSmi()) {
3526 int value = Smi::cast(args[0])->value();
3527 int radix = Smi::cast(args[1])->value();
3528 if (value >= 0 && value < radix) {
3529 RUNTIME_ASSERT(radix <= 36);
3530 // Character array used for conversion.
3531 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 return isolate->heap()->
3533 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003534 }
3535 }
3536
3537 // Slow case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003538 CONVERT_DOUBLE_CHECKED(value, args[0]);
3539 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003541 }
3542 if (isinf(value)) {
3543 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003545 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003546 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003547 }
3548 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
3549 int radix = FastD2I(radix_number);
3550 RUNTIME_ASSERT(2 <= radix && radix <= 36);
3551 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 MaybeObject* result =
3553 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003554 DeleteArray(str);
3555 return result;
3556}
3557
3558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003559RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003560 NoHandleAllocation ha;
3561 ASSERT(args.length() == 2);
3562
3563 CONVERT_DOUBLE_CHECKED(value, args[0]);
3564 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003566 }
3567 if (isinf(value)) {
3568 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003569 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003571 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 }
3573 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3574 int f = FastD2I(f_number);
3575 RUNTIME_ASSERT(f >= 0);
3576 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 MaybeObject* res =
3578 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003580 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581}
3582
3583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003584RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003585 NoHandleAllocation ha;
3586 ASSERT(args.length() == 2);
3587
3588 CONVERT_DOUBLE_CHECKED(value, args[0]);
3589 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
3598 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3599 int f = FastD2I(f_number);
3600 RUNTIME_ASSERT(f >= -1 && f <= 20);
3601 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 MaybeObject* res =
3603 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003606}
3607
3608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003609RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610 NoHandleAllocation ha;
3611 ASSERT(args.length() == 2);
3612
3613 CONVERT_DOUBLE_CHECKED(value, args[0]);
3614 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003615 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003616 }
3617 if (isinf(value)) {
3618 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 }
3623 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
3624 int f = FastD2I(f_number);
3625 RUNTIME_ASSERT(f >= 1 && f <= 21);
3626 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 MaybeObject* res =
3628 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003630 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003631}
3632
3633
3634// Returns a single character string where first character equals
3635// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003636static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003637 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003638 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003639 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003640 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003641 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003642 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643}
3644
3645
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003646MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3647 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003648 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003649 // Handle [] indexing on Strings
3650 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003651 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3652 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653 }
3654
3655 // Handle [] indexing on String objects
3656 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3658 Handle<Object> result =
3659 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3660 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 }
3662
3663 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003664 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003665 return prototype->GetElement(index);
3666 }
3667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003668 return GetElement(object, index);
3669}
3670
3671
lrn@chromium.org303ada72010-10-27 09:33:13 +00003672MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003673 return object->GetElement(index);
3674}
3675
3676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3678 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003679 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003680 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003684 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 isolate->factory()->NewTypeError("non_object_property_load",
3686 HandleVector(args, 2));
3687 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
3689
3690 // Check if the given key is an array index.
3691 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003692 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
3695
3696 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003698 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 bool has_pending_exception = false;
3702 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003703 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003705 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
ager@chromium.org32912102009-01-16 10:38:43 +00003708 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 // the element if so.
3710 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003711 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
3713 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003714 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716}
3717
3718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003719RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 NoHandleAllocation ha;
3721 ASSERT(args.length() == 2);
3722
3723 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003724 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003727}
3728
3729
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003730// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003731RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003732 NoHandleAllocation ha;
3733 ASSERT(args.length() == 2);
3734
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003735 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003736 // itself.
3737 //
3738 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003739 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003740 // global proxy object never has properties. This is the case
3741 // because the global proxy object forwards everything to its hidden
3742 // prototype including local lookups.
3743 //
3744 // Additionally, we need to make sure that we do not cache results
3745 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003746 if (args[0]->IsJSObject() &&
3747 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003748 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003749 args[1]->IsString()) {
3750 JSObject* receiver = JSObject::cast(args[0]);
3751 String* key = String::cast(args[1]);
3752 if (receiver->HasFastProperties()) {
3753 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003754 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003755 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3756 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003757 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003758 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003760 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003761 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003762 LookupResult result;
3763 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003764 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003765 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003766 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003767 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003768 }
3769 } else {
3770 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003771 StringDictionary* dictionary = receiver->property_dictionary();
3772 int entry = dictionary->FindEntry(key);
3773 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003774 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003775 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003776 if (!receiver->IsGlobalObject()) return value;
3777 value = JSGlobalPropertyCell::cast(value)->value();
3778 if (!value->IsTheHole()) return value;
3779 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003780 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003781 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003782 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3783 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003784 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003785 Handle<String> str = args.at<String>(0);
3786 int index = Smi::cast(args[1])->value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003787 if (index >= 0 && index < str->length()) {
3788 Handle<Object> result = GetCharAt(str, index);
3789 return *result;
3790 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003791 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792
3793 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003794 return Runtime::GetObjectProperty(isolate,
3795 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003796 args.at<Object>(1));
3797}
3798
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003799// Implements part of 8.12.9 DefineOwnProperty.
3800// There are 3 cases that lead here:
3801// Step 4b - define a new accessor property.
3802// Steps 9c & 12 - replace an existing data property with an accessor property.
3803// Step 12 - update an existing accessor property with an accessor or generic
3804// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003805RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003806 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003807 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003808 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3809 CONVERT_CHECKED(String, name, args[1]);
3810 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003811 Object* fun = args[3];
3812 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003813 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3814 int unchecked = flag_attr->value();
3815 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3816 RUNTIME_ASSERT(!obj->IsNull());
3817 LookupResult result;
3818 obj->LocalLookupRealNamedProperty(name, &result);
3819
3820 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3821 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3822 // delete it to avoid running into trouble in DefineAccessor, which
3823 // handles this incorrectly if the property is readonly (does nothing)
3824 if (result.IsProperty() &&
3825 (result.type() == FIELD || result.type() == NORMAL
3826 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003827 Object* ok;
3828 { MaybeObject* maybe_ok =
3829 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3830 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3831 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003832 }
3833 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3834}
3835
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003836// Implements part of 8.12.9 DefineOwnProperty.
3837// There are 3 cases that lead here:
3838// Step 4a - define a new data property.
3839// Steps 9b & 12 - replace an existing accessor property with a data property.
3840// Step 12 - update an existing data property with a data or generic
3841// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003842RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003843 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003844 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003845 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3846 CONVERT_ARG_CHECKED(String, name, 1);
3847 Handle<Object> obj_value = args.at<Object>(2);
3848
3849 CONVERT_CHECKED(Smi, flag, args[3]);
3850 int unchecked = flag->value();
3851 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3852
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003853 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3854
3855 // Check if this is an element.
3856 uint32_t index;
3857 bool is_element = name->AsArrayIndex(&index);
3858
3859 // Special case for elements if any of the flags are true.
3860 // If elements are in fast case we always implicitly assume that:
3861 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3862 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3863 is_element) {
3864 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003865 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003866 // We do not need to do access checks here since these has already
3867 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003868 Handle<Object> proto(js_object->GetPrototype());
3869 // If proxy is detached, ignore the assignment. Alternatively,
3870 // we could throw an exception.
3871 if (proto->IsNull()) return *obj_value;
3872 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003873 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003874 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003875 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003876 // Make sure that we never go back to fast case.
3877 dictionary->set_requires_slow_elements();
3878 PropertyDetails details = PropertyDetails(attr, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003879 NumberDictionarySet(dictionary, index, obj_value, details);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003880 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003881 }
3882
ager@chromium.org5c838252010-02-19 08:53:10 +00003883 LookupResult result;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003884 js_object->LookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003885
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003886 // To be compatible with safari we do not change the value on API objects
3887 // in defineProperty. Firefox disagrees here, and actually changes the value.
3888 if (result.IsProperty() &&
3889 (result.type() == CALLBACKS) &&
3890 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003892 }
3893
ager@chromium.org5c838252010-02-19 08:53:10 +00003894 // Take special care when attributes are different and there is already
3895 // a property. For simplicity we normalize the property which enables us
3896 // to not worry about changing the instance_descriptor and creating a new
3897 // map. The current version of SetObjectProperty does not handle attributes
3898 // correctly in the case where a property is a field and is reset with
3899 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003900 if (result.IsProperty() &&
3901 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003902 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003903 if (js_object->IsJSGlobalProxy()) {
3904 // Since the result is a property, the prototype will exist so
3905 // we don't have to check for null.
3906 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003907 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003908 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003909 // Use IgnoreAttributes version since a readonly property may be
3910 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003911 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3912 *obj_value,
3913 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003914 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 return Runtime::ForceSetObjectProperty(isolate,
3917 js_object,
3918 name,
3919 obj_value,
3920 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003921}
3922
3923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003924MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3925 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003926 Handle<Object> key,
3927 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003928 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003929 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003930 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003933 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 isolate->factory()->NewTypeError("non_object_property_store",
3936 HandleVector(args, 2));
3937 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 }
3939
3940 // If the object isn't a JavaScript object, we ignore the store.
3941 if (!object->IsJSObject()) return *value;
3942
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003943 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
3944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945 // Check if the given key is an array index.
3946 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003947 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
3949 // of a string using [] notation. We need to support this too in
3950 // JavaScript.
3951 // In the case of a String object we just need to redirect the assignment to
3952 // the underlying string if the index is in range. Since the underlying
3953 // string does nothing with the assignment then we can ignore such
3954 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003955 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003957 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003959 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003960 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 return *value;
3962 }
3963
3964 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003965 Handle<Object> result;
3966 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003967 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003969 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003970 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003971 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003973 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 return *value;
3975 }
3976
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 bool has_pending_exception = false;
3979 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
3980 if (has_pending_exception) return Failure::Exception();
3981 Handle<String> name = Handle<String>::cast(converted);
3982
3983 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003984 return js_object->SetElement(index, *value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003986 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987 }
3988}
3989
3990
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003991MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
3992 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003993 Handle<Object> key,
3994 Handle<Object> value,
3995 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003996 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003997
3998 // Check if the given key is an array index.
3999 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004000 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004001 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4002 // of a string using [] notation. We need to support this too in
4003 // JavaScript.
4004 // In the case of a String object we just need to redirect the assignment to
4005 // the underlying string if the index is in range. Since the underlying
4006 // string does nothing with the assignment then we can ignore such
4007 // assignments.
4008 if (js_object->IsStringObjectWithCharacterAt(index)) {
4009 return *value;
4010 }
4011
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004012 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004013 }
4014
4015 if (key->IsString()) {
4016 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004017 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004018 } else {
4019 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004020 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004021 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4022 *value,
4023 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004024 }
4025 }
4026
4027 // Call-back into JavaScript to convert the key to a string.
4028 bool has_pending_exception = false;
4029 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4030 if (has_pending_exception) return Failure::Exception();
4031 Handle<String> name = Handle<String>::cast(converted);
4032
4033 if (name->AsArrayIndex(&index)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004034 return js_object->SetElement(index, *value, kNonStrictMode);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004035 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004036 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004037 }
4038}
4039
4040
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004041MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4042 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004043 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004044 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004045
4046 // Check if the given key is an array index.
4047 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004048 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004049 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4050 // characters of a string using [] notation. In the case of a
4051 // String object we just need to redirect the deletion to the
4052 // underlying string if the index is in range. Since the
4053 // underlying string does nothing with the deletion, we can ignore
4054 // such deletions.
4055 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004056 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004057 }
4058
4059 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4060 }
4061
4062 Handle<String> key_string;
4063 if (key->IsString()) {
4064 key_string = Handle<String>::cast(key);
4065 } else {
4066 // Call-back into JavaScript to convert the key to a string.
4067 bool has_pending_exception = false;
4068 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4069 if (has_pending_exception) return Failure::Exception();
4070 key_string = Handle<String>::cast(converted);
4071 }
4072
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004073 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004074 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4075}
4076
4077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004078RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004080 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081
4082 Handle<Object> object = args.at<Object>(0);
4083 Handle<Object> key = args.at<Object>(1);
4084 Handle<Object> value = args.at<Object>(2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004085 CONVERT_SMI_CHECKED(unchecked_attributes, args[3]);
4086 RUNTIME_ASSERT(
4087 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004089 PropertyAttributes attributes =
4090 static_cast<PropertyAttributes>(unchecked_attributes);
4091
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004092 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004093 if (args.length() == 5) {
4094 CONVERT_SMI_CHECKED(strict_unchecked, args[4]);
4095 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4096 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004097 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004099
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004100 return Runtime::SetObjectProperty(isolate,
4101 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004102 key,
4103 value,
4104 attributes,
4105 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106}
4107
4108
4109// Set a local property, even if it is READ_ONLY. If the property does not
4110// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004111RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004113 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004114 CONVERT_CHECKED(JSObject, object, args[0]);
4115 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004116 // Compute attributes.
4117 PropertyAttributes attributes = NONE;
4118 if (args.length() == 4) {
4119 CONVERT_CHECKED(Smi, value_obj, args[3]);
4120 int unchecked_value = value_obj->value();
4121 // Only attribute bits should be set.
4122 RUNTIME_ASSERT(
4123 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4124 attributes = static_cast<PropertyAttributes>(unchecked_value);
4125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004127 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004128 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129}
4130
4131
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004132RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004134 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135
4136 CONVERT_CHECKED(JSObject, object, args[0]);
4137 CONVERT_CHECKED(String, key, args[1]);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004138 CONVERT_SMI_CHECKED(strict, args[2]);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004139 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004140 ? JSObject::STRICT_DELETION
4141 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142}
4143
4144
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004145static Object* HasLocalPropertyImplementation(Isolate* isolate,
4146 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004147 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004148 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004149 // Handle hidden prototypes. If there's a hidden prototype above this thing
4150 // then we have to check it for properties, because they are supposed to
4151 // look like they are on this object.
4152 Handle<Object> proto(object->GetPrototype());
4153 if (proto->IsJSObject() &&
4154 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004155 return HasLocalPropertyImplementation(isolate,
4156 Handle<JSObject>::cast(proto),
4157 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004158 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
4165 ASSERT(args.length() == 2);
4166 CONVERT_CHECKED(String, key, args[1]);
4167
ager@chromium.org9085a012009-05-11 19:22:57 +00004168 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004169 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004170 if (obj->IsJSObject()) {
4171 JSObject* object = JSObject::cast(obj);
4172 // Fast case - no interceptors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004173 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004174 // Slow case. Either it's not there or we have an interceptor. We should
4175 // have handles for this kind of deal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 HandleScope scope(isolate);
4177 return HasLocalPropertyImplementation(isolate,
4178 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004179 Handle<String>(key));
4180 } else if (obj->IsString()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004181 // Well, there is one exception: Handle [] on strings.
4182 uint32_t index;
4183 if (key->AsArrayIndex(&index)) {
ager@chromium.org9085a012009-05-11 19:22:57 +00004184 String* string = String::cast(obj);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00004185 if (index < static_cast<uint32_t>(string->length()))
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004186 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 }
4188 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004189 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190}
4191
4192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004193RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 NoHandleAllocation na;
4195 ASSERT(args.length() == 2);
4196
4197 // Only JS objects can have properties.
4198 if (args[0]->IsJSObject()) {
4199 JSObject* object = JSObject::cast(args[0]);
4200 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204}
4205
4206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004207RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004208 NoHandleAllocation na;
4209 ASSERT(args.length() == 2);
4210
4211 // Only JS objects can have elements.
4212 if (args[0]->IsJSObject()) {
4213 JSObject* object = JSObject::cast(args[0]);
4214 CONVERT_CHECKED(Smi, index_obj, args[1]);
4215 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004218 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219}
4220
4221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004222RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223 NoHandleAllocation ha;
4224 ASSERT(args.length() == 2);
4225
4226 CONVERT_CHECKED(JSObject, object, args[0]);
4227 CONVERT_CHECKED(String, key, args[1]);
4228
4229 uint32_t index;
4230 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 }
4233
ager@chromium.org870a0b62008-11-04 11:43:05 +00004234 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004235 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236}
4237
4238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004239RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004242 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 return *GetKeysFor(object);
4244}
4245
4246
4247// Returns either a FixedArray as Runtime_GetPropertyNames,
4248// or, if the given object has an enum cache that contains
4249// all enumerable properties of the object and its prototypes
4250// have none, the map of the object. This is used to speed up
4251// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004252RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 ASSERT(args.length() == 1);
4254
4255 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4256
4257 if (raw_object->IsSimpleEnum()) return raw_object->map();
4258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004260 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004261 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4262 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004263
4264 // Test again, since cache may have been built by preceding call.
4265 if (object->IsSimpleEnum()) return object->map();
4266
4267 return *content;
4268}
4269
4270
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004271// Find the length of the prototype chain that is to to handled as one. If a
4272// prototype object is hidden it is to be viewed as part of the the object it
4273// is prototype for.
4274static int LocalPrototypeChainLength(JSObject* obj) {
4275 int count = 1;
4276 Object* proto = obj->GetPrototype();
4277 while (proto->IsJSObject() &&
4278 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4279 count++;
4280 proto = JSObject::cast(proto)->GetPrototype();
4281 }
4282 return count;
4283}
4284
4285
4286// Return the names of the local named properties.
4287// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004290 ASSERT(args.length() == 1);
4291 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004292 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004293 }
4294 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4295
4296 // Skip the global proxy as it has no properties and always delegates to the
4297 // real global object.
4298 if (obj->IsJSGlobalProxy()) {
4299 // Only collect names if access is permitted.
4300 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004301 !isolate->MayNamedAccess(*obj,
4302 isolate->heap()->undefined_value(),
4303 v8::ACCESS_KEYS)) {
4304 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4305 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004306 }
4307 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4308 }
4309
4310 // Find the number of objects making up this.
4311 int length = LocalPrototypeChainLength(*obj);
4312
4313 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004314 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004315 int total_property_count = 0;
4316 Handle<JSObject> jsproto = obj;
4317 for (int i = 0; i < length; i++) {
4318 // Only collect names if access is permitted.
4319 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 !isolate->MayNamedAccess(*jsproto,
4321 isolate->heap()->undefined_value(),
4322 v8::ACCESS_KEYS)) {
4323 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4324 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004325 }
4326 int n;
4327 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4328 local_property_count[i] = n;
4329 total_property_count += n;
4330 if (i < length - 1) {
4331 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4332 }
4333 }
4334
4335 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 Handle<FixedArray> names =
4337 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004338
4339 // Get the property names.
4340 jsproto = obj;
4341 int proto_with_hidden_properties = 0;
4342 for (int i = 0; i < length; i++) {
4343 jsproto->GetLocalPropertyNames(*names,
4344 i == 0 ? 0 : local_property_count[i - 1]);
4345 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4346 proto_with_hidden_properties++;
4347 }
4348 if (i < length - 1) {
4349 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4350 }
4351 }
4352
4353 // Filter out name of hidden propeties object.
4354 if (proto_with_hidden_properties > 0) {
4355 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004357 names->length() - proto_with_hidden_properties);
4358 int dest_pos = 0;
4359 for (int i = 0; i < total_property_count; i++) {
4360 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004361 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004362 continue;
4363 }
4364 names->set(dest_pos++, name);
4365 }
4366 }
4367
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004368 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004369}
4370
4371
4372// Return the names of the local indexed properties.
4373// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004374RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004375 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004376 ASSERT(args.length() == 1);
4377 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004379 }
4380 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4381
4382 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004383 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004384 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004385 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004386}
4387
4388
4389// Return information on whether an object has a named or indexed interceptor.
4390// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004391RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393 ASSERT(args.length() == 1);
4394 if (!args[0]->IsJSObject()) {
4395 return Smi::FromInt(0);
4396 }
4397 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4398
4399 int result = 0;
4400 if (obj->HasNamedInterceptor()) result |= 2;
4401 if (obj->HasIndexedInterceptor()) result |= 1;
4402
4403 return Smi::FromInt(result);
4404}
4405
4406
4407// Return property names from named interceptor.
4408// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004410 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004411 ASSERT(args.length() == 1);
4412 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4413
4414 if (obj->HasNamedInterceptor()) {
4415 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4416 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4417 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004418 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419}
4420
4421
4422// Return element names from indexed interceptor.
4423// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004424RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004425 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004426 ASSERT(args.length() == 1);
4427 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4428
4429 if (obj->HasIndexedInterceptor()) {
4430 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4431 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004434}
4435
4436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004437RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004438 ASSERT_EQ(args.length(), 1);
4439 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004441 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004442
4443 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004444 // Do access checks before going to the global object.
4445 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004447 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4449 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004450 }
4451
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004452 Handle<Object> proto(object->GetPrototype());
4453 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004454 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004455 object = Handle<JSObject>::cast(proto);
4456 }
4457
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004458 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4459 LOCAL_ONLY);
4460 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4461 // property array and since the result is mutable we have to create
4462 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004463 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004464 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004465 for (int i = 0; i < length; i++) {
4466 Object* entry = contents->get(i);
4467 if (entry->IsString()) {
4468 copy->set(i, entry);
4469 } else {
4470 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 HandleScope scope(isolate);
4472 Handle<Object> entry_handle(entry, isolate);
4473 Handle<Object> entry_str =
4474 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004475 copy->set(i, *entry_str);
4476 }
4477 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004479}
4480
4481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004482RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 NoHandleAllocation ha;
4484 ASSERT(args.length() == 1);
4485
4486 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004487 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 it.AdvanceToArgumentsFrame();
4489 JavaScriptFrame* frame = it.frame();
4490
4491 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004492 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493
4494 // Try to convert the key to an index. If successful and within
4495 // index return the the argument from the frame.
4496 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004497 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 return frame->GetParameter(index);
4499 }
4500
4501 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 bool exception = false;
4504 Handle<Object> converted =
4505 Execution::ToString(args.at<Object>(0), &exception);
4506 if (exception) return Failure::Exception();
4507 Handle<String> key = Handle<String>::cast(converted);
4508
4509 // Try to convert the string key into an array index.
4510 if (key->AsArrayIndex(&index)) {
4511 if (index < n) {
4512 return frame->GetParameter(index);
4513 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004514 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004515 }
4516 }
4517
4518 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004519 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4520 if (key->Equals(isolate->heap()->callee_symbol())) {
4521 Object* function = frame->function();
4522 if (function->IsJSFunction() &&
4523 JSFunction::cast(function)->shared()->strict_mode()) {
4524 return isolate->Throw(*isolate->factory()->NewTypeError(
4525 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4526 }
4527 return function;
4528 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529
4530 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004531 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532}
4533
4534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004535RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004536 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004537
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004538 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004539 Handle<Object> object = args.at<Object>(0);
4540 if (object->IsJSObject()) {
4541 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004542 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004543 MaybeObject* ok = js_object->TransformToFastProperties(0);
4544 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004545 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004546 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004547 return *object;
4548}
4549
4550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004551RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004553
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004554 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004555 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004556 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004557 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004558 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004559 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004560 return *object;
4561}
4562
4563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004564RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004565 NoHandleAllocation ha;
4566 ASSERT(args.length() == 1);
4567
4568 return args[0]->ToBoolean();
4569}
4570
4571
4572// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4573// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 NoHandleAllocation ha;
4576
4577 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004578 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004579 HeapObject* heap_obj = HeapObject::cast(obj);
4580
4581 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 if (heap_obj->map()->is_undetectable()) {
4583 return isolate->heap()->undefined_symbol();
4584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004585
4586 InstanceType instance_type = heap_obj->map()->instance_type();
4587 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004589 }
4590
4591 switch (instance_type) {
4592 case ODDBALL_TYPE:
4593 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 }
4596 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004597 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 }
4599 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004600 return isolate->heap()->undefined_symbol();
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00004601 case JS_FUNCTION_TYPE: case JS_REGEXP_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004602 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603 default:
4604 // For any kind of object not handled above, the spec rule for
4605 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004606 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004607 }
4608}
4609
4610
lrn@chromium.org25156de2010-04-06 13:10:27 +00004611static bool AreDigits(const char*s, int from, int to) {
4612 for (int i = from; i < to; i++) {
4613 if (s[i] < '0' || s[i] > '9') return false;
4614 }
4615
4616 return true;
4617}
4618
4619
4620static int ParseDecimalInteger(const char*s, int from, int to) {
4621 ASSERT(to - from < 10); // Overflow is not possible.
4622 ASSERT(from < to);
4623 int d = s[from] - '0';
4624
4625 for (int i = from + 1; i < to; i++) {
4626 d = 10 * d + (s[i] - '0');
4627 }
4628
4629 return d;
4630}
4631
4632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004633RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004634 NoHandleAllocation ha;
4635 ASSERT(args.length() == 1);
4636 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004637 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004638
4639 // Fast case: short integer or some sorts of junk values.
4640 int len = subject->length();
4641 if (subject->IsSeqAsciiString()) {
4642 if (len == 0) return Smi::FromInt(0);
4643
4644 char const* data = SeqAsciiString::cast(subject)->GetChars();
4645 bool minus = (data[0] == '-');
4646 int start_pos = (minus ? 1 : 0);
4647
4648 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004649 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004650 } else if (data[start_pos] > '9') {
4651 // Fast check for a junk value. A valid string may start from a
4652 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4653 // the 'I' character ('Infinity'). All of that have codes not greater than
4654 // '9' except 'I'.
4655 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004656 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004657 }
4658 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4659 // The maximal/minimal smi has 10 digits. If the string has less digits we
4660 // know it will fit into the smi-data type.
4661 int d = ParseDecimalInteger(data, start_pos, len);
4662 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004663 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004664 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004665 } else if (!subject->HasHashCode() &&
4666 len <= String::kMaxArrayIndexSize &&
4667 (len == 1 || data[0] != '0')) {
4668 // String hash is not calculated yet but all the data are present.
4669 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004670 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004671#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004672 subject->Hash(); // Force hash calculation.
4673 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4674 static_cast<int>(hash));
4675#endif
4676 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004677 }
4678 return Smi::FromInt(d);
4679 }
4680 }
4681
4682 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004683 return isolate->heap()->NumberFromDouble(
4684 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685}
4686
4687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004688RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689 NoHandleAllocation ha;
4690 ASSERT(args.length() == 1);
4691
4692 CONVERT_CHECKED(JSArray, codes, args[0]);
4693 int length = Smi::cast(codes->length())->value();
4694
4695 // Check if the string can be ASCII.
4696 int i;
4697 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004698 Object* element;
4699 { MaybeObject* maybe_element = codes->GetElement(i);
4700 // We probably can't get an exception here, but just in order to enforce
4701 // the checking of inputs in the runtime calls we check here.
4702 if (!maybe_element->ToObject(&element)) return maybe_element;
4703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4705 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4706 break;
4707 }
4708
lrn@chromium.org303ada72010-10-27 09:33:13 +00004709 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004711 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004713 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004714 }
4715
lrn@chromium.org303ada72010-10-27 09:33:13 +00004716 Object* object = NULL;
4717 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 String* result = String::cast(object);
4719 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004720 Object* element;
4721 { MaybeObject* maybe_element = codes->GetElement(i);
4722 if (!maybe_element->ToObject(&element)) return maybe_element;
4723 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004725 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004726 }
4727 return result;
4728}
4729
4730
4731// kNotEscaped is generated by the following:
4732//
4733// #!/bin/perl
4734// for (my $i = 0; $i < 256; $i++) {
4735// print "\n" if $i % 16 == 0;
4736// my $c = chr($i);
4737// my $escaped = 1;
4738// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4739// print $escaped ? "0, " : "1, ";
4740// }
4741
4742
4743static bool IsNotEscaped(uint16_t character) {
4744 // Only for 8 bit characters, the rest are always escaped (in a different way)
4745 ASSERT(character < 256);
4746 static const char kNotEscaped[256] = {
4747 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4748 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4749 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4750 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4752 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4753 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4754 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4759 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4760 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4761 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4762 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4763 };
4764 return kNotEscaped[character] != 0;
4765}
4766
4767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004768RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 const char hex_chars[] = "0123456789ABCDEF";
4770 NoHandleAllocation ha;
4771 ASSERT(args.length() == 1);
4772 CONVERT_CHECKED(String, source, args[0]);
4773
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004774 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
4776 int escaped_length = 0;
4777 int length = source->length();
4778 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004779 Access<StringInputBuffer> buffer(
4780 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 buffer->Reset(source);
4782 while (buffer->has_more()) {
4783 uint16_t character = buffer->GetNext();
4784 if (character >= 256) {
4785 escaped_length += 6;
4786 } else if (IsNotEscaped(character)) {
4787 escaped_length++;
4788 } else {
4789 escaped_length += 3;
4790 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004791 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004792 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004793 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004794 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795 return Failure::OutOfMemoryException();
4796 }
4797 }
4798 }
4799 // No length change implies no change. Return original string if no change.
4800 if (escaped_length == length) {
4801 return source;
4802 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004803 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004804 { MaybeObject* maybe_o =
4805 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004806 if (!maybe_o->ToObject(&o)) return maybe_o;
4807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004808 String* destination = String::cast(o);
4809 int dest_position = 0;
4810
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004811 Access<StringInputBuffer> buffer(
4812 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 buffer->Rewind();
4814 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004815 uint16_t chr = buffer->GetNext();
4816 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004817 destination->Set(dest_position, '%');
4818 destination->Set(dest_position+1, 'u');
4819 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4820 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4821 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4822 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004824 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004825 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 dest_position++;
4827 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004828 destination->Set(dest_position, '%');
4829 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4830 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 dest_position += 3;
4832 }
4833 }
4834 return destination;
4835}
4836
4837
4838static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4839 static const signed char kHexValue['g'] = {
4840 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4841 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4842 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4843 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4844 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4845 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4846 -1, 10, 11, 12, 13, 14, 15 };
4847
4848 if (character1 > 'f') return -1;
4849 int hi = kHexValue[character1];
4850 if (hi == -1) return -1;
4851 if (character2 > 'f') return -1;
4852 int lo = kHexValue[character2];
4853 if (lo == -1) return -1;
4854 return (hi << 4) + lo;
4855}
4856
4857
ager@chromium.org870a0b62008-11-04 11:43:05 +00004858static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004859 int i,
4860 int length,
4861 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004862 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004863 int32_t hi = 0;
4864 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 if (character == '%' &&
4866 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004867 source->Get(i + 1) == 'u' &&
4868 (hi = TwoDigitHex(source->Get(i + 2),
4869 source->Get(i + 3))) != -1 &&
4870 (lo = TwoDigitHex(source->Get(i + 4),
4871 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872 *step = 6;
4873 return (hi << 8) + lo;
4874 } else if (character == '%' &&
4875 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004876 (lo = TwoDigitHex(source->Get(i + 1),
4877 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 *step = 3;
4879 return lo;
4880 } else {
4881 *step = 1;
4882 return character;
4883 }
4884}
4885
4886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004887RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 NoHandleAllocation ha;
4889 ASSERT(args.length() == 1);
4890 CONVERT_CHECKED(String, source, args[0]);
4891
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004892 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893
4894 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004895 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896
4897 int unescaped_length = 0;
4898 for (int i = 0; i < length; unescaped_length++) {
4899 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004900 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004902 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004903 i += step;
4904 }
4905
4906 // No length change implies no change. Return original string if no change.
4907 if (unescaped_length == length)
4908 return source;
4909
lrn@chromium.org303ada72010-10-27 09:33:13 +00004910 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004911 { MaybeObject* maybe_o =
4912 ascii ?
4913 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
4914 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 if (!maybe_o->ToObject(&o)) return maybe_o;
4916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004917 String* destination = String::cast(o);
4918
4919 int dest_position = 0;
4920 for (int i = 0; i < length; dest_position++) {
4921 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004922 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923 i += step;
4924 }
4925 return destination;
4926}
4927
4928
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004929static const unsigned int kQuoteTableLength = 128u;
4930
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004931static const int kJsonQuotesCharactersPerEntry = 8;
4932static const char* const JsonQuotes =
4933 "\\u0000 \\u0001 \\u0002 \\u0003 "
4934 "\\u0004 \\u0005 \\u0006 \\u0007 "
4935 "\\b \\t \\n \\u000b "
4936 "\\f \\r \\u000e \\u000f "
4937 "\\u0010 \\u0011 \\u0012 \\u0013 "
4938 "\\u0014 \\u0015 \\u0016 \\u0017 "
4939 "\\u0018 \\u0019 \\u001a \\u001b "
4940 "\\u001c \\u001d \\u001e \\u001f "
4941 " ! \\\" # "
4942 "$ % & ' "
4943 "( ) * + "
4944 ", - . / "
4945 "0 1 2 3 "
4946 "4 5 6 7 "
4947 "8 9 : ; "
4948 "< = > ? "
4949 "@ A B C "
4950 "D E F G "
4951 "H I J K "
4952 "L M N O "
4953 "P Q R S "
4954 "T U V W "
4955 "X Y Z [ "
4956 "\\\\ ] ^ _ "
4957 "` a b c "
4958 "d e f g "
4959 "h i j k "
4960 "l m n o "
4961 "p q r s "
4962 "t u v w "
4963 "x y z { "
4964 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004965
4966
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004967// For a string that is less than 32k characters it should always be
4968// possible to allocate it in new space.
4969static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
4970
4971
4972// Doing JSON quoting cannot make the string more than this many times larger.
4973static const int kJsonQuoteWorstCaseBlowup = 6;
4974
4975
4976// Covers the entire ASCII range (all other characters are unchanged by JSON
4977// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004978static const byte JsonQuoteLengths[kQuoteTableLength] = {
4979 6, 6, 6, 6, 6, 6, 6, 6,
4980 2, 2, 2, 6, 2, 2, 6, 6,
4981 6, 6, 6, 6, 6, 6, 6, 6,
4982 6, 6, 6, 6, 6, 6, 6, 6,
4983 1, 1, 2, 1, 1, 1, 1, 1,
4984 1, 1, 1, 1, 1, 1, 1, 1,
4985 1, 1, 1, 1, 1, 1, 1, 1,
4986 1, 1, 1, 1, 1, 1, 1, 1,
4987 1, 1, 1, 1, 1, 1, 1, 1,
4988 1, 1, 1, 1, 1, 1, 1, 1,
4989 1, 1, 1, 1, 1, 1, 1, 1,
4990 1, 1, 1, 1, 2, 1, 1, 1,
4991 1, 1, 1, 1, 1, 1, 1, 1,
4992 1, 1, 1, 1, 1, 1, 1, 1,
4993 1, 1, 1, 1, 1, 1, 1, 1,
4994 1, 1, 1, 1, 1, 1, 1, 1,
4995};
4996
4997
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004998template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004999MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005000
5001
5002template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005003MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5004 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005005}
5006
5007
5008template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005009MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5010 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005011}
5012
5013
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005014template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005015static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5016 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005017 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005018 const Char* read_cursor = characters.start();
5019 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005020 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005021 int quoted_length = kSpaceForQuotes;
5022 while (read_cursor < end) {
5023 Char c = *(read_cursor++);
5024 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5025 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005026 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005027 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005028 }
5029 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005030 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5031 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005032 Object* new_object;
5033 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005034 return new_alloc;
5035 }
5036 StringType* new_string = StringType::cast(new_object);
5037
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005038 Char* write_cursor = reinterpret_cast<Char*>(
5039 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005040 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005041 *(write_cursor++) = '"';
5042
5043 read_cursor = characters.start();
5044 while (read_cursor < end) {
5045 Char c = *(read_cursor++);
5046 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5047 *(write_cursor++) = c;
5048 } else {
5049 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5050 const char* replacement = JsonQuotes +
5051 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5052 for (int i = 0; i < len; i++) {
5053 *write_cursor++ = *replacement++;
5054 }
5055 }
5056 }
5057 *(write_cursor++) = '"';
5058 return new_string;
5059}
5060
5061
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005062template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063static MaybeObject* QuoteJsonString(Isolate* isolate,
5064 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005065 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005066 isolate->counters()->quote_json_char_count()->Increment(length);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005067 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005068 int worst_case_length = length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes;
5069 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005071 }
5072
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5074 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005075 Object* new_object;
5076 if (!new_alloc->ToObject(&new_object)) {
5077 return new_alloc;
5078 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005080 // Even if our string is small enough to fit in new space we still have to
5081 // handle it being allocated in old space as may happen in the third
5082 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5083 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005084 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005085 }
5086 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005088
5089 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5090 Char* write_cursor = reinterpret_cast<Char*>(
5091 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005092 if (comma) *(write_cursor++) = ',';
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005093 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005094
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005095 const Char* read_cursor = characters.start();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005096 const Char* end = read_cursor + length;
5097 while (read_cursor < end) {
5098 Char c = *(read_cursor++);
5099 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5100 *(write_cursor++) = c;
5101 } else {
5102 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5103 const char* replacement = JsonQuotes +
5104 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5105 write_cursor[0] = replacement[0];
5106 if (len > 1) {
5107 write_cursor[1] = replacement[1];
5108 if (len > 2) {
5109 ASSERT(len == 6);
5110 write_cursor[2] = replacement[2];
5111 write_cursor[3] = replacement[3];
5112 write_cursor[4] = replacement[4];
5113 write_cursor[5] = replacement[5];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114 }
5115 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005116 write_cursor += len;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005117 }
5118 }
5119 *(write_cursor++) = '"';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005120
5121 int final_length = static_cast<int>(
5122 write_cursor - reinterpret_cast<Char*>(
5123 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005124 isolate->heap()->new_space()->
5125 template ShrinkStringAtAllocationBoundary<StringType>(
5126 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005127 return new_string;
5128}
5129
5130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005131RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005132 NoHandleAllocation ha;
5133 CONVERT_CHECKED(String, str, args[0]);
5134 if (!str->IsFlat()) {
5135 MaybeObject* try_flatten = str->TryFlatten();
5136 Object* flat;
5137 if (!try_flatten->ToObject(&flat)) {
5138 return try_flatten;
5139 }
5140 str = String::cast(flat);
5141 ASSERT(str->IsFlat());
5142 }
5143 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5145 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005146 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005147 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5148 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005149 }
5150}
5151
5152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005153RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005154 NoHandleAllocation ha;
5155 CONVERT_CHECKED(String, str, args[0]);
5156 if (!str->IsFlat()) {
5157 MaybeObject* try_flatten = str->TryFlatten();
5158 Object* flat;
5159 if (!try_flatten->ToObject(&flat)) {
5160 return try_flatten;
5161 }
5162 str = String::cast(flat);
5163 ASSERT(str->IsFlat());
5164 }
5165 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005166 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5167 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005168 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005169 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5170 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005171 }
5172}
5173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005174RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 NoHandleAllocation ha;
5176
5177 CONVERT_CHECKED(String, s, args[0]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005178 CONVERT_SMI_CHECKED(radix, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005180 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181
lrn@chromium.org25156de2010-04-06 13:10:27 +00005182 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005183 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185}
5186
5187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005188RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189 NoHandleAllocation ha;
5190 CONVERT_CHECKED(String, str, args[0]);
5191
5192 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005193 double value = StringToDouble(isolate->unicode_cache(),
5194 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195
5196 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005197 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198}
5199
5200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005202MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005204 String* s,
5205 int length,
5206 int input_string_length,
5207 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005208 // We try this twice, once with the assumption that the result is no longer
5209 // than the input and, if that assumption breaks, again with the exact
5210 // length. This may not be pretty, but it is nicer than what was here before
5211 // and I hereby claim my vaffel-is.
5212 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005213 // Allocate the resulting string.
5214 //
5215 // NOTE: This assumes that the upper/lower case of an ascii
5216 // character is also ascii. This is currently the case, but it
5217 // might break in the future if we implement more context and locale
5218 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005219 Object* o;
5220 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 ? isolate->heap()->AllocateRawAsciiString(length)
5222 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005223 if (!maybe_o->ToObject(&o)) return maybe_o;
5224 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005225 String* result = String::cast(o);
5226 bool has_changed_character = false;
5227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 // Convert all characters to upper case, assuming that they will fit
5229 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005230 Access<StringInputBuffer> buffer(
5231 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005232 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005233 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234 // We can assume that the string is not empty
5235 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005236 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005237 bool has_next = buffer->has_more();
5238 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005239 int char_length = mapping->get(current, next, chars);
5240 if (char_length == 0) {
5241 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005242 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 i++;
5244 } else if (char_length == 1) {
5245 // Common case: converting the letter resulted in one character.
5246 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005247 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248 has_changed_character = true;
5249 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005250 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 // We've assumed that the result would be as long as the
5252 // input but here is a character that converts to several
5253 // characters. No matter, we calculate the exact length
5254 // of the result and try the whole thing again.
5255 //
5256 // Note that this leaves room for optimization. We could just
5257 // memcpy what we already have to the result string. Also,
5258 // the result string is the last object allocated we could
5259 // "realloc" it and probably, in the vast majority of cases,
5260 // extend the existing string to be able to hold the full
5261 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005262 int next_length = 0;
5263 if (has_next) {
5264 next_length = mapping->get(next, 0, chars);
5265 if (next_length == 0) next_length = 1;
5266 }
5267 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 while (buffer->has_more()) {
5269 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005270 // NOTE: we use 0 as the next character here because, while
5271 // the next character may affect what a character converts to,
5272 // it does not in any case affect the length of what it convert
5273 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005274 int char_length = mapping->get(current, 0, chars);
5275 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005276 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005277 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005278 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005279 return Failure::OutOfMemoryException();
5280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005281 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005282 // Try again with the real length.
5283 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005284 } else {
5285 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005286 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005287 i++;
5288 }
5289 has_changed_character = true;
5290 }
5291 current = next;
5292 }
5293 if (has_changed_character) {
5294 return result;
5295 } else {
5296 // If we didn't actually change anything in doing the conversion
5297 // we simple return the result and let the converted string
5298 // become garbage; there is no reason to keep two identical strings
5299 // alive.
5300 return s;
5301 }
5302}
5303
5304
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005305namespace {
5306
lrn@chromium.org303ada72010-10-27 09:33:13 +00005307static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5308
5309
5310// Given a word and two range boundaries returns a word with high bit
5311// set in every byte iff the corresponding input byte was strictly in
5312// the range (m, n). All the other bits in the result are cleared.
5313// This function is only useful when it can be inlined and the
5314// boundaries are statically known.
5315// Requires: all bytes in the input word and the boundaries must be
5316// ascii (less than 0x7F).
5317static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5318 // Every byte in an ascii string is less than or equal to 0x7F.
5319 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5320 // Use strict inequalities since in edge cases the function could be
5321 // further simplified.
5322 ASSERT(0 < m && m < n && n < 0x7F);
5323 // Has high bit set in every w byte less than n.
5324 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5325 // Has high bit set in every w byte greater than m.
5326 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5327 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5328}
5329
5330
5331enum AsciiCaseConversion {
5332 ASCII_TO_LOWER,
5333 ASCII_TO_UPPER
5334};
5335
5336
5337template <AsciiCaseConversion dir>
5338struct FastAsciiConverter {
5339 static bool Convert(char* dst, char* src, int length) {
5340#ifdef DEBUG
5341 char* saved_dst = dst;
5342 char* saved_src = src;
5343#endif
5344 // We rely on the distance between upper and lower case letters
5345 // being a known power of 2.
5346 ASSERT('a' - 'A' == (1 << 5));
5347 // Boundaries for the range of input characters than require conversion.
5348 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5349 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5350 bool changed = false;
5351 char* const limit = src + length;
5352#ifdef V8_HOST_CAN_READ_UNALIGNED
5353 // Process the prefix of the input that requires no conversion one
5354 // (machine) word at a time.
5355 while (src <= limit - sizeof(uintptr_t)) {
5356 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5357 if (AsciiRangeMask(w, lo, hi) != 0) {
5358 changed = true;
5359 break;
5360 }
5361 *reinterpret_cast<uintptr_t*>(dst) = w;
5362 src += sizeof(uintptr_t);
5363 dst += sizeof(uintptr_t);
5364 }
5365 // Process the remainder of the input performing conversion when
5366 // required one word at a time.
5367 while (src <= limit - sizeof(uintptr_t)) {
5368 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5369 uintptr_t m = AsciiRangeMask(w, lo, hi);
5370 // The mask has high (7th) bit set in every byte that needs
5371 // conversion and we know that the distance between cases is
5372 // 1 << 5.
5373 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5374 src += sizeof(uintptr_t);
5375 dst += sizeof(uintptr_t);
5376 }
5377#endif
5378 // Process the last few bytes of the input (or the whole input if
5379 // unaligned access is not supported).
5380 while (src < limit) {
5381 char c = *src;
5382 if (lo < c && c < hi) {
5383 c ^= (1 << 5);
5384 changed = true;
5385 }
5386 *dst = c;
5387 ++src;
5388 ++dst;
5389 }
5390#ifdef DEBUG
5391 CheckConvert(saved_dst, saved_src, length, changed);
5392#endif
5393 return changed;
5394 }
5395
5396#ifdef DEBUG
5397 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5398 bool expected_changed = false;
5399 for (int i = 0; i < length; i++) {
5400 if (dst[i] == src[i]) continue;
5401 expected_changed = true;
5402 if (dir == ASCII_TO_LOWER) {
5403 ASSERT('A' <= src[i] && src[i] <= 'Z');
5404 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5405 } else {
5406 ASSERT(dir == ASCII_TO_UPPER);
5407 ASSERT('a' <= src[i] && src[i] <= 'z');
5408 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5409 }
5410 }
5411 ASSERT(expected_changed == changed);
5412 }
5413#endif
5414};
5415
5416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005417struct ToLowerTraits {
5418 typedef unibrow::ToLowercase UnibrowConverter;
5419
lrn@chromium.org303ada72010-10-27 09:33:13 +00005420 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005421};
5422
5423
5424struct ToUpperTraits {
5425 typedef unibrow::ToUppercase UnibrowConverter;
5426
lrn@chromium.org303ada72010-10-27 09:33:13 +00005427 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005428};
5429
5430} // namespace
5431
5432
5433template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005434MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005435 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005436 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005437 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005438 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005439 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005440 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005441
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005442 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005443 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005444 if (length == 0) return s;
5445
5446 // Simpler handling of ascii strings.
5447 //
5448 // NOTE: This assumes that the upper/lower case of an ascii
5449 // character is also ascii. This is currently the case, but it
5450 // might break in the future if we implement more context and locale
5451 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005452 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005453 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005454 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005455 if (!maybe_o->ToObject(&o)) return maybe_o;
5456 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005457 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005458 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005459 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005460 return has_changed_character ? result : s;
5461 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462
lrn@chromium.org303ada72010-10-27 09:33:13 +00005463 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005464 { MaybeObject* maybe_answer =
5465 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005466 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5467 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005468 if (answer->IsSmi()) {
5469 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005470 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005471 ConvertCaseHelper(isolate,
5472 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005473 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5474 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005475 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005476 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005477}
5478
5479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005480RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005481 return ConvertCase<ToLowerTraits>(
5482 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005483}
5484
5485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005486RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005487 return ConvertCase<ToUpperTraits>(
5488 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489}
5490
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005491
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005492static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5493 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5494}
5495
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005497RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005498 NoHandleAllocation ha;
5499 ASSERT(args.length() == 3);
5500
5501 CONVERT_CHECKED(String, s, args[0]);
5502 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5503 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5504
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005505 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005506 int length = s->length();
5507
5508 int left = 0;
5509 if (trimLeft) {
5510 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5511 left++;
5512 }
5513 }
5514
5515 int right = length;
5516 if (trimRight) {
5517 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5518 right--;
5519 }
5520 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005521 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005522}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005524
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005525template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005526void FindStringIndices(Isolate* isolate,
5527 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005528 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005529 ZoneList<int>* indices,
5530 unsigned int limit) {
5531 ASSERT(limit > 0);
5532 // Collect indices of pattern in subject, and the end-of-string index.
5533 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005534 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005535 int pattern_length = pattern.length();
5536 int index = 0;
5537 while (limit > 0) {
5538 index = search.Search(subject, index);
5539 if (index < 0) return;
5540 indices->Add(index);
5541 index += pattern_length;
5542 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005543 }
5544}
5545
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005547RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005548 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005549 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005550 CONVERT_ARG_CHECKED(String, subject, 0);
5551 CONVERT_ARG_CHECKED(String, pattern, 1);
5552 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5553
5554 int subject_length = subject->length();
5555 int pattern_length = pattern->length();
5556 RUNTIME_ASSERT(pattern_length > 0);
5557
5558 // The limit can be very large (0xffffffffu), but since the pattern
5559 // isn't empty, we can never create more parts than ~half the length
5560 // of the subject.
5561
5562 if (!subject->IsFlat()) FlattenString(subject);
5563
5564 static const int kMaxInitialListCapacity = 16;
5565
5566 ZoneScope scope(DELETE_ON_EXIT);
5567
5568 // Find (up to limit) indices of separator and end-of-string in subject
5569 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5570 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005571 if (!pattern->IsFlat()) FlattenString(pattern);
5572
5573 // No allocation block.
5574 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005575 AssertNoAllocation nogc;
5576 if (subject->IsAsciiRepresentation()) {
5577 Vector<const char> subject_vector = subject->ToAsciiVector();
5578 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005579 FindStringIndices(isolate,
5580 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005581 pattern->ToAsciiVector(),
5582 &indices,
5583 limit);
5584 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005585 FindStringIndices(isolate,
5586 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005587 pattern->ToUC16Vector(),
5588 &indices,
5589 limit);
5590 }
5591 } else {
5592 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5593 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005594 FindStringIndices(isolate,
5595 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005596 pattern->ToAsciiVector(),
5597 &indices,
5598 limit);
5599 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005600 FindStringIndices(isolate,
5601 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005602 pattern->ToUC16Vector(),
5603 &indices,
5604 limit);
5605 }
5606 }
5607 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005608
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005609 if (static_cast<uint32_t>(indices.length()) < limit) {
5610 indices.Add(subject_length);
5611 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005612
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005613 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005614
5615 // Create JSArray of substrings separated by separator.
5616 int part_count = indices.length();
5617
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005619 result->set_length(Smi::FromInt(part_count));
5620
5621 ASSERT(result->HasFastElements());
5622
5623 if (part_count == 1 && indices.at(0) == subject_length) {
5624 FixedArray::cast(result->elements())->set(0, *subject);
5625 return *result;
5626 }
5627
5628 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5629 int part_start = 0;
5630 for (int i = 0; i < part_count; i++) {
5631 HandleScope local_loop_handle;
5632 int part_end = indices.at(i);
5633 Handle<String> substring =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005634 isolate->factory()->NewSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005635 elements->set(i, *substring);
5636 part_start = part_end + pattern_length;
5637 }
5638
5639 return *result;
5640}
5641
5642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005643// Copies ascii characters to the given fixed array looking up
5644// one-char strings in the cache. Gives up on the first char that is
5645// not in the cache and fills the remainder with smi zeros. Returns
5646// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005647static int CopyCachedAsciiCharsToArray(Heap* heap,
5648 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005649 FixedArray* elements,
5650 int length) {
5651 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005652 FixedArray* ascii_cache = heap->single_character_string_cache();
5653 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005654 int i;
5655 for (i = 0; i < length; ++i) {
5656 Object* value = ascii_cache->get(chars[i]);
5657 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005659 elements->set(i, value, SKIP_WRITE_BARRIER);
5660 }
5661 if (i < length) {
5662 ASSERT(Smi::FromInt(0) == 0);
5663 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5664 }
5665#ifdef DEBUG
5666 for (int j = 0; j < length; ++j) {
5667 Object* element = elements->get(j);
5668 ASSERT(element == Smi::FromInt(0) ||
5669 (element->IsString() && String::cast(element)->LooksValid()));
5670 }
5671#endif
5672 return i;
5673}
5674
5675
5676// Converts a String to JSArray.
5677// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005678RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005680 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005681 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005682 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005683
5684 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005685 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005686
5687 Handle<FixedArray> elements;
5688 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005689 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005690 { MaybeObject* maybe_obj =
5691 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005692 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5693 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005694 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005695
5696 Vector<const char> chars = s->ToAsciiVector();
5697 // Note, this will initialize all elements (not only the prefix)
5698 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005699 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5700 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005701 *elements,
5702 length);
5703
5704 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005705 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5706 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005707 }
5708 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005709 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005710 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005711 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5712 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713 }
5714 }
5715
5716#ifdef DEBUG
5717 for (int i = 0; i < length; ++i) {
5718 ASSERT(String::cast(elements->get(i))->length() == 1);
5719 }
5720#endif
5721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005722 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005723}
5724
5725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005726RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005727 NoHandleAllocation ha;
5728 ASSERT(args.length() == 1);
5729 CONVERT_CHECKED(String, value, args[0]);
5730 return value->ToObject();
5731}
5732
5733
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005734bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005735 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005736 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005737 return char_length == 0;
5738}
5739
5740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005741RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742 NoHandleAllocation ha;
5743 ASSERT(args.length() == 1);
5744
5745 Object* number = args[0];
5746 RUNTIME_ASSERT(number->IsNumber());
5747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005748 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005749}
5750
5751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005752RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005753 NoHandleAllocation ha;
5754 ASSERT(args.length() == 1);
5755
5756 Object* number = args[0];
5757 RUNTIME_ASSERT(number->IsNumber());
5758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005759 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005760}
5761
5762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005763RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005764 NoHandleAllocation ha;
5765 ASSERT(args.length() == 1);
5766
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005767 CONVERT_DOUBLE_CHECKED(number, args[0]);
5768
5769 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5770 if (number > 0 && number <= Smi::kMaxValue) {
5771 return Smi::FromInt(static_cast<int>(number));
5772 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005773 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005774}
5775
5776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005777RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005778 NoHandleAllocation ha;
5779 ASSERT(args.length() == 1);
5780
5781 CONVERT_DOUBLE_CHECKED(number, args[0]);
5782
5783 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5784 if (number > 0 && number <= Smi::kMaxValue) {
5785 return Smi::FromInt(static_cast<int>(number));
5786 }
5787
5788 double double_value = DoubleToInteger(number);
5789 // Map both -0 and +0 to +0.
5790 if (double_value == 0) double_value = 0;
5791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005792 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005793}
5794
5795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005796RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005797 NoHandleAllocation ha;
5798 ASSERT(args.length() == 1);
5799
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005800 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005802}
5803
5804
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005805RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005806 NoHandleAllocation ha;
5807 ASSERT(args.length() == 1);
5808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005809 CONVERT_DOUBLE_CHECKED(number, args[0]);
5810
5811 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5812 if (number > 0 && number <= Smi::kMaxValue) {
5813 return Smi::FromInt(static_cast<int>(number));
5814 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005815 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005816}
5817
5818
ager@chromium.org870a0b62008-11-04 11:43:05 +00005819// Converts a Number to a Smi, if possible. Returns NaN if the number is not
5820// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005821RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005822 NoHandleAllocation ha;
5823 ASSERT(args.length() == 1);
5824
5825 Object* obj = args[0];
5826 if (obj->IsSmi()) {
5827 return obj;
5828 }
5829 if (obj->IsHeapNumber()) {
5830 double value = HeapNumber::cast(obj)->value();
5831 int int_value = FastD2I(value);
5832 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
5833 return Smi::FromInt(int_value);
5834 }
5835 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005836 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005837}
5838
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005840RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005841 NoHandleAllocation ha;
5842 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005843 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005844}
5845
5846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005847RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005848 NoHandleAllocation ha;
5849 ASSERT(args.length() == 2);
5850
5851 CONVERT_DOUBLE_CHECKED(x, args[0]);
5852 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005853 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854}
5855
5856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005857RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005858 NoHandleAllocation ha;
5859 ASSERT(args.length() == 2);
5860
5861 CONVERT_DOUBLE_CHECKED(x, args[0]);
5862 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005863 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005864}
5865
5866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005867RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 NoHandleAllocation ha;
5869 ASSERT(args.length() == 2);
5870
5871 CONVERT_DOUBLE_CHECKED(x, args[0]);
5872 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005873 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005874}
5875
5876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005877RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005878 NoHandleAllocation ha;
5879 ASSERT(args.length() == 1);
5880
5881 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005882 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883}
5884
5885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005886RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005887 NoHandleAllocation ha;
5888 ASSERT(args.length() == 0);
5889
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005890 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00005891}
5892
5893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895 NoHandleAllocation ha;
5896 ASSERT(args.length() == 2);
5897
5898 CONVERT_DOUBLE_CHECKED(x, args[0]);
5899 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005900 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005901}
5902
5903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005904RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005905 NoHandleAllocation ha;
5906 ASSERT(args.length() == 2);
5907
5908 CONVERT_DOUBLE_CHECKED(x, args[0]);
5909 CONVERT_DOUBLE_CHECKED(y, args[1]);
5910
ager@chromium.org3811b432009-10-28 14:53:37 +00005911 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005912 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005913 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914}
5915
5916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005917RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005918 NoHandleAllocation ha;
5919 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005920 CONVERT_CHECKED(String, str1, args[0]);
5921 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005922 isolate->counters()->string_add_runtime()->Increment();
5923 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005924}
5925
5926
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005927template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005928static inline void StringBuilderConcatHelper(String* special,
5929 sinkchar* sink,
5930 FixedArray* fixed_array,
5931 int array_length) {
5932 int position = 0;
5933 for (int i = 0; i < array_length; i++) {
5934 Object* element = fixed_array->get(i);
5935 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005936 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005937 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005938 int pos;
5939 int len;
5940 if (encoded_slice > 0) {
5941 // Position and length encoded in one smi.
5942 pos = StringBuilderSubstringPosition::decode(encoded_slice);
5943 len = StringBuilderSubstringLength::decode(encoded_slice);
5944 } else {
5945 // Position and length encoded in two smis.
5946 Object* obj = fixed_array->get(++i);
5947 ASSERT(obj->IsSmi());
5948 pos = Smi::cast(obj)->value();
5949 len = -encoded_slice;
5950 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00005951 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005952 sink + position,
5953 pos,
5954 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005955 position += len;
5956 } else {
5957 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005958 int element_length = string->length();
5959 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005960 position += element_length;
5961 }
5962 }
5963}
5964
5965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005966RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005967 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005968 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005970 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005971 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005972 return Failure::OutOfMemoryException();
5973 }
5974 int array_length = Smi::cast(args[1])->value();
5975 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005976
5977 // This assumption is used by the slice encoding in one or two smis.
5978 ASSERT(Smi::kMaxValue >= String::kMaxLength);
5979
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005980 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983 }
5984 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005985 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005986 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005987 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988
5989 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005990 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005991 } else if (array_length == 1) {
5992 Object* first = fixed_array->get(0);
5993 if (first->IsString()) return first;
5994 }
5995
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005996 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005997 int position = 0;
5998 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005999 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000 Object* elt = fixed_array->get(i);
6001 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006002 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006003 int smi_value = Smi::cast(elt)->value();
6004 int pos;
6005 int len;
6006 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006007 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006008 pos = StringBuilderSubstringPosition::decode(smi_value);
6009 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006010 } else {
6011 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006012 len = -smi_value;
6013 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006014 i++;
6015 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006016 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006017 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006018 Object* next_smi = fixed_array->get(i);
6019 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006020 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006021 }
6022 pos = Smi::cast(next_smi)->value();
6023 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006024 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006027 ASSERT(pos >= 0);
6028 ASSERT(len >= 0);
6029 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006030 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006031 }
6032 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 } else if (elt->IsString()) {
6034 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006035 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006036 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006037 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006039 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006040 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006041 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006042 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006043 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006044 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006045 return Failure::OutOfMemoryException();
6046 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006047 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 }
6049
6050 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006051 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006054 { MaybeObject* maybe_object =
6055 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056 if (!maybe_object->ToObject(&object)) return maybe_object;
6057 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006058 SeqAsciiString* answer = SeqAsciiString::cast(object);
6059 StringBuilderConcatHelper(special,
6060 answer->GetChars(),
6061 fixed_array,
6062 array_length);
6063 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006064 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 { MaybeObject* maybe_object =
6066 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006067 if (!maybe_object->ToObject(&object)) return maybe_object;
6068 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006069 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6070 StringBuilderConcatHelper(special,
6071 answer->GetChars(),
6072 fixed_array,
6073 array_length);
6074 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076}
6077
6078
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006079RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006080 NoHandleAllocation ha;
6081 ASSERT(args.length() == 3);
6082 CONVERT_CHECKED(JSArray, array, args[0]);
6083 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006084 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006085 return Failure::OutOfMemoryException();
6086 }
6087 int array_length = Smi::cast(args[1])->value();
6088 CONVERT_CHECKED(String, separator, args[2]);
6089
6090 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006091 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006092 }
6093 FixedArray* fixed_array = FixedArray::cast(array->elements());
6094 if (fixed_array->length() < array_length) {
6095 array_length = fixed_array->length();
6096 }
6097
6098 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006100 } else if (array_length == 1) {
6101 Object* first = fixed_array->get(0);
6102 if (first->IsString()) return first;
6103 }
6104
6105 int separator_length = separator->length();
6106 int max_nof_separators =
6107 (String::kMaxLength + separator_length - 1) / separator_length;
6108 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006110 return Failure::OutOfMemoryException();
6111 }
6112 int length = (array_length - 1) * separator_length;
6113 for (int i = 0; i < array_length; i++) {
6114 Object* element_obj = fixed_array->get(i);
6115 if (!element_obj->IsString()) {
6116 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006117 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006118 }
6119 String* element = String::cast(element_obj);
6120 int increment = element->length();
6121 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006122 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006123 return Failure::OutOfMemoryException();
6124 }
6125 length += increment;
6126 }
6127
6128 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006129 { MaybeObject* maybe_object =
6130 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006131 if (!maybe_object->ToObject(&object)) return maybe_object;
6132 }
6133 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6134
6135 uc16* sink = answer->GetChars();
6136#ifdef DEBUG
6137 uc16* end = sink + length;
6138#endif
6139
6140 String* first = String::cast(fixed_array->get(0));
6141 int first_length = first->length();
6142 String::WriteToFlat(first, sink, 0, first_length);
6143 sink += first_length;
6144
6145 for (int i = 1; i < array_length; i++) {
6146 ASSERT(sink + separator_length <= end);
6147 String::WriteToFlat(separator, sink, 0, separator_length);
6148 sink += separator_length;
6149
6150 String* element = String::cast(fixed_array->get(i));
6151 int element_length = element->length();
6152 ASSERT(sink + element_length <= end);
6153 String::WriteToFlat(element, sink, 0, element_length);
6154 sink += element_length;
6155 }
6156 ASSERT(sink == end);
6157
6158 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6159 return answer;
6160}
6161
6162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006163RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006164 NoHandleAllocation ha;
6165 ASSERT(args.length() == 2);
6166
6167 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6168 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006169 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170}
6171
6172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006173RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006174 NoHandleAllocation ha;
6175 ASSERT(args.length() == 2);
6176
6177 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6178 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006179 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006180}
6181
6182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006183RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006184 NoHandleAllocation ha;
6185 ASSERT(args.length() == 2);
6186
6187 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6188 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006189 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006190}
6191
6192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006193RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006194 NoHandleAllocation ha;
6195 ASSERT(args.length() == 1);
6196
6197 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006198 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006199}
6200
6201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006202RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203 NoHandleAllocation ha;
6204 ASSERT(args.length() == 2);
6205
6206 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6207 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006208 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006209}
6210
6211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006212RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006213 NoHandleAllocation ha;
6214 ASSERT(args.length() == 2);
6215
6216 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6217 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006218 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006219}
6220
6221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006222RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006223 NoHandleAllocation ha;
6224 ASSERT(args.length() == 2);
6225
6226 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6227 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006229}
6230
6231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006232RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006233 NoHandleAllocation ha;
6234 ASSERT(args.length() == 2);
6235
6236 CONVERT_DOUBLE_CHECKED(x, args[0]);
6237 CONVERT_DOUBLE_CHECKED(y, args[1]);
6238 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6239 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6240 if (x == y) return Smi::FromInt(EQUAL);
6241 Object* result;
6242 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6243 result = Smi::FromInt(EQUAL);
6244 } else {
6245 result = Smi::FromInt(NOT_EQUAL);
6246 }
6247 return result;
6248}
6249
6250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006251RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252 NoHandleAllocation ha;
6253 ASSERT(args.length() == 2);
6254
6255 CONVERT_CHECKED(String, x, args[0]);
6256 CONVERT_CHECKED(String, y, args[1]);
6257
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006258 bool not_equal = !x->Equals(y);
6259 // This is slightly convoluted because the value that signifies
6260 // equality is 0 and inequality is 1 so we have to negate the result
6261 // from String::Equals.
6262 ASSERT(not_equal == 0 || not_equal == 1);
6263 STATIC_CHECK(EQUAL == 0);
6264 STATIC_CHECK(NOT_EQUAL == 1);
6265 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006266}
6267
6268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006269RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270 NoHandleAllocation ha;
6271 ASSERT(args.length() == 3);
6272
6273 CONVERT_DOUBLE_CHECKED(x, args[0]);
6274 CONVERT_DOUBLE_CHECKED(y, args[1]);
6275 if (isnan(x) || isnan(y)) return args[2];
6276 if (x == y) return Smi::FromInt(EQUAL);
6277 if (isless(x, y)) return Smi::FromInt(LESS);
6278 return Smi::FromInt(GREATER);
6279}
6280
6281
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006282// Compare two Smis as if they were converted to strings and then
6283// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006284RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006285 NoHandleAllocation ha;
6286 ASSERT(args.length() == 2);
6287
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006288 // Extract the integer values from the Smis.
6289 CONVERT_CHECKED(Smi, x, args[0]);
6290 CONVERT_CHECKED(Smi, y, args[1]);
6291 int x_value = x->value();
6292 int y_value = y->value();
6293
6294 // If the integers are equal so are the string representations.
6295 if (x_value == y_value) return Smi::FromInt(EQUAL);
6296
6297 // If one of the integers are zero the normal integer order is the
6298 // same as the lexicographic order of the string representations.
6299 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
6300
ager@chromium.org32912102009-01-16 10:38:43 +00006301 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006302 // smallest because the char code of '-' is less than the char code
6303 // of any digit. Otherwise, we make both values positive.
6304 if (x_value < 0 || y_value < 0) {
6305 if (y_value >= 0) return Smi::FromInt(LESS);
6306 if (x_value >= 0) return Smi::FromInt(GREATER);
6307 x_value = -x_value;
6308 y_value = -y_value;
6309 }
6310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 // Arrays for the individual characters of the two Smis. Smis are
6312 // 31 bit integers and 10 decimal digits are therefore enough.
6313 // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
6314 int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
6315 int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
6316
6317
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006318 // Convert the integers to arrays of their decimal digits.
6319 int x_index = 0;
6320 int y_index = 0;
6321 while (x_value > 0) {
6322 x_elms[x_index++] = x_value % 10;
6323 x_value /= 10;
6324 }
6325 while (y_value > 0) {
6326 y_elms[y_index++] = y_value % 10;
6327 y_value /= 10;
6328 }
6329
6330 // Loop through the arrays of decimal digits finding the first place
6331 // where they differ.
6332 while (--x_index >= 0 && --y_index >= 0) {
6333 int diff = x_elms[x_index] - y_elms[y_index];
6334 if (diff != 0) return Smi::FromInt(diff);
6335 }
6336
6337 // If one array is a suffix of the other array, the longest array is
6338 // the representation of the largest of the Smis in the
6339 // lexicographic ordering.
6340 return Smi::FromInt(x_index - y_index);
6341}
6342
6343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344static Object* StringInputBufferCompare(RuntimeState* state,
6345 String* x,
6346 String* y) {
6347 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6348 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006349 bufx.Reset(x);
6350 bufy.Reset(y);
6351 while (bufx.has_more() && bufy.has_more()) {
6352 int d = bufx.GetNext() - bufy.GetNext();
6353 if (d < 0) return Smi::FromInt(LESS);
6354 else if (d > 0) return Smi::FromInt(GREATER);
6355 }
6356
6357 // x is (non-trivial) prefix of y:
6358 if (bufy.has_more()) return Smi::FromInt(LESS);
6359 // y is prefix of x:
6360 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6361}
6362
6363
6364static Object* FlatStringCompare(String* x, String* y) {
6365 ASSERT(x->IsFlat());
6366 ASSERT(y->IsFlat());
6367 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6368 int prefix_length = x->length();
6369 if (y->length() < prefix_length) {
6370 prefix_length = y->length();
6371 equal_prefix_result = Smi::FromInt(GREATER);
6372 } else if (y->length() > prefix_length) {
6373 equal_prefix_result = Smi::FromInt(LESS);
6374 }
6375 int r;
6376 if (x->IsAsciiRepresentation()) {
6377 Vector<const char> x_chars = x->ToAsciiVector();
6378 if (y->IsAsciiRepresentation()) {
6379 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006380 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006381 } else {
6382 Vector<const uc16> y_chars = y->ToUC16Vector();
6383 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6384 }
6385 } else {
6386 Vector<const uc16> x_chars = x->ToUC16Vector();
6387 if (y->IsAsciiRepresentation()) {
6388 Vector<const char> y_chars = y->ToAsciiVector();
6389 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6390 } else {
6391 Vector<const uc16> y_chars = y->ToUC16Vector();
6392 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6393 }
6394 }
6395 Object* result;
6396 if (r == 0) {
6397 result = equal_prefix_result;
6398 } else {
6399 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6400 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006401 ASSERT(result ==
6402 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006403 return result;
6404}
6405
6406
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006407RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006408 NoHandleAllocation ha;
6409 ASSERT(args.length() == 2);
6410
6411 CONVERT_CHECKED(String, x, args[0]);
6412 CONVERT_CHECKED(String, y, args[1]);
6413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006414 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006415
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006416 // A few fast case tests before we flatten.
6417 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006418 if (y->length() == 0) {
6419 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006420 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006421 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006422 return Smi::FromInt(LESS);
6423 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006424
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006425 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006426 if (d < 0) return Smi::FromInt(LESS);
6427 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428
lrn@chromium.org303ada72010-10-27 09:33:13 +00006429 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006430 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006431 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006433 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006434 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6435 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006438 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006439}
6440
6441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006442RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006443 NoHandleAllocation ha;
6444 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446
6447 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006448 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449}
6450
6451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006452RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 NoHandleAllocation ha;
6454 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006455 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006456
6457 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006458 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006459}
6460
6461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006462RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006463 NoHandleAllocation ha;
6464 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006465 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006466
6467 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006468 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006469}
6470
6471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006472static const double kPiDividedBy4 = 0.78539816339744830962;
6473
6474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006475RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476 NoHandleAllocation ha;
6477 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479
6480 CONVERT_DOUBLE_CHECKED(x, args[0]);
6481 CONVERT_DOUBLE_CHECKED(y, args[1]);
6482 double result;
6483 if (isinf(x) && isinf(y)) {
6484 // Make sure that the result in case of two infinite arguments
6485 // is a multiple of Pi / 4. The sign of the result is determined
6486 // by the first argument (x) and the sign of the second argument
6487 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006488 int multiplier = (x < 0) ? -1 : 1;
6489 if (y < 0) multiplier *= 3;
6490 result = multiplier * kPiDividedBy4;
6491 } else {
6492 result = atan2(x, y);
6493 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006494 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006495}
6496
6497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006498RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006499 NoHandleAllocation ha;
6500 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502
6503 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006504 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505}
6506
6507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006508RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006509 NoHandleAllocation ha;
6510 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006511 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512
6513 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006518RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519 NoHandleAllocation ha;
6520 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006521 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006522
6523 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006528RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006529 NoHandleAllocation ha;
6530 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006531 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006532
6533 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006534 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006535}
6536
6537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006538RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539 NoHandleAllocation ha;
6540 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006541 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006542
6543 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006544 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006545}
6546
6547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006548RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006549 NoHandleAllocation ha;
6550 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006552
6553 CONVERT_DOUBLE_CHECKED(x, args[0]);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006554
6555 // If the second argument is a smi, it is much faster to call the
6556 // custom powi() function than the generic pow().
6557 if (args[1]->IsSmi()) {
6558 int y = Smi::cast(args[1])->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006560 }
6561
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006562 CONVERT_DOUBLE_CHECKED(y, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006563 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564}
6565
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006566// Fast version of Math.pow if we know that y is not an integer and
6567// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006568RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006569 NoHandleAllocation ha;
6570 ASSERT(args.length() == 2);
6571 CONVERT_DOUBLE_CHECKED(x, args[0]);
6572 CONVERT_DOUBLE_CHECKED(y, args[1]);
6573 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006574 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006575 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006577 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006579 }
6580}
6581
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006583RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 NoHandleAllocation ha;
6585 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006586 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006588 if (!args[0]->IsHeapNumber()) {
6589 // Must be smi. Return the argument unchanged for all the other types
6590 // to make fuzz-natives test happy.
6591 return args[0];
6592 }
6593
6594 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6595
6596 double value = number->value();
6597 int exponent = number->get_exponent();
6598 int sign = number->get_sign();
6599
danno@chromium.org160a7b02011-04-18 15:51:38 +00006600 if (exponent < -1) {
6601 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6602 if (sign) return isolate->heap()->minus_zero_value();
6603 return Smi::FromInt(0);
6604 }
6605
6606 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6607 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6608 // agument holds for 32-bit smis).
6609 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006610 return Smi::FromInt(static_cast<int>(value + 0.5));
6611 }
6612
6613 // If the magnitude is big enough, there's no place for fraction part. If we
6614 // try to add 0.5 to this number, 1.0 will be added instead.
6615 if (exponent >= 52) {
6616 return number;
6617 }
6618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006619 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006620
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006621 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006622 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623}
6624
6625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006626RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627 NoHandleAllocation ha;
6628 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006629 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630
6631 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633}
6634
6635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006636RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 NoHandleAllocation ha;
6638 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006639 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006640
6641 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006642 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006643}
6644
6645
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006646RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006647 NoHandleAllocation ha;
6648 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006649 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650
6651 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006652 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653}
6654
6655
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006656static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006657 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
6658 181, 212, 243, 273, 304, 334};
6659 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
6660 182, 213, 244, 274, 305, 335};
6661
6662 year += month / 12;
6663 month %= 12;
6664 if (month < 0) {
6665 year--;
6666 month += 12;
6667 }
6668
6669 ASSERT(month >= 0);
6670 ASSERT(month < 12);
6671
6672 // year_delta is an arbitrary number such that:
6673 // a) year_delta = -1 (mod 400)
6674 // b) year + year_delta > 0 for years in the range defined by
6675 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
6676 // Jan 1 1970. This is required so that we don't run into integer
6677 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006678 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006679 // operations.
6680 static const int year_delta = 399999;
6681 static const int base_day = 365 * (1970 + year_delta) +
6682 (1970 + year_delta) / 4 -
6683 (1970 + year_delta) / 100 +
6684 (1970 + year_delta) / 400;
6685
6686 int year1 = year + year_delta;
6687 int day_from_year = 365 * year1 +
6688 year1 / 4 -
6689 year1 / 100 +
6690 year1 / 400 -
6691 base_day;
6692
6693 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006694 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006695 }
6696
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006697 return day_from_year + day_from_month_leap[month] + day - 1;
6698}
6699
6700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006701RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006702 NoHandleAllocation ha;
6703 ASSERT(args.length() == 3);
6704
6705 CONVERT_SMI_CHECKED(year, args[0]);
6706 CONVERT_SMI_CHECKED(month, args[1]);
6707 CONVERT_SMI_CHECKED(date, args[2]);
6708
6709 return Smi::FromInt(MakeDay(year, month, date));
6710}
6711
6712
6713static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
6714static const int kDaysIn4Years = 4 * 365 + 1;
6715static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
6716static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
6717static const int kDays1970to2000 = 30 * 365 + 7;
6718static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
6719 kDays1970to2000;
6720static const int kYearsOffset = 400000;
6721
6722static const char kDayInYear[] = {
6723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6724 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6726 22, 23, 24, 25, 26, 27, 28,
6727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6728 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6730 22, 23, 24, 25, 26, 27, 28, 29, 30,
6731 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6732 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6733 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6734 22, 23, 24, 25, 26, 27, 28, 29, 30,
6735 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6736 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6737 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6738 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6739 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6740 22, 23, 24, 25, 26, 27, 28, 29, 30,
6741 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6742 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6743 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6744 22, 23, 24, 25, 26, 27, 28, 29, 30,
6745 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6746 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6747
6748 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6749 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6750 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6751 22, 23, 24, 25, 26, 27, 28,
6752 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6753 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6754 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6755 22, 23, 24, 25, 26, 27, 28, 29, 30,
6756 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6757 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6758 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6759 22, 23, 24, 25, 26, 27, 28, 29, 30,
6760 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6761 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6762 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6763 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6764 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6765 22, 23, 24, 25, 26, 27, 28, 29, 30,
6766 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6767 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6768 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6769 22, 23, 24, 25, 26, 27, 28, 29, 30,
6770 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6771 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6772
6773 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6774 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6775 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6776 22, 23, 24, 25, 26, 27, 28, 29,
6777 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6778 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6779 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6780 22, 23, 24, 25, 26, 27, 28, 29, 30,
6781 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6782 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6783 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6784 22, 23, 24, 25, 26, 27, 28, 29, 30,
6785 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6786 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6787 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6788 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6789 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6790 22, 23, 24, 25, 26, 27, 28, 29, 30,
6791 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6792 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6793 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6794 22, 23, 24, 25, 26, 27, 28, 29, 30,
6795 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6796 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6797
6798 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6799 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6800 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6801 22, 23, 24, 25, 26, 27, 28,
6802 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6803 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6804 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6805 22, 23, 24, 25, 26, 27, 28, 29, 30,
6806 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6807 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6808 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6809 22, 23, 24, 25, 26, 27, 28, 29, 30,
6810 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6811 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6812 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6813 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6814 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6815 22, 23, 24, 25, 26, 27, 28, 29, 30,
6816 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6817 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
6818 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6819 22, 23, 24, 25, 26, 27, 28, 29, 30,
6820 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
6821 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
6822
6823static const char kMonthInYear[] = {
6824 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,
6825 0, 0, 0, 0, 0, 0,
6826 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,
6827 1, 1, 1,
6828 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,
6829 2, 2, 2, 2, 2, 2,
6830 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,
6831 3, 3, 3, 3, 3,
6832 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,
6833 4, 4, 4, 4, 4, 4,
6834 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,
6835 5, 5, 5, 5, 5,
6836 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,
6837 6, 6, 6, 6, 6, 6,
6838 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,
6839 7, 7, 7, 7, 7, 7,
6840 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,
6841 8, 8, 8, 8, 8,
6842 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,
6843 9, 9, 9, 9, 9, 9,
6844 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6845 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6846 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6847 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6848
6849 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,
6850 0, 0, 0, 0, 0, 0,
6851 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,
6852 1, 1, 1,
6853 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,
6854 2, 2, 2, 2, 2, 2,
6855 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,
6856 3, 3, 3, 3, 3,
6857 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,
6858 4, 4, 4, 4, 4, 4,
6859 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,
6860 5, 5, 5, 5, 5,
6861 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,
6862 6, 6, 6, 6, 6, 6,
6863 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,
6864 7, 7, 7, 7, 7, 7,
6865 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,
6866 8, 8, 8, 8, 8,
6867 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,
6868 9, 9, 9, 9, 9, 9,
6869 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6870 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6871 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6872 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6873
6874 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,
6875 0, 0, 0, 0, 0, 0,
6876 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,
6877 1, 1, 1, 1,
6878 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,
6879 2, 2, 2, 2, 2, 2,
6880 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,
6881 3, 3, 3, 3, 3,
6882 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,
6883 4, 4, 4, 4, 4, 4,
6884 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,
6885 5, 5, 5, 5, 5,
6886 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,
6887 6, 6, 6, 6, 6, 6,
6888 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,
6889 7, 7, 7, 7, 7, 7,
6890 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,
6891 8, 8, 8, 8, 8,
6892 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,
6893 9, 9, 9, 9, 9, 9,
6894 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6895 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6896 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6897 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6898
6899 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,
6900 0, 0, 0, 0, 0, 0,
6901 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,
6902 1, 1, 1,
6903 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,
6904 2, 2, 2, 2, 2, 2,
6905 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,
6906 3, 3, 3, 3, 3,
6907 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,
6908 4, 4, 4, 4, 4, 4,
6909 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,
6910 5, 5, 5, 5, 5,
6911 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,
6912 6, 6, 6, 6, 6, 6,
6913 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,
6914 7, 7, 7, 7, 7, 7,
6915 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,
6916 8, 8, 8, 8, 8,
6917 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,
6918 9, 9, 9, 9, 9, 9,
6919 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6920 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
6921 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
6922 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
6923
6924
6925// This function works for dates from 1970 to 2099.
6926static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006927 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006928#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006929 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006930#endif
6931
6932 year = 1970 + (4 * date + 2) / kDaysIn4Years;
6933 date %= kDaysIn4Years;
6934
6935 month = kMonthInYear[date];
6936 day = kDayInYear[date];
6937
6938 ASSERT(MakeDay(year, month, day) == save_date);
6939}
6940
6941
6942static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006943 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006944#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00006945 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006946#endif
6947
6948 date += kDaysOffset;
6949 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
6950 date %= kDaysIn400Years;
6951
6952 ASSERT(MakeDay(year, 0, 1) + date == save_date);
6953
6954 date--;
6955 int yd1 = date / kDaysIn100Years;
6956 date %= kDaysIn100Years;
6957 year += 100 * yd1;
6958
6959 date++;
6960 int yd2 = date / kDaysIn4Years;
6961 date %= kDaysIn4Years;
6962 year += 4 * yd2;
6963
6964 date--;
6965 int yd3 = date / 365;
6966 date %= 365;
6967 year += yd3;
6968
6969 bool is_leap = (!yd1 || yd2) && !yd3;
6970
6971 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006972 ASSERT(is_leap || (date >= 0));
6973 ASSERT((date < 365) || (is_leap && (date < 366)));
6974 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
6975 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
6976 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006977
6978 if (is_leap) {
6979 day = kDayInYear[2*365 + 1 + date];
6980 month = kMonthInYear[2*365 + 1 + date];
6981 } else {
6982 day = kDayInYear[date];
6983 month = kMonthInYear[date];
6984 }
6985
6986 ASSERT(MakeDay(year, month, day) == save_date);
6987}
6988
6989
6990static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006991 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00006992 if (date >= 0 && date < 32 * kDaysIn4Years) {
6993 DateYMDFromTimeAfter1970(date, year, month, day);
6994 } else {
6995 DateYMDFromTimeSlow(date, year, month, day);
6996 }
6997}
6998
6999
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007000RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007001 NoHandleAllocation ha;
7002 ASSERT(args.length() == 2);
7003
7004 CONVERT_DOUBLE_CHECKED(t, args[0]);
7005 CONVERT_CHECKED(JSArray, res_array, args[1]);
7006
7007 int year, month, day;
7008 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007010 RUNTIME_ASSERT(res_array->elements()->map() ==
7011 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007012 FixedArray* elms = FixedArray::cast(res_array->elements());
7013 RUNTIME_ASSERT(elms->length() == 3);
7014
7015 elms->set(0, Smi::FromInt(year));
7016 elms->set(1, Smi::FromInt(month));
7017 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007018
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007019 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007020}
7021
7022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007023RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007024 NoHandleAllocation ha;
7025 ASSERT(args.length() == 3);
7026
7027 JSFunction* callee = JSFunction::cast(args[0]);
7028 Object** parameters = reinterpret_cast<Object**>(args[1]);
7029 const int length = Smi::cast(args[2])->value();
7030
lrn@chromium.org303ada72010-10-27 09:33:13 +00007031 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007032 { MaybeObject* maybe_result =
7033 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007034 if (!maybe_result->ToObject(&result)) return maybe_result;
7035 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007036 // Allocate the elements if needed.
7037 if (length > 0) {
7038 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007039 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007040 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007041 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7042 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007043
7044 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007045 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007046 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007047 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007048
7049 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007050 for (int i = 0; i < length; i++) {
7051 array->set(i, *--parameters, mode);
7052 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007053 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007054 }
7055 return result;
7056}
7057
7058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007059RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007060 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007061 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007062 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007063 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007064 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007066 // Allocate global closures in old space and allocate local closures
7067 // in new space. Additionally pretenure closures that are assigned
7068 // directly to properties.
7069 pretenure = pretenure || (context->global_context() == *context);
7070 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007072 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7073 context,
7074 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075 return *result;
7076}
7077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007078
7079static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7080 int* total_argc) {
7081 // Find frame containing arguments passed to the caller.
7082 JavaScriptFrameIterator it;
7083 JavaScriptFrame* frame = it.frame();
7084 List<JSFunction*> functions(2);
7085 frame->GetFunctions(&functions);
7086 if (functions.length() > 1) {
7087 int inlined_frame_index = functions.length() - 1;
7088 JSFunction* inlined_function = functions[inlined_frame_index];
7089 int args_count = inlined_function->shared()->formal_parameter_count();
7090 ScopedVector<SlotRef> args_slots(args_count);
7091 SlotRef::ComputeSlotMappingForArguments(frame,
7092 inlined_frame_index,
7093 &args_slots);
7094
7095 *total_argc = bound_argc + args_count;
7096 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7097 for (int i = 0; i < args_count; i++) {
7098 Handle<Object> val = args_slots[i].GetValue();
7099 param_data[bound_argc + i] = val.location();
7100 }
7101 return param_data;
7102 } else {
7103 it.AdvanceToArgumentsFrame();
7104 frame = it.frame();
7105 int args_count = frame->ComputeParametersCount();
7106
7107 *total_argc = bound_argc + args_count;
7108 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7109 for (int i = 0; i < args_count; i++) {
7110 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7111 param_data[bound_argc + i] = val.location();
7112 }
7113 return param_data;
7114 }
7115}
7116
7117
7118RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007119 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007120 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007121 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007122 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007123
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007124 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007125 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007126 int bound_argc = 0;
7127 if (!args[1]->IsNull()) {
7128 CONVERT_ARG_CHECKED(JSArray, params, 1);
7129 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007130 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007131 bound_argc = Smi::cast(params->length())->value();
7132 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007134 int total_argc = 0;
7135 SmartPointer<Object**> param_data =
7136 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007137 for (int i = 0; i < bound_argc; i++) {
7138 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007139 param_data[i] = val.location();
7140 }
7141
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007142 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007143 Handle<Object> result =
7144 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007145 if (exception) {
7146 return Failure::Exception();
7147 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007148
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007149 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007150 return *result;
7151}
7152
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007153
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007154static void TrySettingInlineConstructStub(Isolate* isolate,
7155 Handle<JSFunction> function) {
7156 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007157 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007158 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007159 }
7160 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007161 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007162 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007163 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007164 function->shared()->set_construct_stub(
7165 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007166 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007167 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007168}
7169
7170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007171RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173 ASSERT(args.length() == 1);
7174
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007175 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007176
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007177 // If the constructor isn't a proper function we throw a type error.
7178 if (!constructor->IsJSFunction()) {
7179 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7180 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007181 isolate->factory()->NewTypeError("not_constructor", arguments);
7182 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007183 }
7184
7185 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007186
7187 // If function should not have prototype, construction is not allowed. In this
7188 // case generated code bailouts here, since function has no initial_map.
7189 if (!function->should_have_prototype()) {
7190 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7191 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007192 isolate->factory()->NewTypeError("not_constructor", arguments);
7193 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007194 }
7195
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007196#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007197 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007198 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007199 if (debug->StepInActive()) {
7200 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007201 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007202#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007203
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007204 if (function->has_initial_map()) {
7205 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007206 // The 'Function' function ignores the receiver object when
7207 // called using 'new' and creates a new JSFunction object that
7208 // is returned. The receiver object is only used for error
7209 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007210 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007211 // allocate JSFunctions since it does not properly initialize
7212 // the shared part of the function. Since the receiver is
7213 // ignored anyway, we use the global object as the receiver
7214 // instead of a new JSFunction object. This way, errors are
7215 // reported the same way whether or not 'Function' is called
7216 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007217 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007218 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007219 }
7220
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007221 // The function should be compiled for the optimization hints to be
7222 // available. We cannot use EnsureCompiled because that forces a
7223 // compilation through the shared function info which makes it
7224 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007225 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007226 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007227
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007228 if (!function->has_initial_map() &&
7229 shared->IsInobjectSlackTrackingInProgress()) {
7230 // The tracking is already in progress for another function. We can only
7231 // track one initial_map at a time, so we force the completion before the
7232 // function is called as a constructor for the first time.
7233 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007234 }
7235
7236 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007237 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7238 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007239 // Delay setting the stub if inobject slack tracking is in progress.
7240 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007241 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007242 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007244 isolate->counters()->constructed_objects()->Increment();
7245 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007246
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007247 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007248}
7249
7250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007251RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007252 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007253 ASSERT(args.length() == 1);
7254
7255 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7256 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007257 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007259 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007260}
7261
7262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007263RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007264 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265 ASSERT(args.length() == 1);
7266
7267 Handle<JSFunction> function = args.at<JSFunction>(0);
7268#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007269 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007271 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007272 PrintF("]\n");
7273 }
7274#endif
7275
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007276 // Compile the target function. Here we compile using CompileLazyInLoop in
7277 // order to get the optimized version. This helps code like delta-blue
7278 // that calls performance-critical routines through constructors. A
7279 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7280 // direct call. Since the in-loop tracking takes place through CallICs
7281 // this means that things called through constructors are never known to
7282 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007283 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007284 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285 return Failure::Exception();
7286 }
7287
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007288 // All done. Return the compiled code.
7289 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 return function->code();
7291}
7292
7293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007294RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007295 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007296 ASSERT(args.length() == 1);
7297 Handle<JSFunction> function = args.at<JSFunction>(0);
7298 // If the function is not optimizable or debugger is active continue using the
7299 // code from the full compiler.
7300 if (!function->shared()->code()->optimizable() ||
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007301 isolate->debug()->has_break_points()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007302 if (FLAG_trace_opt) {
7303 PrintF("[failed to optimize ");
7304 function->PrintName();
7305 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7306 function->shared()->code()->optimizable() ? "T" : "F",
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007307 isolate->debug()->has_break_points() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007308 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007309 function->ReplaceCode(function->shared()->code());
7310 return function->code();
7311 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007312 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007313 return function->code();
7314 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007315 if (FLAG_trace_opt) {
7316 PrintF("[failed to optimize ");
7317 function->PrintName();
7318 PrintF(": optimized compilation failed]\n");
7319 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007320 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007321 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007322}
7323
7324
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007325RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007327 ASSERT(args.length() == 1);
7328 RUNTIME_ASSERT(args[0]->IsSmi());
7329 Deoptimizer::BailoutType type =
7330 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007331 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7332 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007333 int frames = deoptimizer->output_count();
7334
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007335 deoptimizer->MaterializeHeapNumbers();
7336 delete deoptimizer;
7337
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007338 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007339 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007340 for (int i = 0; i < frames - 1; i++) it.Advance();
7341 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007342
7343 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007344 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007345 Handle<Object> arguments;
7346 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007347 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007348 if (arguments.is_null()) {
7349 // FunctionGetArguments can't throw an exception, so cast away the
7350 // doubt with an assert.
7351 arguments = Handle<Object>(
7352 Accessors::FunctionGetArguments(*function,
7353 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007354 ASSERT(*arguments != isolate->heap()->null_value());
7355 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007356 }
7357 frame->SetExpression(i, *arguments);
7358 }
7359 }
7360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007361 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007362 if (type == Deoptimizer::EAGER) {
7363 RUNTIME_ASSERT(function->IsOptimized());
7364 } else {
7365 RUNTIME_ASSERT(!function->IsOptimized());
7366 }
7367
7368 // Avoid doing too much work when running with --always-opt and keep
7369 // the optimized code around.
7370 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007372 }
7373
7374 // Count the number of optimized activations of the function.
7375 int activations = 0;
7376 while (!it.done()) {
7377 JavaScriptFrame* frame = it.frame();
7378 if (frame->is_optimized() && frame->function() == *function) {
7379 activations++;
7380 }
7381 it.Advance();
7382 }
7383
7384 // TODO(kasperl): For now, we cannot support removing the optimized
7385 // code when we have recursive invocations of the same function.
7386 if (activations == 0) {
7387 if (FLAG_trace_deopt) {
7388 PrintF("[removing optimized code for: ");
7389 function->PrintName();
7390 PrintF("]\n");
7391 }
7392 function->ReplaceCode(function->shared()->code());
7393 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007395}
7396
7397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007398RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007399 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007400 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007401 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007402}
7403
7404
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007405RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007406 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007407 ASSERT(args.length() == 1);
7408 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007410
7411 Deoptimizer::DeoptimizeFunction(*function);
7412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007413 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007414}
7415
7416
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007417RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7418 HandleScope scope(isolate);
7419 ASSERT(args.length() == 1);
7420 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7421 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7422 function->MarkForLazyRecompilation();
7423 return isolate->heap()->undefined_value();
7424}
7425
7426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007427RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007428 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007429 ASSERT(args.length() == 1);
7430 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7431
7432 // We're not prepared to handle a function with arguments object.
7433 ASSERT(!function->shared()->scope_info()->HasArgumentsShadow());
7434
7435 // We have hit a back edge in an unoptimized frame for a function that was
7436 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007437 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007438 // Keep track of whether we've succeeded in optimizing.
7439 bool succeeded = unoptimized->optimizable();
7440 if (succeeded) {
7441 // If we are trying to do OSR when there are already optimized
7442 // activations of the function, it means (a) the function is directly or
7443 // indirectly recursive and (b) an optimized invocation has been
7444 // deoptimized so that we are currently in an unoptimized activation.
7445 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007446 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007447 while (succeeded && !it.done()) {
7448 JavaScriptFrame* frame = it.frame();
7449 succeeded = !frame->is_optimized() || frame->function() != *function;
7450 it.Advance();
7451 }
7452 }
7453
7454 int ast_id = AstNode::kNoNumber;
7455 if (succeeded) {
7456 // The top JS function is this one, the PC is somewhere in the
7457 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007458 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007459 JavaScriptFrame* frame = it.frame();
7460 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007461 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007462 ASSERT(unoptimized->contains(frame->pc()));
7463
7464 // Use linear search of the unoptimized code's stack check table to find
7465 // the AST id matching the PC.
7466 Address start = unoptimized->instruction_start();
7467 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007468 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007469 uint32_t table_length = Memory::uint32_at(table_cursor);
7470 table_cursor += kIntSize;
7471 for (unsigned i = 0; i < table_length; ++i) {
7472 // Table entries are (AST id, pc offset) pairs.
7473 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7474 if (pc_offset == target_pc_offset) {
7475 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7476 break;
7477 }
7478 table_cursor += 2 * kIntSize;
7479 }
7480 ASSERT(ast_id != AstNode::kNoNumber);
7481 if (FLAG_trace_osr) {
7482 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7483 function->PrintName();
7484 PrintF("]\n");
7485 }
7486
7487 // Try to compile the optimized code. A true return value from
7488 // CompileOptimized means that compilation succeeded, not necessarily
7489 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007490 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7491 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007492 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7493 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007494 if (data->OsrPcOffset()->value() >= 0) {
7495 if (FLAG_trace_osr) {
7496 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007497 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007498 }
7499 ASSERT(data->OsrAstId()->value() == ast_id);
7500 } else {
7501 // We may never generate the desired OSR entry if we emit an
7502 // early deoptimize.
7503 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007504 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007505 } else {
7506 succeeded = false;
7507 }
7508 }
7509
7510 // Revert to the original stack checks in the original unoptimized code.
7511 if (FLAG_trace_osr) {
7512 PrintF("[restoring original stack checks in ");
7513 function->PrintName();
7514 PrintF("]\n");
7515 }
7516 StackCheckStub check_stub;
7517 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007518 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007519 Deoptimizer::RevertStackCheckCode(*unoptimized,
7520 *check_code,
7521 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007522
7523 // Allow OSR only at nesting level zero again.
7524 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7525
7526 // If the optimization attempt succeeded, return the AST id tagged as a
7527 // smi. This tells the builtin that we need to translate the unoptimized
7528 // frame to an optimized one.
7529 if (succeeded) {
7530 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7531 return Smi::FromInt(ast_id);
7532 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007533 if (function->IsMarkedForLazyRecompilation()) {
7534 function->ReplaceCode(function->shared()->code());
7535 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007536 return Smi::FromInt(-1);
7537 }
7538}
7539
7540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007541RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007542 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007543 ASSERT(args.length() == 1);
7544 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7545 return *Execution::GetFunctionDelegate(args.at<Object>(0));
7546}
7547
7548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007549RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007550 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00007551 ASSERT(args.length() == 1);
7552 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7553 return *Execution::GetConstructorDelegate(args.at<Object>(0));
7554}
7555
7556
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007557RUNTIME_FUNCTION(MaybeObject*, Runtime_NewContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007558 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00007559 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007560
kasper.lund7276f142008-07-30 08:49:36 +00007561 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00007562 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007563 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007564 { MaybeObject* maybe_result =
7565 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007566 if (!maybe_result->ToObject(&result)) return maybe_result;
7567 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007568
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007569 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570
kasper.lund7276f142008-07-30 08:49:36 +00007571 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007572}
7573
lrn@chromium.org303ada72010-10-27 09:33:13 +00007574
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007575MUST_USE_RESULT static MaybeObject* PushContextHelper(Isolate* isolate,
7576 Object* object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007577 bool is_catch_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 // Convert the object to a proper JavaScript object.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007579 Object* js_object = object;
7580 if (!js_object->IsJSObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007581 MaybeObject* maybe_js_object = js_object->ToObject();
7582 if (!maybe_js_object->ToObject(&js_object)) {
7583 if (!Failure::cast(maybe_js_object)->IsInternalError()) {
7584 return maybe_js_object;
7585 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007586 HandleScope scope(isolate);
7587 Handle<Object> handle(object, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007588 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007589 isolate->factory()->NewTypeError("with_expression",
7590 HandleVector(&handle, 1));
7591 return isolate->Throw(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007592 }
7593 }
7594
lrn@chromium.org303ada72010-10-27 09:33:13 +00007595 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007596 { MaybeObject* maybe_result = isolate->heap()->AllocateWithContext(
7597 isolate->context(), JSObject::cast(js_object), is_catch_context);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007598 if (!maybe_result->ToObject(&result)) return maybe_result;
7599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007600
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007601 Context* context = Context::cast(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007602 isolate->set_context(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007603
kasper.lund7276f142008-07-30 08:49:36 +00007604 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007605}
7606
7607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007608RUNTIME_FUNCTION(MaybeObject*, Runtime_PushContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007609 NoHandleAllocation ha;
7610 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007611 return PushContextHelper(isolate, args[0], false);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007612}
7613
7614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007615RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007616 NoHandleAllocation ha;
7617 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007618 return PushContextHelper(isolate, args[0], true);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007619}
7620
7621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007622RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007623 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007624 ASSERT(args.length() == 2);
7625
7626 CONVERT_ARG_CHECKED(Context, context, 0);
7627 CONVERT_ARG_CHECKED(String, name, 1);
7628
7629 int index;
7630 PropertyAttributes attributes;
7631 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007632 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007633
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007634 // If the slot was not found the result is true.
7635 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007636 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007637 }
7638
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007639 // If the slot was found in a context, it should be DONT_DELETE.
7640 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007641 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007642 }
7643
7644 // The slot was found in a JSObject, either a context extension object,
7645 // the global object, or an arguments object. Try to delete it
7646 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
7647 // which allows deleting all parameters in functions that mention
7648 // 'arguments', we do this even for the case of slots found on an
7649 // arguments object. The slot was found on an arguments object if the
7650 // index is non-negative.
7651 Handle<JSObject> object = Handle<JSObject>::cast(holder);
7652 if (index >= 0) {
7653 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
7654 } else {
7655 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
7656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007657}
7658
7659
ager@chromium.orga1645e22009-09-09 19:27:10 +00007660// A mechanism to return a pair of Object pointers in registers (if possible).
7661// How this is achieved is calling convention-dependent.
7662// All currently supported x86 compiles uses calling conventions that are cdecl
7663// variants where a 64-bit value is returned in two 32-bit registers
7664// (edx:eax on ia32, r1:r0 on ARM).
7665// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
7666// In Win64 calling convention, a struct of two pointers is returned in memory,
7667// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007668#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007669struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007670 MaybeObject* x;
7671 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007672};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007673
lrn@chromium.org303ada72010-10-27 09:33:13 +00007674static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007675 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00007676 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
7677 // In Win64 they are assigned to a hidden first argument.
7678 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007679}
7680#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007681typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007682static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007683 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007684 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007685}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007686#endif
7687
7688
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007689static inline MaybeObject* Unhole(Heap* heap,
7690 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007691 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007692 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
7693 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007694 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007695}
7696
7697
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007698static JSObject* ComputeReceiverForNonGlobal(Isolate* isolate,
7699 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007700 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007701 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007702 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007703 JSFunction* context_extension_function =
7704 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007705 // If the holder isn't a context extension object, we just return it
7706 // as the receiver. This allows arguments objects to be used as
7707 // receivers, but only if they are put in the context scope chain
7708 // explicitly via a with-statement.
7709 Object* constructor = holder->map()->constructor();
7710 if (constructor != context_extension_function) return holder;
7711 // Fall back to using the global object as the receiver if the
7712 // property turns out to be a local variable allocated in a context
7713 // extension object - introduced via eval.
7714 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007715}
7716
7717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007718static ObjectPair LoadContextSlotHelper(Arguments args,
7719 Isolate* isolate,
7720 bool throw_error) {
7721 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00007722 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007723
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007724 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007725 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007726 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007727 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007728 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007729
7730 int index;
7731 PropertyAttributes attributes;
7732 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007733 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007734
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007735 // If the index is non-negative, the slot has been found in a local
7736 // variable or a parameter. Read it from the context object or the
7737 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007738 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007739 // If the "property" we were looking for is a local variable or an
7740 // argument in a context, the receiver is the global object; see
7741 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007742 JSObject* receiver =
7743 isolate->context()->global()->global_receiver();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007744 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007745 ? Context::cast(*holder)->get(index)
7746 : JSObject::cast(*holder)->GetElement(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007747 return MakePair(Unhole(isolate->heap(), value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 }
7749
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007750 // If the holder is found, we read the property from it.
7751 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007752 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007753 JSObject* object = JSObject::cast(*holder);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007754 JSObject* receiver;
7755 if (object->IsGlobalObject()) {
7756 receiver = GlobalObject::cast(object)->global_receiver();
7757 } else if (context->is_exception_holder(*holder)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007758 receiver = isolate->context()->global()->global_receiver();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007759 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007760 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007761 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007762 // No need to unhole the value here. This is taken care of by the
7763 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007764 MaybeObject* value = object->GetProperty(*name);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007765 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 }
7767
7768 if (throw_error) {
7769 // The property doesn't exist - throw exception.
7770 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007771 isolate->factory()->NewReferenceError("not_defined",
7772 HandleVector(&name, 1));
7773 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007774 } else {
7775 // The property doesn't exist - return undefined
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007776 return MakePair(isolate->heap()->undefined_value(),
7777 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007778 }
7779}
7780
7781
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007782RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007783 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784}
7785
7786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007787RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007788 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007789}
7790
7791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007792RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007793 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007794 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007795
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007796 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007797 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007798 CONVERT_ARG_CHECKED(String, name, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007799 CONVERT_SMI_CHECKED(strict_unchecked, args[3]);
7800 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
7801 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007802 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007803
7804 int index;
7805 PropertyAttributes attributes;
7806 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00007807 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007808
7809 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007810 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007811 // Ignore if read_only variable.
7812 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007813 // Context is a fixed array and set cannot fail.
7814 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007815 } else if (strict_mode == kStrictMode) {
7816 // Setting read only property in strict mode.
7817 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007818 isolate->factory()->NewTypeError("strict_cannot_assign",
7819 HandleVector(&name, 1));
7820 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007821 }
7822 } else {
7823 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007824 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007825 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007826 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007827 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007828 return Failure::Exception();
7829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007830 }
7831 return *value;
7832 }
7833
7834 // Slow case: The property is not in a FixedArray context.
7835 // It is either in an JSObject extension context or it was not found.
7836 Handle<JSObject> context_ext;
7837
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007838 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007839 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007840 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007841 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007842 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007843 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007844
7845 if (strict_mode == kStrictMode) {
7846 // Throw in strict mode (assignment to undefined variable).
7847 Handle<Object> error =
7848 isolate->factory()->NewReferenceError(
7849 "not_defined", HandleVector(&name, 1));
7850 return isolate->Throw(*error);
7851 }
7852 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007853 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007854 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 }
7856
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007857 // Set the property, but ignore if read_only variable on the context
7858 // extension object itself.
7859 if ((attributes & READ_ONLY) == 0 ||
7860 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007861 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007862 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007863 SetProperty(context_ext, name, value, NONE, strict_mode));
7864 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007865 // Setting read only property in strict mode.
7866 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007867 isolate->factory()->NewTypeError(
7868 "strict_cannot_assign", HandleVector(&name, 1));
7869 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007870 }
7871 return *value;
7872}
7873
7874
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007875RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007876 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007877 ASSERT(args.length() == 1);
7878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007879 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007880}
7881
7882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007883RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007885 ASSERT(args.length() == 1);
7886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007888}
7889
7890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007891RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007892 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007893 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007894}
7895
7896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007897RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899 ASSERT(args.length() == 1);
7900
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007901 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007902 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007903 isolate->factory()->NewReferenceError("not_defined",
7904 HandleVector(&name, 1));
7905 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007906}
7907
7908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007909RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00007910 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007911
7912 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007913 if (isolate->stack_guard()->IsStackOverflow()) {
7914 NoHandleAllocation na;
7915 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00007916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007917
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00007918 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919}
7920
7921
7922// NOTE: These PrintXXX functions are defined for all builds (not just
7923// DEBUG builds) because we may want to be able to trace function
7924// calls in all modes.
7925static void PrintString(String* str) {
7926 // not uncommon to have empty strings
7927 if (str->length() > 0) {
7928 SmartPointer<char> s =
7929 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
7930 PrintF("%s", *s);
7931 }
7932}
7933
7934
7935static void PrintObject(Object* obj) {
7936 if (obj->IsSmi()) {
7937 PrintF("%d", Smi::cast(obj)->value());
7938 } else if (obj->IsString() || obj->IsSymbol()) {
7939 PrintString(String::cast(obj));
7940 } else if (obj->IsNumber()) {
7941 PrintF("%g", obj->Number());
7942 } else if (obj->IsFailure()) {
7943 PrintF("<failure>");
7944 } else if (obj->IsUndefined()) {
7945 PrintF("<undefined>");
7946 } else if (obj->IsNull()) {
7947 PrintF("<null>");
7948 } else if (obj->IsTrue()) {
7949 PrintF("<true>");
7950 } else if (obj->IsFalse()) {
7951 PrintF("<false>");
7952 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007953 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007954 }
7955}
7956
7957
7958static int StackSize() {
7959 int n = 0;
7960 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
7961 return n;
7962}
7963
7964
7965static void PrintTransition(Object* result) {
7966 // indentation
7967 { const int nmax = 80;
7968 int n = StackSize();
7969 if (n <= nmax)
7970 PrintF("%4d:%*s", n, n, "");
7971 else
7972 PrintF("%4d:%*s", n, nmax, "...");
7973 }
7974
7975 if (result == NULL) {
7976 // constructor calls
7977 JavaScriptFrameIterator it;
7978 JavaScriptFrame* frame = it.frame();
7979 if (frame->IsConstructor()) PrintF("new ");
7980 // function name
7981 Object* fun = frame->function();
7982 if (fun->IsJSFunction()) {
7983 PrintObject(JSFunction::cast(fun)->shared()->name());
7984 } else {
7985 PrintObject(fun);
7986 }
7987 // function arguments
7988 // (we are intentionally only printing the actually
7989 // supplied parameters, not all parameters required)
7990 PrintF("(this=");
7991 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007992 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007993 for (int i = 0; i < length; i++) {
7994 PrintF(", ");
7995 PrintObject(frame->GetParameter(i));
7996 }
7997 PrintF(") {\n");
7998
7999 } else {
8000 // function result
8001 PrintF("} -> ");
8002 PrintObject(result);
8003 PrintF("\n");
8004 }
8005}
8006
8007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008008RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008009 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008010 NoHandleAllocation ha;
8011 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008013}
8014
8015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008016RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008017 NoHandleAllocation ha;
8018 PrintTransition(args[0]);
8019 return args[0]; // return TOS
8020}
8021
8022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008023RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008024 NoHandleAllocation ha;
8025 ASSERT(args.length() == 1);
8026
8027#ifdef DEBUG
8028 if (args[0]->IsString()) {
8029 // If we have a string, assume it's a code "marker"
8030 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008031 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008032 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008033 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8034 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008035 } else {
8036 PrintF("DebugPrint: ");
8037 }
8038 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008039 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008040 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008041 HeapObject::cast(args[0])->map()->Print();
8042 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008044 // ShortPrint is available in release mode. Print is not.
8045 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008046#endif
8047 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008048 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008049
8050 return args[0]; // return TOS
8051}
8052
8053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008054RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008055 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008057 isolate->PrintStack();
8058 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059}
8060
8061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008062RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008063 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008064 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008065
8066 // According to ECMA-262, section 15.9.1, page 117, the precision of
8067 // the number in a Date object representing a particular instant in
8068 // time is milliseconds. Therefore, we floor the result of getting
8069 // the OS time.
8070 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008071 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072}
8073
8074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008075RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008076 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008077 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008078
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008079 CONVERT_ARG_CHECKED(String, str, 0);
8080 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008081
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008082 CONVERT_ARG_CHECKED(JSArray, output, 1);
8083 RUNTIME_ASSERT(output->HasFastElements());
8084
8085 AssertNoAllocation no_allocation;
8086
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008087 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008088 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8089 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008090 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008091 result = DateParser::Parse(str->ToAsciiVector(),
8092 output_array,
8093 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008095 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008096 result = DateParser::Parse(str->ToUC16Vector(),
8097 output_array,
8098 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008099 }
8100
8101 if (result) {
8102 return *output;
8103 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008104 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008105 }
8106}
8107
8108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008109RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008110 NoHandleAllocation ha;
8111 ASSERT(args.length() == 1);
8112
8113 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008114 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008115 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008116}
8117
8118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008119RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008120 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008121 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008123 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008124}
8125
8126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008127RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008128 NoHandleAllocation ha;
8129 ASSERT(args.length() == 1);
8130
8131 CONVERT_DOUBLE_CHECKED(x, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008132 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008133}
8134
8135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008136RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008137 ASSERT(args.length() == 1);
8138 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008139 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008140 return JSGlobalObject::cast(global)->global_receiver();
8141}
8142
8143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008144RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008145 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008146 ASSERT_EQ(1, args.length());
8147 CONVERT_ARG_CHECKED(String, source, 0);
8148
8149 Handle<Object> result = JsonParser::Parse(source);
8150 if (result.is_null()) {
8151 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008152 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008153 return Failure::Exception();
8154 }
8155 return *result;
8156}
8157
8158
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008159RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008161 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008162 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008163
ager@chromium.org381abbb2009-02-25 13:23:22 +00008164 // Compile source string in the global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008165 Handle<Context> context(isolate->context()->global_context());
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008166 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8167 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008168 true,
8169 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008170 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008171 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8173 context,
8174 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008175 return *fun;
8176}
8177
8178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008179static ObjectPair CompileGlobalEval(Isolate* isolate,
8180 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008181 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008182 StrictModeFlag strict_mode) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008183 // Deal with a normal eval call with a string argument. Compile it
8184 // and return the compiled function bound in the local context.
8185 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8186 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008187 Handle<Context>(isolate->context()),
8188 isolate->context()->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008189 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008190 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008191 Handle<JSFunction> compiled =
8192 isolate->factory()->NewFunctionFromSharedFunctionInfo(
8193 shared, Handle<Context>(isolate->context()), NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008194 return MakePair(*compiled, *receiver);
8195}
8196
8197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008198RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008199 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008200
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008201 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008202 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008203 Handle<Object> receiver; // Will be overwritten.
8204
8205 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008206 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008207#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008208 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008209 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008210 StackFrameLocator locator;
8211 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008212 ASSERT(Context::cast(frame->context()) == *context);
8213#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008214
8215 // Find where the 'eval' symbol is bound. It is unaliased only if
8216 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008217 int index = -1;
8218 PropertyAttributes attributes = ABSENT;
8219 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008220 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8221 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008222 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008223 // Stop search when eval is found or when the global context is
8224 // reached.
8225 if (attributes != ABSENT || context->IsGlobalContext()) break;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008226 if (context->is_function_context()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008227 context = Handle<Context>(Context::cast(context->closure()->context()),
8228 isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008229 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008230 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008231 }
8232 }
8233
iposva@chromium.org245aa852009-02-10 00:49:54 +00008234 // If eval could not be resolved, it has been deleted and we need to
8235 // throw a reference error.
8236 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008237 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008238 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008239 isolate->factory()->NewReferenceError("not_defined",
8240 HandleVector(&name, 1));
8241 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008242 }
8243
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008244 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008245 // 'eval' is not bound in the global context. Just call the function
8246 // with the given arguments. This is not necessarily the global eval.
8247 if (receiver->IsContext()) {
8248 context = Handle<Context>::cast(receiver);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 receiver = Handle<Object>(context->get(index), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008250 } else if (receiver->IsJSContextExtensionObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 receiver = Handle<JSObject>(
8252 isolate->context()->global()->global_receiver(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008253 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008254 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008255 }
8256
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008257 // 'eval' is bound in the global context, but it may have been overwritten.
8258 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008259 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008260 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008261 return MakePair(*callee,
8262 isolate->context()->global()->global_receiver());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008263 }
8264
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008265 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008266 return CompileGlobalEval(isolate,
8267 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008268 args.at<Object>(2),
8269 static_cast<StrictModeFlag>(
8270 Smi::cast(args[3])->value()));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008271}
8272
8273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008274RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008275 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008277 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008278 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008279
8280 // 'eval' is bound in the global context, but it may have been overwritten.
8281 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008283 !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 return MakePair(*callee,
8285 isolate->context()->global()->global_receiver());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008286 }
8287
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008288 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 return CompileGlobalEval(isolate,
8290 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008291 args.at<Object>(2),
8292 static_cast<StrictModeFlag>(
8293 Smi::cast(args[3])->value()));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008294}
8295
8296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008297RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298 // This utility adjusts the property attributes for newly created Function
8299 // object ("new Function(...)") by changing the map.
8300 // All it does is changing the prototype property to enumerable
8301 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303 ASSERT(args.length() == 1);
8304 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008305
8306 Handle<Map> map = func->shared()->strict_mode()
8307 ? isolate->strict_mode_function_instance_map()
8308 : isolate->function_instance_map();
8309
8310 ASSERT(func->map()->instance_type() == map->instance_type());
8311 ASSERT(func->map()->instance_size() == map->instance_size());
8312 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313 return *func;
8314}
8315
8316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008317RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008318 // Allocate a block of memory in NewSpace (filled with a filler).
8319 // Use as fallback for allocation in generated code when NewSpace
8320 // is full.
8321 ASSERT(args.length() == 1);
8322 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8323 int size = size_smi->value();
8324 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8325 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008326 Heap* heap = isolate->heap();
8327 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008328 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008329 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008330 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008331 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008332 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008333 }
8334 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008335 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008336}
8337
8338
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008339// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008340// array. Returns true if the element was pushed on the stack and
8341// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008342RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008343 ASSERT(args.length() == 2);
8344 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008345 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008346 RUNTIME_ASSERT(array->HasFastElements());
8347 int length = Smi::cast(array->length())->value();
8348 FixedArray* elements = FixedArray::cast(array->elements());
8349 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008350 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008351 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008352 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008353 // Strict not needed. Used for cycle detection in Array join implementation.
8354 { MaybeObject* maybe_obj = array->SetFastElement(length, element,
8355 kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008356 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8357 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008358 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008359}
8360
8361
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008362/**
8363 * A simple visitor visits every element of Array's.
8364 * The backend storage can be a fixed array for fast elements case,
8365 * or a dictionary for sparse array. Since Dictionary is a subtype
8366 * of FixedArray, the class can be used by both fast and slow cases.
8367 * The second parameter of the constructor, fast_elements, specifies
8368 * whether the storage is a FixedArray or Dictionary.
8369 *
8370 * An index limit is used to deal with the situation that a result array
8371 * length overflows 32-bit non-negative integer.
8372 */
8373class ArrayConcatVisitor {
8374 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008375 ArrayConcatVisitor(Isolate* isolate,
8376 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008377 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008378 isolate_(isolate),
8379 storage_(Handle<FixedArray>::cast(
8380 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008381 index_offset_(0u),
8382 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008383
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008384 ~ArrayConcatVisitor() {
8385 clear_storage();
8386 }
8387
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008388 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008389 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008390 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008391
8392 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008393 if (index < static_cast<uint32_t>(storage_->length())) {
8394 storage_->set(index, *elm);
8395 return;
8396 }
8397 // Our initial estimate of length was foiled, possibly by
8398 // getters on the arrays increasing the length of later arrays
8399 // during iteration.
8400 // This shouldn't happen in anything but pathological cases.
8401 SetDictionaryMode(index);
8402 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008403 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008404 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008405 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008406 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008407 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008408 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008409 // Dictionary needed to grow.
8410 clear_storage();
8411 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008412 }
8413}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008414
8415 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008416 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8417 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008418 } else {
8419 index_offset_ += delta;
8420 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008421 }
8422
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008423 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008424 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008425 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008426 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008427 Handle<Map> map;
8428 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008429 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008430 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008431 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008432 }
8433 array->set_map(*map);
8434 array->set_length(*length);
8435 array->set_elements(*storage_);
8436 return array;
8437 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008438
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008439 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008440 // Convert storage to dictionary mode.
8441 void SetDictionaryMode(uint32_t index) {
8442 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008443 Handle<FixedArray> current_storage(*storage_);
8444 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008445 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008446 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8447 for (uint32_t i = 0; i < current_length; i++) {
8448 HandleScope loop_scope;
8449 Handle<Object> element(current_storage->get(i));
8450 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008451 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008452 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008453 if (!new_storage.is_identical_to(slow_storage)) {
8454 slow_storage = loop_scope.CloseAndEscape(new_storage);
8455 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008456 }
8457 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008458 clear_storage();
8459 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008460 fast_elements_ = false;
8461 }
8462
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008463 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008464 isolate_->global_handles()->Destroy(
8465 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008466 }
8467
8468 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008469 storage_ = Handle<FixedArray>::cast(
8470 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008471 }
8472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008473 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008474 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008475 // Index after last seen index. Always less than or equal to
8476 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008477 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008478 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008479};
8480
8481
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008482static uint32_t EstimateElementCount(Handle<JSArray> array) {
8483 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8484 int element_count = 0;
8485 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008486 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008487 // Fast elements can't have lengths that are not representable by
8488 // a 32-bit signed integer.
8489 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8490 int fast_length = static_cast<int>(length);
8491 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8492 for (int i = 0; i < fast_length; i++) {
8493 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008494 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008495 break;
8496 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008497 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008498 Handle<NumberDictionary> dictionary(
8499 NumberDictionary::cast(array->elements()));
8500 int capacity = dictionary->Capacity();
8501 for (int i = 0; i < capacity; i++) {
8502 Handle<Object> key(dictionary->KeyAt(i));
8503 if (dictionary->IsKey(*key)) {
8504 element_count++;
8505 }
8506 }
8507 break;
8508 }
8509 default:
8510 // External arrays are always dense.
8511 return length;
8512 }
8513 // As an estimate, we assume that the prototype doesn't contain any
8514 // inherited elements.
8515 return element_count;
8516}
8517
8518
8519
8520template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008521static void IterateExternalArrayElements(Isolate* isolate,
8522 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008523 bool elements_are_ints,
8524 bool elements_are_guaranteed_smis,
8525 ArrayConcatVisitor* visitor) {
8526 Handle<ExternalArrayClass> array(
8527 ExternalArrayClass::cast(receiver->elements()));
8528 uint32_t len = static_cast<uint32_t>(array->length());
8529
8530 ASSERT(visitor != NULL);
8531 if (elements_are_ints) {
8532 if (elements_are_guaranteed_smis) {
8533 for (uint32_t j = 0; j < len; j++) {
8534 HandleScope loop_scope;
8535 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8536 visitor->visit(j, e);
8537 }
8538 } else {
8539 for (uint32_t j = 0; j < len; j++) {
8540 HandleScope loop_scope;
8541 int64_t val = static_cast<int64_t>(array->get(j));
8542 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8543 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8544 visitor->visit(j, e);
8545 } else {
8546 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008547 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008548 visitor->visit(j, e);
8549 }
8550 }
8551 }
8552 } else {
8553 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008554 HandleScope loop_scope(isolate);
8555 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008556 visitor->visit(j, e);
8557 }
8558 }
8559}
8560
8561
8562// Used for sorting indices in a List<uint32_t>.
8563static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8564 uint32_t a = *ap;
8565 uint32_t b = *bp;
8566 return (a == b) ? 0 : (a < b) ? -1 : 1;
8567}
8568
8569
8570static void CollectElementIndices(Handle<JSObject> object,
8571 uint32_t range,
8572 List<uint32_t>* indices) {
8573 JSObject::ElementsKind kind = object->GetElementsKind();
8574 switch (kind) {
8575 case JSObject::FAST_ELEMENTS: {
8576 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8577 uint32_t length = static_cast<uint32_t>(elements->length());
8578 if (range < length) length = range;
8579 for (uint32_t i = 0; i < length; i++) {
8580 if (!elements->get(i)->IsTheHole()) {
8581 indices->Add(i);
8582 }
8583 }
8584 break;
8585 }
8586 case JSObject::DICTIONARY_ELEMENTS: {
8587 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008588 uint32_t capacity = dict->Capacity();
8589 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008590 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008591 Handle<Object> k(dict->KeyAt(j));
8592 if (dict->IsKey(*k)) {
8593 ASSERT(k->IsNumber());
8594 uint32_t index = static_cast<uint32_t>(k->Number());
8595 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008596 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008597 }
8598 }
8599 }
8600 break;
8601 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008602 default: {
8603 int dense_elements_length;
8604 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008605 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008606 dense_elements_length =
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008607 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008608 break;
8609 }
8610 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8611 dense_elements_length =
8612 ExternalByteArray::cast(object->elements())->length();
8613 break;
8614 }
8615 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8616 dense_elements_length =
8617 ExternalUnsignedByteArray::cast(object->elements())->length();
8618 break;
8619 }
8620 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8621 dense_elements_length =
8622 ExternalShortArray::cast(object->elements())->length();
8623 break;
8624 }
8625 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8626 dense_elements_length =
8627 ExternalUnsignedShortArray::cast(object->elements())->length();
8628 break;
8629 }
8630 case JSObject::EXTERNAL_INT_ELEMENTS: {
8631 dense_elements_length =
8632 ExternalIntArray::cast(object->elements())->length();
8633 break;
8634 }
8635 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8636 dense_elements_length =
8637 ExternalUnsignedIntArray::cast(object->elements())->length();
8638 break;
8639 }
8640 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8641 dense_elements_length =
8642 ExternalFloatArray::cast(object->elements())->length();
8643 break;
8644 }
8645 default:
8646 UNREACHABLE();
8647 dense_elements_length = 0;
8648 break;
8649 }
8650 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8651 if (range <= length) {
8652 length = range;
8653 // We will add all indices, so we might as well clear it first
8654 // and avoid duplicates.
8655 indices->Clear();
8656 }
8657 for (uint32_t i = 0; i < length; i++) {
8658 indices->Add(i);
8659 }
8660 if (length == range) return; // All indices accounted for already.
8661 break;
8662 }
8663 }
8664
8665 Handle<Object> prototype(object->GetPrototype());
8666 if (prototype->IsJSObject()) {
8667 // The prototype will usually have no inherited element indices,
8668 // but we have to check.
8669 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8670 }
8671}
8672
8673
8674/**
8675 * A helper function that visits elements of a JSArray in numerical
8676 * order.
8677 *
8678 * The visitor argument called for each existing element in the array
8679 * with the element index and the element's value.
8680 * Afterwards it increments the base-index of the visitor by the array
8681 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008682 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008683 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008684static bool IterateElements(Isolate* isolate,
8685 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008686 ArrayConcatVisitor* visitor) {
8687 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8688 switch (receiver->GetElementsKind()) {
8689 case JSObject::FAST_ELEMENTS: {
8690 // Run through the elements FixedArray and use HasElement and GetElement
8691 // to check the prototype for missing elements.
8692 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8693 int fast_length = static_cast<int>(length);
8694 ASSERT(fast_length <= elements->length());
8695 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 HandleScope loop_scope(isolate);
8697 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008698 if (!element_value->IsTheHole()) {
8699 visitor->visit(j, element_value);
8700 } else if (receiver->HasElement(j)) {
8701 // Call GetElement on receiver, not its prototype, or getters won't
8702 // have the correct receiver.
8703 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008704 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008705 visitor->visit(j, element_value);
8706 }
8707 }
8708 break;
8709 }
8710 case JSObject::DICTIONARY_ELEMENTS: {
8711 Handle<NumberDictionary> dict(receiver->element_dictionary());
8712 List<uint32_t> indices(dict->Capacity() / 2);
8713 // Collect all indices in the object and the prototypes less
8714 // than length. This might introduce duplicates in the indices list.
8715 CollectElementIndices(receiver, length, &indices);
8716 indices.Sort(&compareUInt32);
8717 int j = 0;
8718 int n = indices.length();
8719 while (j < n) {
8720 HandleScope loop_scope;
8721 uint32_t index = indices[j];
8722 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008723 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008724 visitor->visit(index, element);
8725 // Skip to next different index (i.e., omit duplicates).
8726 do {
8727 j++;
8728 } while (j < n && indices[j] == index);
8729 }
8730 break;
8731 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008732 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
8733 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
8734 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008735 for (uint32_t j = 0; j < length; j++) {
8736 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8737 visitor->visit(j, e);
8738 }
8739 break;
8740 }
8741 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8742 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008743 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008744 break;
8745 }
8746 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8747 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008748 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008749 break;
8750 }
8751 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8752 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008753 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008754 break;
8755 }
8756 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8757 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008758 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008759 break;
8760 }
8761 case JSObject::EXTERNAL_INT_ELEMENTS: {
8762 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008763 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008764 break;
8765 }
8766 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8767 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008768 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008769 break;
8770 }
8771 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8772 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008773 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008774 break;
8775 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008776 default:
8777 UNREACHABLE();
8778 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008779 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008780 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008781 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008782}
8783
8784
8785/**
8786 * Array::concat implementation.
8787 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008788 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008789 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008790 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008791RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008792 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008793 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008794
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008795 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8796 int argument_count = static_cast<int>(arguments->length()->Number());
8797 RUNTIME_ASSERT(arguments->HasFastElements());
8798 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008799
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008800 // Pass 1: estimate the length and number of elements of the result.
8801 // The actual length can be larger if any of the arguments have getters
8802 // that mutate other arguments (but will otherwise be precise).
8803 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008804
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008805 uint32_t estimate_result_length = 0;
8806 uint32_t estimate_nof_elements = 0;
8807 {
8808 for (int i = 0; i < argument_count; i++) {
8809 HandleScope loop_scope;
8810 Handle<Object> obj(elements->get(i));
8811 uint32_t length_estimate;
8812 uint32_t element_estimate;
8813 if (obj->IsJSArray()) {
8814 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8815 length_estimate =
8816 static_cast<uint32_t>(array->length()->Number());
8817 element_estimate =
8818 EstimateElementCount(array);
8819 } else {
8820 length_estimate = 1;
8821 element_estimate = 1;
8822 }
8823 // Avoid overflows by capping at kMaxElementCount.
8824 if (JSObject::kMaxElementCount - estimate_result_length <
8825 length_estimate) {
8826 estimate_result_length = JSObject::kMaxElementCount;
8827 } else {
8828 estimate_result_length += length_estimate;
8829 }
8830 if (JSObject::kMaxElementCount - estimate_nof_elements <
8831 element_estimate) {
8832 estimate_nof_elements = JSObject::kMaxElementCount;
8833 } else {
8834 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008835 }
8836 }
8837 }
8838
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008839 // If estimated number of elements is more than half of length, a
8840 // fixed array (fast case) is more time and space-efficient than a
8841 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008842 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008843
8844 Handle<FixedArray> storage;
8845 if (fast_case) {
8846 // The backing storage array must have non-existing elements to
8847 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008848 storage = isolate->factory()->NewFixedArrayWithHoles(
8849 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008850 } else {
8851 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8852 uint32_t at_least_space_for = estimate_nof_elements +
8853 (estimate_nof_elements >> 2);
8854 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008855 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008856 }
8857
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008858 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008859
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008860 for (int i = 0; i < argument_count; i++) {
8861 Handle<Object> obj(elements->get(i));
8862 if (obj->IsJSArray()) {
8863 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008864 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008865 return Failure::Exception();
8866 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008867 } else {
8868 visitor.visit(0, obj);
8869 visitor.increase_index_offset(1);
8870 }
8871 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008872
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008873 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008874}
8875
8876
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008877// This will not allocate (flatten the string), but it may run
8878// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008879RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 NoHandleAllocation ha;
8881 ASSERT(args.length() == 1);
8882
8883 CONVERT_CHECKED(String, string, args[0]);
8884 StringInputBuffer buffer(string);
8885 while (buffer.has_more()) {
8886 uint16_t character = buffer.GetNext();
8887 PrintF("%c", character);
8888 }
8889 return string;
8890}
8891
ager@chromium.org5ec48922009-05-05 07:25:34 +00008892// Moves all own elements of an object, that are below a limit, to positions
8893// starting at zero. All undefined values are placed after non-undefined values,
8894// and are followed by non-existing element. Does not change the length
8895// property.
8896// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008897RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008898 ASSERT(args.length() == 2);
8899 CONVERT_CHECKED(JSObject, object, args[0]);
8900 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
8901 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008902}
8903
8904
8905// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008906RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008907 ASSERT(args.length() == 2);
8908 CONVERT_CHECKED(JSArray, from, args[0]);
8909 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008910 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008911 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
8913 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008914 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008915 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008916 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008917 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008918 Object* new_map;
8919 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008920 to->set_map(Map::cast(new_map));
8921 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00008923 Object* obj;
8924 { MaybeObject* maybe_obj = from->ResetElements();
8925 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8926 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008927 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008928 return to;
8929}
8930
8931
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008932// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008933RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008935 CONVERT_CHECKED(JSObject, object, args[0]);
8936 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008937 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008938 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008939 } else if (object->IsJSArray()) {
8940 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008941 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008942 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008943 }
8944}
8945
8946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008947RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008948 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008949
8950 ASSERT_EQ(3, args.length());
8951
ager@chromium.orgac091b72010-05-05 07:34:42 +00008952 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008953 Handle<Object> key1 = args.at<Object>(1);
8954 Handle<Object> key2 = args.at<Object>(2);
8955
8956 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008957 if (!key1->ToArrayIndex(&index1)
8958 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008959 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008960 }
8961
ager@chromium.orgac091b72010-05-05 07:34:42 +00008962 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
8963 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008964 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008965 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008966 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00008967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008968 RETURN_IF_EMPTY_HANDLE(isolate,
8969 SetElement(jsobject, index1, tmp2, kStrictMode));
8970 RETURN_IF_EMPTY_HANDLE(isolate,
8971 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00008972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008973 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008974}
8975
8976
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008977// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00008978// might have elements. Can either return keys (positive integers) or
8979// intervals (pair of a negative integer (-start-1) followed by a
8980// positive (length)) or undefined values.
8981// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008982RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00008985 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008986 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008987 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988 // Create an array and get all the keys into it, then remove all the
8989 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008990 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991 int keys_length = keys->length();
8992 for (int i = 0; i < keys_length; i++) {
8993 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008994 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008995 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008996 // Zap invalid keys.
8997 keys->set_undefined(i);
8998 }
8999 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009000 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009002 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009003 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009005 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009006 uint32_t actual_length =
9007 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009008 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009010 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009012 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013 }
9014}
9015
9016
9017// DefineAccessor takes an optional final argument which is the
9018// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9019// to the way accessors are implemented, it is set for both the getter
9020// and setter on the first call to DefineAccessor and ignored on
9021// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009022RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9024 // Compute attributes.
9025 PropertyAttributes attributes = NONE;
9026 if (args.length() == 5) {
9027 CONVERT_CHECKED(Smi, attrs, args[4]);
9028 int value = attrs->value();
9029 // Only attribute bits should be set.
9030 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9031 attributes = static_cast<PropertyAttributes>(value);
9032 }
9033
9034 CONVERT_CHECKED(JSObject, obj, args[0]);
9035 CONVERT_CHECKED(String, name, args[1]);
9036 CONVERT_CHECKED(Smi, flag, args[2]);
9037 CONVERT_CHECKED(JSFunction, fun, args[3]);
9038 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9039}
9040
9041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009042RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009043 ASSERT(args.length() == 3);
9044 CONVERT_CHECKED(JSObject, obj, args[0]);
9045 CONVERT_CHECKED(String, name, args[1]);
9046 CONVERT_CHECKED(Smi, flag, args[2]);
9047 return obj->LookupAccessor(name, flag->value() == 0);
9048}
9049
9050
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009051#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009052RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009053 ASSERT(args.length() == 0);
9054 return Execution::DebugBreakHelper();
9055}
9056
9057
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058// Helper functions for wrapping and unwrapping stack frame ids.
9059static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009060 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061 return Smi::FromInt(id >> 2);
9062}
9063
9064
9065static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9066 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9067}
9068
9069
9070// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009071// args[0]: debug event listener function to set or null or undefined for
9072// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009073// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009074RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009075 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009076 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9077 args[0]->IsUndefined() ||
9078 args[0]->IsNull());
9079 Handle<Object> callback = args.at<Object>(0);
9080 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009081 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009083 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084}
9085
9086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009087RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009088 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009089 isolate->stack_guard()->DebugBreak();
9090 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009091}
9092
9093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009094static MaybeObject* DebugLookupResultValue(Heap* heap,
9095 Object* receiver,
9096 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009097 LookupResult* result,
9098 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009099 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009100 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009101 case NORMAL:
9102 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009103 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105 }
9106 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009107 case FIELD:
9108 value =
9109 JSObject::cast(
9110 result->holder())->FastPropertyAt(result->GetFieldIndex());
9111 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009112 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009113 }
9114 return value;
9115 case CONSTANT_FUNCTION:
9116 return result->GetConstantFunction();
9117 case CALLBACKS: {
9118 Object* structure = result->GetCallbackObject();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009119 if (structure->IsProxy() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009120 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009121 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009122 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009123 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009124 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009125 maybe_value = heap->isolate()->pending_exception();
9126 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009127 if (caught_exception != NULL) {
9128 *caught_exception = true;
9129 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009130 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009131 }
9132 return value;
9133 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009134 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009135 }
9136 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009138 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009139 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009140 case CONSTANT_TRANSITION:
9141 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143 default:
9144 UNREACHABLE();
9145 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009146 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009147 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148}
9149
9150
ager@chromium.org32912102009-01-16 10:38:43 +00009151// Get debugger related details for an object property.
9152// args[0]: object holding property
9153// args[1]: name of the property
9154//
9155// The array returned contains the following information:
9156// 0: Property value
9157// 1: Property details
9158// 2: Property value is exception
9159// 3: Getter function if defined
9160// 4: Setter function if defined
9161// Items 2-4 are only filled if the property has either a getter or a setter
9162// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009163RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009164 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165
9166 ASSERT(args.length() == 2);
9167
9168 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9169 CONVERT_ARG_CHECKED(String, name, 1);
9170
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009171 // Make sure to set the current context to the context before the debugger was
9172 // entered (if the debugger is entered). The reason for switching context here
9173 // is that for some property lookups (accessors and interceptors) callbacks
9174 // into the embedding application can occour, and the embedding application
9175 // could have the assumption that its own global context is the current
9176 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009177 SaveContext save(isolate);
9178 if (isolate->debug()->InDebugger()) {
9179 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009180 }
9181
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009182 // Skip the global proxy as it has no properties and always delegates to the
9183 // real global object.
9184 if (obj->IsJSGlobalProxy()) {
9185 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9186 }
9187
9188
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189 // Check if the name is trivially convertible to an index and get the element
9190 // if so.
9191 uint32_t index;
9192 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009193 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009194 Object* element_or_char;
9195 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009197 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9198 return maybe_element_or_char;
9199 }
9200 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009201 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009203 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204 }
9205
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009206 // Find the number of objects making up this.
9207 int length = LocalPrototypeChainLength(*obj);
9208
9209 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009210 Handle<JSObject> jsproto = obj;
9211 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009212 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009213 jsproto->LocalLookup(*name, &result);
9214 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009215 // LookupResult is not GC safe as it holds raw object pointers.
9216 // GC can happen later in this code so put the required fields into
9217 // local variables using handles when required for later use.
9218 PropertyType result_type = result.type();
9219 Handle<Object> result_callback_obj;
9220 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009221 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9222 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009223 }
9224 Smi* property_details = result.GetPropertyDetails().AsSmi();
9225 // DebugLookupResultValue can cause GC so details from LookupResult needs
9226 // to be copied to handles before this.
9227 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009228 Object* raw_value;
9229 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230 DebugLookupResultValue(isolate->heap(), *obj, *name,
9231 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009232 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9233 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009235
9236 // If the callback object is a fixed array then it contains JavaScript
9237 // getter and/or setter.
9238 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9239 result_callback_obj->IsFixedArray();
9240 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009241 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009242 details->set(0, *value);
9243 details->set(1, property_details);
9244 if (hasJavaScriptAccessors) {
9245 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 caught_exception ? isolate->heap()->true_value()
9247 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009248 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9249 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9250 }
9251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009253 }
9254 if (i < length - 1) {
9255 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9256 }
9257 }
9258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009259 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009260}
9261
9262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009263RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009264 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265
9266 ASSERT(args.length() == 2);
9267
9268 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9269 CONVERT_ARG_CHECKED(String, name, 1);
9270
9271 LookupResult result;
9272 obj->Lookup(*name, &result);
9273 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009274 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009276 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009277}
9278
9279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009280// Return the property type calculated from the property details.
9281// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009282RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009283 ASSERT(args.length() == 1);
9284 CONVERT_CHECKED(Smi, details, args[0]);
9285 PropertyType type = PropertyDetails(details).type();
9286 return Smi::FromInt(static_cast<int>(type));
9287}
9288
9289
9290// Return the property attribute calculated from the property details.
9291// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009292RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293 ASSERT(args.length() == 1);
9294 CONVERT_CHECKED(Smi, details, args[0]);
9295 PropertyAttributes attributes = PropertyDetails(details).attributes();
9296 return Smi::FromInt(static_cast<int>(attributes));
9297}
9298
9299
9300// Return the property insertion index calculated from the property details.
9301// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009302RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009303 ASSERT(args.length() == 1);
9304 CONVERT_CHECKED(Smi, details, args[0]);
9305 int index = PropertyDetails(details).index();
9306 return Smi::FromInt(index);
9307}
9308
9309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009310// Return property value from named interceptor.
9311// args[0]: object
9312// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009313RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009314 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315 ASSERT(args.length() == 2);
9316 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9317 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9318 CONVERT_ARG_CHECKED(String, name, 1);
9319
9320 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009321 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322}
9323
9324
9325// Return element value from indexed interceptor.
9326// args[0]: object
9327// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009328RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009329 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330 ASSERT(args.length() == 2);
9331 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9332 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9333 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9334
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009335 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009336}
9337
9338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009339RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340 ASSERT(args.length() >= 1);
9341 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009342 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009343 if (isolate->debug()->break_id() == 0 ||
9344 break_id != isolate->debug()->break_id()) {
9345 return isolate->Throw(
9346 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009347 }
9348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009349 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009350}
9351
9352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009353RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009354 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355 ASSERT(args.length() == 1);
9356
9357 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009358 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009359 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9360 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009361 if (!maybe_result->ToObject(&result)) return maybe_result;
9362 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009363
9364 // Count all frames which are relevant to debugging stack trace.
9365 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009367 if (id == StackFrame::NO_ID) {
9368 // If there is no JavaScript stack frame count is 0.
9369 return Smi::FromInt(0);
9370 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009371 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009372 return Smi::FromInt(n);
9373}
9374
9375
9376static const int kFrameDetailsFrameIdIndex = 0;
9377static const int kFrameDetailsReceiverIndex = 1;
9378static const int kFrameDetailsFunctionIndex = 2;
9379static const int kFrameDetailsArgumentCountIndex = 3;
9380static const int kFrameDetailsLocalCountIndex = 4;
9381static const int kFrameDetailsSourcePositionIndex = 5;
9382static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009383static const int kFrameDetailsAtReturnIndex = 7;
9384static const int kFrameDetailsDebuggerFrameIndex = 8;
9385static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009386
9387// Return an array with frame details
9388// args[0]: number: break id
9389// args[1]: number: frame index
9390//
9391// The array returned contains the following information:
9392// 0: Frame id
9393// 1: Receiver
9394// 2: Function
9395// 3: Argument count
9396// 4: Local count
9397// 5: Source position
9398// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009399// 7: Is at return
9400// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401// Arguments name, value
9402// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009403// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009404RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009405 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406 ASSERT(args.length() == 2);
9407
9408 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009409 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009410 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9411 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009412 if (!maybe_check->ToObject(&check)) return maybe_check;
9413 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009414 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009415 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416
9417 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009418 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009419 if (id == StackFrame::NO_ID) {
9420 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009421 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009422 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009423 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009424 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009425 for (; !it.done(); it.Advance()) {
9426 if (count == index) break;
9427 count++;
9428 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009429 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009430
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009431 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009432 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434 // Traverse the saved contexts chain to find the active context for the
9435 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009436 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009437 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009438 save = save->prev();
9439 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009440 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009441
9442 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009443 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009444
9445 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009446 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009447 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009448
9449 // Check for constructor frame.
9450 bool constructor = it.frame()->IsConstructor();
9451
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009452 // Get scope info and read from it for local variable information.
9453 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +00009454 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009455 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009456
9457 // Get the context.
9458 Handle<Context> context(Context::cast(it.frame()->context()));
9459
9460 // Get the locals names and values into a temporary array.
9461 //
9462 // TODO(1240907): Hide compiler-introduced stack variables
9463 // (e.g. .result)? For users of the debugger, they will probably be
9464 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009465 Handle<FixedArray> locals =
9466 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009467
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009468 // Fill in the names of the locals.
9469 for (int i = 0; i < info.NumberOfLocals(); i++) {
9470 locals->set(i * 2, *info.LocalName(i));
9471 }
9472
9473 // Fill in the values of the locals.
9474 for (int i = 0; i < info.NumberOfLocals(); i++) {
9475 if (is_optimized_frame) {
9476 // If we are inspecting an optimized frame use undefined as the
9477 // value for all locals.
9478 //
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009479 // TODO(1140): We should be able to get the correct values
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009480 // for locals in optimized frames.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009481 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009482 } else if (i < info.number_of_stack_slots()) {
9483 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009484 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
9485 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009486 // Traverse the context chain to the function context as all local
9487 // variables stored in the context will be on the function context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009488 Handle<String> name = info.LocalName(i);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009489 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009490 context = Handle<Context>(context->previous());
9491 }
9492 ASSERT(context->is_function_context());
9493 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009494 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009495 }
9496 }
9497
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009498 // Check whether this frame is positioned at return. If not top
9499 // frame or if the frame is optimized it cannot be at a return.
9500 bool at_return = false;
9501 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009503 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009504
9505 // If positioned just before return find the value to be returned and add it
9506 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009508 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009509 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009510 Address internal_frame_sp = NULL;
9511 while (!it2.done()) {
9512 if (it2.frame()->is_internal()) {
9513 internal_frame_sp = it2.frame()->sp();
9514 } else {
9515 if (it2.frame()->is_java_script()) {
9516 if (it2.frame()->id() == it.frame()->id()) {
9517 // The internal frame just before the JavaScript frame contains the
9518 // value to return on top. A debug break at return will create an
9519 // internal frame to store the return value (eax/rax/r0) before
9520 // entering the debug break exit frame.
9521 if (internal_frame_sp != NULL) {
9522 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009523 Handle<Object>(Memory::Object_at(internal_frame_sp),
9524 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009525 break;
9526 }
9527 }
9528 }
9529
9530 // Indicate that the previous frame was not an internal frame.
9531 internal_frame_sp = NULL;
9532 }
9533 it2.Advance();
9534 }
9535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536
9537 // Now advance to the arguments adapter frame (if any). It contains all
9538 // the provided parameters whereas the function frame always have the number
9539 // of arguments matching the functions parameters. The rest of the
9540 // information (except for what is collected above) is the same.
9541 it.AdvanceToArgumentsFrame();
9542
9543 // Find the number of arguments to fill. At least fill the number of
9544 // parameters for the function and fill more if more parameters are provided.
9545 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009546 if (argument_count < it.frame()->ComputeParametersCount()) {
9547 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548 }
9549
9550 // Calculate the size of the result.
9551 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009552 2 * (argument_count + info.NumberOfLocals()) +
9553 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555
9556 // Add the frame id.
9557 details->set(kFrameDetailsFrameIdIndex, *frame_id);
9558
9559 // Add the function (same as in function frame).
9560 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
9561
9562 // Add the arguments count.
9563 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
9564
9565 // Add the locals count
9566 details->set(kFrameDetailsLocalCountIndex,
9567 Smi::FromInt(info.NumberOfLocals()));
9568
9569 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00009570 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
9572 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009574 }
9575
9576 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009577 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009578
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009579 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009580 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009581
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009582 // Add information on whether this frame is invoked in the debugger context.
9583 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 heap->ToBoolean(*save->context() ==
9585 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586
9587 // Fill the dynamic part.
9588 int details_index = kFrameDetailsFirstDynamicIndex;
9589
9590 // Add arguments name and value.
9591 for (int i = 0; i < argument_count; i++) {
9592 // Name of the argument.
9593 if (i < info.number_of_parameters()) {
9594 details->set(details_index++, *info.parameter_name(i));
9595 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009596 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009597 }
9598
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009599 // Parameter value. If we are inspecting an optimized frame, use
9600 // undefined as the value.
9601 //
9602 // TODO(3141533): We should be able to get the actual parameter
9603 // value for optimized frames.
9604 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009605 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009606 details->set(details_index++, it.frame()->GetParameter(i));
9607 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009608 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009609 }
9610 }
9611
9612 // Add locals name and value from the temporary copy from the function frame.
9613 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
9614 details->set(details_index++, locals->get(i));
9615 }
9616
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009617 // Add the value being returned.
9618 if (at_return) {
9619 details->set(details_index++, *return_value);
9620 }
9621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009622 // Add the receiver (same as in function frame).
9623 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
9624 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009625 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009626 if (!receiver->IsJSObject()) {
9627 // If the receiver is NOT a JSObject we have hit an optimization
9628 // where a value object is not converted into a wrapped JS objects.
9629 // To hide this optimization from the debugger, we wrap the receiver
9630 // by creating correct wrapper object based on the calling frame's
9631 // global context.
9632 it.Advance();
9633 Handle<Context> calling_frames_global_context(
9634 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009635 receiver =
9636 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009637 }
9638 details->set(kFrameDetailsReceiverIndex, *receiver);
9639
9640 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009641 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009642}
9643
9644
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009645// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009646static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009647 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +00009648 Handle<SerializedScopeInfo> serialized_scope_info,
9649 ScopeInfo<>& scope_info,
9650 Handle<Context> context,
9651 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009652 // Fill all context locals to the context extension.
9653 for (int i = Context::MIN_CONTEXT_SLOTS;
9654 i < scope_info.number_of_context_slots();
9655 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +00009656 int context_index = serialized_scope_info->ContextSlotIndex(
9657 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009658
9659 // Don't include the arguments shadow (.arguments) context variable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009660 if (*scope_info.context_slot_name(i) !=
9661 isolate->heap()->arguments_shadow_symbol()) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009662 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009663 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009664 SetProperty(scope_object,
9665 scope_info.context_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009666 Handle<Object>(context->get(context_index), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009667 NONE,
9668 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009669 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009670 }
9671 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009672
9673 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009674}
9675
9676
9677// Create a plain JSObject which materializes the local scope for the specified
9678// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009679static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
9680 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009681 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009682 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009683 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9684 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009685
9686 // Allocate and initialize a JSObject with all the arguments, stack locals
9687 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009688 Handle<JSObject> local_scope =
9689 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009690
9691 // First fill all parameters.
9692 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009693 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009694 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009695 SetProperty(local_scope,
9696 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009697 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009698 NONE,
9699 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009700 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009701 }
9702
9703 // Second fill all stack locals.
9704 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009705 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009706 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009707 SetProperty(local_scope,
9708 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009709 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009710 NONE,
9711 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009712 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009713 }
9714
9715 // Third fill all context locals.
9716 Handle<Context> frame_context(Context::cast(frame->context()));
9717 Handle<Context> function_context(frame_context->fcontext());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009718 if (!CopyContextLocalsToScopeObject(isolate,
9719 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009720 function_context, local_scope)) {
9721 return Handle<JSObject>();
9722 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009723
9724 // Finally copy any properties from the function context extension. This will
9725 // be variables introduced by eval.
9726 if (function_context->closure() == *function) {
9727 if (function_context->has_extension() &&
9728 !function_context->IsGlobalContext()) {
9729 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009730 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009731 for (int i = 0; i < keys->length(); i++) {
9732 // Names of variables introduced by eval are strings.
9733 ASSERT(keys->get(i)->IsString());
9734 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009735 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009736 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009737 SetProperty(local_scope,
9738 key,
9739 GetProperty(ext, key),
9740 NONE,
9741 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009742 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009743 }
9744 }
9745 }
9746 return local_scope;
9747}
9748
9749
9750// Create a plain JSObject which materializes the closure content for the
9751// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009752static Handle<JSObject> MaterializeClosure(Isolate* isolate,
9753 Handle<Context> context) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009754 ASSERT(context->is_function_context());
9755
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009756 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +00009757 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
9758 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009759
9760 // Allocate and initialize a JSObject with all the content of theis function
9761 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009762 Handle<JSObject> closure_scope =
9763 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009764
9765 // Check whether the arguments shadow object exists.
9766 int arguments_shadow_index =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009767 shared->scope_info()->ContextSlotIndex(
9768 isolate->heap()->arguments_shadow_symbol(), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009769 if (arguments_shadow_index >= 0) {
9770 // In this case all the arguments are available in the arguments shadow
9771 // object.
9772 Handle<JSObject> arguments_shadow(
9773 JSObject::cast(context->get(arguments_shadow_index)));
9774 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009775 // We don't expect exception-throwing getters on the arguments shadow.
9776 Object* element = arguments_shadow->GetElement(i)->ToObjectUnchecked();
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009777 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009778 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009779 SetProperty(closure_scope,
9780 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009781 Handle<Object>(element, isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009782 NONE,
9783 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009784 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009785 }
9786 }
9787
9788 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009789 if (!CopyContextLocalsToScopeObject(isolate,
9790 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009791 context, closure_scope)) {
9792 return Handle<JSObject>();
9793 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009794
9795 // Finally copy any properties from the function context extension. This will
9796 // be variables introduced by eval.
9797 if (context->has_extension()) {
9798 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009799 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009800 for (int i = 0; i < keys->length(); i++) {
9801 // Names of variables introduced by eval are strings.
9802 ASSERT(keys->get(i)->IsString());
9803 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009804 RETURN_IF_EMPTY_HANDLE_VALUE(
9805 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009806 SetProperty(closure_scope,
9807 key,
9808 GetProperty(ext, key),
9809 NONE,
9810 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009811 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009812 }
9813 }
9814
9815 return closure_scope;
9816}
9817
9818
9819// Iterate over the actual scopes visible from a stack frame. All scopes are
9820// backed by an actual context except the local scope, which is inserted
9821// "artifically" in the context chain.
9822class ScopeIterator {
9823 public:
9824 enum ScopeType {
9825 ScopeTypeGlobal = 0,
9826 ScopeTypeLocal,
9827 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +00009828 ScopeTypeClosure,
9829 // Every catch block contains an implicit with block (its parameter is
9830 // a JSContextExtensionObject) that extends current scope with a variable
9831 // holding exception object. Such with blocks are treated as scopes of their
9832 // own type.
9833 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009834 };
9835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009836 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
9837 : isolate_(isolate),
9838 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009839 function_(JSFunction::cast(frame->function())),
9840 context_(Context::cast(frame->context())),
9841 local_done_(false),
9842 at_local_(false) {
9843
9844 // Check whether the first scope is actually a local scope.
9845 if (context_->IsGlobalContext()) {
9846 // If there is a stack slot for .result then this local scope has been
9847 // created for evaluating top level code and it is not a real local scope.
9848 // Checking for the existence of .result seems fragile, but the scope info
9849 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +00009850 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009851 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009852 at_local_ = index < 0;
9853 } else if (context_->is_function_context()) {
9854 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009855 } else if (context_->closure() != *function_) {
9856 // The context_ is a with block from the outer function.
9857 ASSERT(context_->has_extension());
9858 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009859 }
9860 }
9861
9862 // More scopes?
9863 bool Done() { return context_.is_null(); }
9864
9865 // Move to the next scope.
9866 void Next() {
9867 // If at a local scope mark the local scope as passed.
9868 if (at_local_) {
9869 at_local_ = false;
9870 local_done_ = true;
9871
9872 // If the current context is not associated with the local scope the
9873 // current context is the next real scope, so don't move to the next
9874 // context in this case.
9875 if (context_->closure() != *function_) {
9876 return;
9877 }
9878 }
9879
9880 // The global scope is always the last in the chain.
9881 if (context_->IsGlobalContext()) {
9882 context_ = Handle<Context>();
9883 return;
9884 }
9885
9886 // Move to the next context.
9887 if (context_->is_function_context()) {
9888 context_ = Handle<Context>(Context::cast(context_->closure()->context()));
9889 } else {
9890 context_ = Handle<Context>(context_->previous());
9891 }
9892
9893 // If passing the local scope indicate that the current scope is now the
9894 // local scope.
9895 if (!local_done_ &&
9896 (context_->IsGlobalContext() || (context_->is_function_context()))) {
9897 at_local_ = true;
9898 }
9899 }
9900
9901 // Return the type of the current scope.
9902 int Type() {
9903 if (at_local_) {
9904 return ScopeTypeLocal;
9905 }
9906 if (context_->IsGlobalContext()) {
9907 ASSERT(context_->global()->IsGlobalObject());
9908 return ScopeTypeGlobal;
9909 }
9910 if (context_->is_function_context()) {
9911 return ScopeTypeClosure;
9912 }
9913 ASSERT(context_->has_extension());
ager@chromium.orga1645e22009-09-09 19:27:10 +00009914 // Current scope is either an explicit with statement or a with statement
9915 // implicitely generated for a catch block.
9916 // If the extension object here is a JSContextExtensionObject then
9917 // current with statement is one frome a catch block otherwise it's a
9918 // regular with statement.
9919 if (context_->extension()->IsJSContextExtensionObject()) {
9920 return ScopeTypeCatch;
9921 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009922 return ScopeTypeWith;
9923 }
9924
9925 // Return the JavaScript object with the content of the current scope.
9926 Handle<JSObject> ScopeObject() {
9927 switch (Type()) {
9928 case ScopeIterator::ScopeTypeGlobal:
9929 return Handle<JSObject>(CurrentContext()->global());
9930 break;
9931 case ScopeIterator::ScopeTypeLocal:
9932 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009933 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009934 break;
9935 case ScopeIterator::ScopeTypeWith:
ager@chromium.orga1645e22009-09-09 19:27:10 +00009936 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009937 // Return the with object.
9938 return Handle<JSObject>(CurrentContext()->extension());
9939 break;
9940 case ScopeIterator::ScopeTypeClosure:
9941 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009942 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009943 break;
9944 }
9945 UNREACHABLE();
9946 return Handle<JSObject>();
9947 }
9948
9949 // Return the context for this scope. For the local context there might not
9950 // be an actual context.
9951 Handle<Context> CurrentContext() {
9952 if (at_local_ && context_->closure() != *function_) {
9953 return Handle<Context>();
9954 }
9955 return context_;
9956 }
9957
9958#ifdef DEBUG
9959 // Debug print of the content of the current scope.
9960 void DebugPrint() {
9961 switch (Type()) {
9962 case ScopeIterator::ScopeTypeGlobal:
9963 PrintF("Global:\n");
9964 CurrentContext()->Print();
9965 break;
9966
9967 case ScopeIterator::ScopeTypeLocal: {
9968 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00009969 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009970 scope_info.Print();
9971 if (!CurrentContext().is_null()) {
9972 CurrentContext()->Print();
9973 if (CurrentContext()->has_extension()) {
9974 Handle<JSObject> extension =
9975 Handle<JSObject>(CurrentContext()->extension());
9976 if (extension->IsJSContextExtensionObject()) {
9977 extension->Print();
9978 }
9979 }
9980 }
9981 break;
9982 }
9983
9984 case ScopeIterator::ScopeTypeWith: {
9985 PrintF("With:\n");
9986 Handle<JSObject> extension =
9987 Handle<JSObject>(CurrentContext()->extension());
9988 extension->Print();
9989 break;
9990 }
9991
ager@chromium.orga1645e22009-09-09 19:27:10 +00009992 case ScopeIterator::ScopeTypeCatch: {
9993 PrintF("Catch:\n");
9994 Handle<JSObject> extension =
9995 Handle<JSObject>(CurrentContext()->extension());
9996 extension->Print();
9997 break;
9998 }
9999
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010000 case ScopeIterator::ScopeTypeClosure: {
10001 PrintF("Closure:\n");
10002 CurrentContext()->Print();
10003 if (CurrentContext()->has_extension()) {
10004 Handle<JSObject> extension =
10005 Handle<JSObject>(CurrentContext()->extension());
10006 if (extension->IsJSContextExtensionObject()) {
10007 extension->Print();
10008 }
10009 }
10010 break;
10011 }
10012
10013 default:
10014 UNREACHABLE();
10015 }
10016 PrintF("\n");
10017 }
10018#endif
10019
10020 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010022 JavaScriptFrame* frame_;
10023 Handle<JSFunction> function_;
10024 Handle<Context> context_;
10025 bool local_done_;
10026 bool at_local_;
10027
10028 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10029};
10030
10031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010032RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010033 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010034 ASSERT(args.length() == 2);
10035
10036 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010037 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010038 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10039 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010040 if (!maybe_check->ToObject(&check)) return maybe_check;
10041 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010042 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10043
10044 // Get the frame where the debugging is performed.
10045 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010046 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010047 JavaScriptFrame* frame = it.frame();
10048
10049 // Count the visible scopes.
10050 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010052 n++;
10053 }
10054
10055 return Smi::FromInt(n);
10056}
10057
10058
10059static const int kScopeDetailsTypeIndex = 0;
10060static const int kScopeDetailsObjectIndex = 1;
10061static const int kScopeDetailsSize = 2;
10062
10063// Return an array with scope details
10064// args[0]: number: break id
10065// args[1]: number: frame index
10066// args[2]: number: scope index
10067//
10068// The array returned contains the following information:
10069// 0: Scope type
10070// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010071RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010072 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010073 ASSERT(args.length() == 3);
10074
10075 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010076 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010077 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10078 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010079 if (!maybe_check->ToObject(&check)) return maybe_check;
10080 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010081 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10082 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10083
10084 // Get the frame where the debugging is performed.
10085 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010086 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010087 JavaScriptFrame* frame = frame_it.frame();
10088
10089 // Find the requested scope.
10090 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010091 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010092 for (; !it.Done() && n < index; it.Next()) {
10093 n++;
10094 }
10095 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010096 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010097 }
10098
10099 // Calculate the size of the result.
10100 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010101 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010102
10103 // Fill in scope details.
10104 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010105 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010106 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010107 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010109 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010110}
10111
10112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010113RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010114 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010115 ASSERT(args.length() == 0);
10116
10117#ifdef DEBUG
10118 // Print the scopes for the top frame.
10119 StackFrameLocator locator;
10120 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010121 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010122 it.DebugPrint();
10123 }
10124#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010125 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010126}
10127
10128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010129RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010130 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010131 ASSERT(args.length() == 1);
10132
10133 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010134 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010135 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10136 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010137 if (!maybe_result->ToObject(&result)) return maybe_result;
10138 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010139
10140 // Count all archived V8 threads.
10141 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010142 for (ThreadState* thread =
10143 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010144 thread != NULL;
10145 thread = thread->Next()) {
10146 n++;
10147 }
10148
10149 // Total number of threads is current thread and archived threads.
10150 return Smi::FromInt(n + 1);
10151}
10152
10153
10154static const int kThreadDetailsCurrentThreadIndex = 0;
10155static const int kThreadDetailsThreadIdIndex = 1;
10156static const int kThreadDetailsSize = 2;
10157
10158// Return an array with thread details
10159// args[0]: number: break id
10160// args[1]: number: thread index
10161//
10162// The array returned contains the following information:
10163// 0: Is current thread?
10164// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010165RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010167 ASSERT(args.length() == 2);
10168
10169 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010170 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010171 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10172 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010173 if (!maybe_check->ToObject(&check)) return maybe_check;
10174 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010175 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10176
10177 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010178 Handle<FixedArray> details =
10179 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010180
10181 // Thread index 0 is current thread.
10182 if (index == 0) {
10183 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010184 details->set(kThreadDetailsCurrentThreadIndex,
10185 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010186 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010187 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010188 } else {
10189 // Find the thread with the requested index.
10190 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010191 ThreadState* thread =
10192 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010193 while (index != n && thread != NULL) {
10194 thread = thread->Next();
10195 n++;
10196 }
10197 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010198 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010199 }
10200
10201 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010202 details->set(kThreadDetailsCurrentThreadIndex,
10203 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010204 details->set(kThreadDetailsThreadIdIndex,
10205 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010206 }
10207
10208 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010209 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010210}
10211
10212
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010213// Sets the disable break state
10214// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010215RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010216 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010217 ASSERT(args.length() == 1);
10218 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010219 isolate->debug()->set_disable_break(disable_break);
10220 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010221}
10222
10223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010224RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010225 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010226 ASSERT(args.length() == 1);
10227
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010228 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10229 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230 // Find the number of break points
10231 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010232 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010234 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235 Handle<FixedArray>::cast(break_locations));
10236}
10237
10238
10239// Set a break point in a function
10240// args[0]: function
10241// args[1]: number: break source position (within the function source)
10242// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010243RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010244 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010246 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10247 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10249 RUNTIME_ASSERT(source_position >= 0);
10250 Handle<Object> break_point_object_arg = args.at<Object>(2);
10251
10252 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010253 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10254 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010256 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257}
10258
10259
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010260Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10261 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010262 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263 // Iterate the heap looking for SharedFunctionInfo generated from the
10264 // script. The inner most SharedFunctionInfo containing the source position
10265 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010266 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010267 // which is found is not compiled it is compiled and the heap is iterated
10268 // again as the compilation might create inner functions from the newly
10269 // compiled function and the actual requested break point might be in one of
10270 // these functions.
10271 bool done = false;
10272 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010273 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010274 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 while (!done) {
10276 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010277 for (HeapObject* obj = iterator.next();
10278 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279 if (obj->IsSharedFunctionInfo()) {
10280 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10281 if (shared->script() == *script) {
10282 // If the SharedFunctionInfo found has the requested script data and
10283 // contains the source position it is a candidate.
10284 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010285 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 start_position = shared->start_position();
10287 }
10288 if (start_position <= position &&
10289 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010290 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291 // candidate this is the new candidate.
10292 if (target.is_null()) {
10293 target_start_position = start_position;
10294 target = shared;
10295 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010296 if (target_start_position == start_position &&
10297 shared->end_position() == target->end_position()) {
10298 // If a top-level function contain only one function
10299 // declartion the source for the top-level and the function is
10300 // the same. In that case prefer the non top-level function.
10301 if (!shared->is_toplevel()) {
10302 target_start_position = start_position;
10303 target = shared;
10304 }
10305 } else if (target_start_position <= start_position &&
10306 shared->end_position() <= target->end_position()) {
10307 // This containment check includes equality as a function inside
10308 // a top-level function can share either start or end position
10309 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 target_start_position = start_position;
10311 target = shared;
10312 }
10313 }
10314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315 }
10316 }
10317 }
10318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010319 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010320 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010321 }
10322
10323 // If the candidate found is compiled we are done. NOTE: when lazy
10324 // compilation of inner functions is introduced some additional checking
10325 // needs to be done here to compile inner functions.
10326 done = target->is_compiled();
10327 if (!done) {
10328 // If the candidate is not compiled compile it to reveal any inner
10329 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010330 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010331 }
10332 }
10333
10334 return *target;
10335}
10336
10337
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010338// Changes the state of a break point in a script and returns source position
10339// where break point was set. NOTE: Regarding performance see the NOTE for
10340// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341// args[0]: script to set break point in
10342// args[1]: number: break source position (within the script source)
10343// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010344RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010345 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010346 ASSERT(args.length() == 3);
10347 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10348 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10349 RUNTIME_ASSERT(source_position >= 0);
10350 Handle<Object> break_point_object_arg = args.at<Object>(2);
10351
10352 // Get the script from the script wrapper.
10353 RUNTIME_ASSERT(wrapper->value()->IsScript());
10354 Handle<Script> script(Script::cast(wrapper->value()));
10355
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010356 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010357 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010358 if (!result->IsUndefined()) {
10359 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10360 // Find position within function. The script position might be before the
10361 // source position of the first function.
10362 int position;
10363 if (shared->start_position() > source_position) {
10364 position = 0;
10365 } else {
10366 position = source_position - shared->start_position();
10367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010368 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010369 position += shared->start_position();
10370 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010372 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010373}
10374
10375
10376// Clear a break point
10377// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010378RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010379 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010380 ASSERT(args.length() == 1);
10381 Handle<Object> break_point_object_arg = args.at<Object>(0);
10382
10383 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010384 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010385
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010386 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010387}
10388
10389
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010390// Change the state of break on exceptions.
10391// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10392// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010393RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010394 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010395 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010396 RUNTIME_ASSERT(args[0]->IsNumber());
10397 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010399 // If the number doesn't match an enum value, the ChangeBreakOnException
10400 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010401 ExceptionBreakType type =
10402 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010403 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010404 isolate->debug()->ChangeBreakOnException(type, enable);
10405 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010406}
10407
10408
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010409// Returns the state of break on exceptions
10410// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010411RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010412 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010413 ASSERT(args.length() == 1);
10414 RUNTIME_ASSERT(args[0]->IsNumber());
10415
10416 ExceptionBreakType type =
10417 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010418 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010419 return Smi::FromInt(result);
10420}
10421
10422
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010423// Prepare for stepping
10424// args[0]: break id for checking execution state
10425// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010426// args[2]: number of times to perform the step, for step out it is the number
10427// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010428RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010429 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 ASSERT(args.length() == 3);
10431 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010432 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010433 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10434 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010435 if (!maybe_check->ToObject(&check)) return maybe_check;
10436 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010437 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010439 }
10440
10441 // Get the step action and check validity.
10442 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10443 if (step_action != StepIn &&
10444 step_action != StepNext &&
10445 step_action != StepOut &&
10446 step_action != StepInMin &&
10447 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010448 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010449 }
10450
10451 // Get the number of steps.
10452 int step_count = NumberToInt32(args[2]);
10453 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010454 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 }
10456
ager@chromium.orga1645e22009-09-09 19:27:10 +000010457 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010458 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010459
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010461 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10462 step_count);
10463 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464}
10465
10466
10467// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010468RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010470 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010471 isolate->debug()->ClearStepping();
10472 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473}
10474
10475
10476// Creates a copy of the with context chain. The copy of the context chain is
10477// is linked to the function context supplied.
10478static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
10479 Handle<Context> function_context) {
10480 // At the bottom of the chain. Return the function context to link to.
10481 if (context_chain->is_function_context()) {
10482 return function_context;
10483 }
10484
10485 // Recursively copy the with contexts.
10486 Handle<Context> previous(context_chain->previous());
10487 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
danno@chromium.org160a7b02011-04-18 15:51:38 +000010488 Handle<Context> context = CopyWithContextChain(previous, function_context);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010489 return context->GetIsolate()->factory()->NewWithContext(
10490 context, extension, context_chain->IsCatchContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010491}
10492
10493
10494// Helper function to find or create the arguments object for
10495// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010496static Handle<Object> GetArgumentsObject(Isolate* isolate,
10497 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010498 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010499 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010500 const ScopeInfo<>* sinfo,
10501 Handle<Context> function_context) {
10502 // Try to find the value of 'arguments' to pass as parameter. If it is not
10503 // found (that is the debugged function does not reference 'arguments' and
10504 // does not support eval) then create an 'arguments' object.
10505 int index;
10506 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010507 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010509 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510 }
10511 }
10512
10513 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010514 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
10515 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518 }
10519 }
10520
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010521 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010522 Handle<JSObject> arguments =
10523 isolate->factory()->NewArgumentsObject(function, length);
10524 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010525
10526 AssertNoAllocation no_gc;
10527 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010528 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010529 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010531 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532 return arguments;
10533}
10534
10535
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010536static const char kSourceStr[] =
10537 "(function(arguments,__source__){return eval(__source__);})";
10538
10539
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010540// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000010541// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010542// extension part has all the parameters and locals of the function on the
10543// stack frame. A function which calls eval with the code to evaluate is then
10544// compiled in this context and called in this context. As this context
10545// replaces the context of the function on the stack frame a new (empty)
10546// function is created as well to be used as the closure for the context.
10547// This function and the context acts as replacements for the function on the
10548// stack frame presenting the same view of the values of parameters and
10549// local variables as if the piece of JavaScript was evaluated at the point
10550// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010551RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010552 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553
10554 // Check the execution state and decode arguments frame and source to be
10555 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010556 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010557 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010558 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10559 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010560 if (!maybe_check_result->ToObject(&check_result)) {
10561 return maybe_check_result;
10562 }
10563 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010564 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10565 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010566 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010567 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010568
10569 // Handle the processing of break.
10570 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010571
10572 // Get the frame where the debugging is performed.
10573 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010574 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575 JavaScriptFrame* frame = it.frame();
10576 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010577 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010578 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010579
10580 // Traverse the saved contexts chain to find the active context for the
10581 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010582 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010583 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 save = save->prev();
10585 }
10586 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010587 SaveContext savex(isolate);
10588 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589
10590 // Create the (empty) function replacing the function on the stack frame for
10591 // the purpose of evaluating in the context created below. It is important
10592 // that this function does not describe any parameters and local variables
10593 // in the context. If it does then this will cause problems with the lookup
10594 // in Context::Lookup, where context slots for parameters and local variables
10595 // are looked at before the extension object.
10596 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010597 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
10598 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 go_between->set_context(function->context());
10600#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010601 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602 ASSERT(go_between_sinfo.number_of_parameters() == 0);
10603 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
10604#endif
10605
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010606 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
10608 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010609
10610 // Allocate a new context for the debug evaluation and set the extension
10611 // object build.
10612 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010613 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
10614 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010615 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010617 Handle<Context> frame_context(Context::cast(frame->context()));
10618 Handle<Context> function_context(frame_context->fcontext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619 context = CopyWithContextChain(frame_context, context);
10620
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010621 if (additional_context->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010622 context = isolate->factory()->NewWithContext(context,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010623 Handle<JSObject>::cast(additional_context), false);
10624 }
10625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626 // Wrap the evaluation statement in a new function compiled in the newly
10627 // created context. The function has one parameter which has to be called
10628 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000010629 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010630 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010631
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010632 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010633 isolate->factory()->NewStringFromAscii(
10634 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010635
10636 // Currently, the eval code will be executed in non-strict mode,
10637 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010638 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000010639 Compiler::CompileEval(function_source,
10640 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010641 context->IsGlobalContext(),
10642 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010643 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010645 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646
10647 // Invoke the result of the compilation to get the evaluation function.
10648 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010649 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010650 Handle<Object> evaluation_function =
10651 Execution::Call(compiled_function, receiver, 0, NULL,
10652 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010653 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010655 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
10656 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010657 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010658
10659 // Invoke the evaluation function and return the result.
10660 const int argc = 2;
10661 Object** argv[argc] = { arguments.location(),
10662 Handle<Object>::cast(source).location() };
10663 Handle<Object> result =
10664 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
10665 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010666 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010667
10668 // Skip the global proxy as it has no properties and always delegates to the
10669 // real global object.
10670 if (result->IsJSGlobalProxy()) {
10671 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
10672 }
10673
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010674 return *result;
10675}
10676
10677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010678RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010679 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010680
10681 // Check the execution state and decode arguments frame and source to be
10682 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010683 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010684 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010685 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
10686 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010687 if (!maybe_check_result->ToObject(&check_result)) {
10688 return maybe_check_result;
10689 }
10690 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010691 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010692 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010693 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000010694
10695 // Handle the processing of break.
10696 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010697
10698 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010699 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010700 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010701 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010702 top = top->prev();
10703 }
10704 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010705 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706 }
10707
10708 // Get the global context now set to the top context from before the
10709 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010710 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010711
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010712 bool is_global = true;
10713
10714 if (additional_context->IsJSObject()) {
10715 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010716 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
10717 isolate->factory()->empty_string(),
10718 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010719 go_between->set_context(*context);
10720 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010721 isolate->factory()->NewFunctionContext(
10722 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000010723 context->set_extension(JSObject::cast(*additional_context));
10724 is_global = false;
10725 }
10726
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010727 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010728 // Currently, the eval code will be executed in non-strict mode,
10729 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010730 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010731 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000010732 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010733 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010734 Handle<JSFunction>(
10735 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
10736 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010737
10738 // Invoke the result of the compilation to get the evaluation function.
10739 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010740 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010741 Handle<Object> result =
10742 Execution::Call(compiled_function, receiver, 0, NULL,
10743 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000010744 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010745 return *result;
10746}
10747
10748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010749RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010750 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000010751 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010753 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010754 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010755
10756 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010757 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010758 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
10759 // Get the script wrapper in a local handle before calling GetScriptWrapper,
10760 // because using
10761 // instances->set(i, *GetScriptWrapper(script))
10762 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
10763 // already have deferenced the instances handle.
10764 Handle<JSValue> wrapper = GetScriptWrapper(script);
10765 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010766 }
10767
10768 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 Handle<JSObject> result =
10770 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771 Handle<JSArray>::cast(result)->SetContent(*instances);
10772 return *result;
10773}
10774
10775
10776// Helper function used by Runtime_DebugReferencedBy below.
10777static int DebugReferencedBy(JSObject* target,
10778 Object* instance_filter, int max_references,
10779 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780 JSFunction* arguments_function) {
10781 NoHandleAllocation ha;
10782 AssertNoAllocation no_alloc;
10783
10784 // Iterate the heap.
10785 int count = 0;
10786 JSObject* last = NULL;
10787 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010788 HeapObject* heap_obj = NULL;
10789 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790 (max_references == 0 || count < max_references)) {
10791 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010792 if (heap_obj->IsJSObject()) {
10793 // Skip context extension objects and argument arrays as these are
10794 // checked in the context of functions using them.
10795 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010796 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010797 obj->map()->constructor() == arguments_function) {
10798 continue;
10799 }
10800
10801 // Check if the JS object has a reference to the object looked for.
10802 if (obj->ReferencesObject(target)) {
10803 // Check instance filter if supplied. This is normally used to avoid
10804 // references from mirror objects (see Runtime_IsInPrototypeChain).
10805 if (!instance_filter->IsUndefined()) {
10806 Object* V = obj;
10807 while (true) {
10808 Object* prototype = V->GetPrototype();
10809 if (prototype->IsNull()) {
10810 break;
10811 }
10812 if (instance_filter == prototype) {
10813 obj = NULL; // Don't add this object.
10814 break;
10815 }
10816 V = prototype;
10817 }
10818 }
10819
10820 if (obj != NULL) {
10821 // Valid reference found add to instance array if supplied an update
10822 // count.
10823 if (instances != NULL && count < instances_size) {
10824 instances->set(count, obj);
10825 }
10826 last = obj;
10827 count++;
10828 }
10829 }
10830 }
10831 }
10832
10833 // Check for circular reference only. This can happen when the object is only
10834 // referenced from mirrors and has a circular reference in which case the
10835 // object is not really alive and would have been garbage collected if not
10836 // referenced from the mirror.
10837 if (count == 1 && last == target) {
10838 count = 0;
10839 }
10840
10841 // Return the number of referencing objects found.
10842 return count;
10843}
10844
10845
10846// Scan the heap for objects with direct references to an object
10847// args[0]: the object to find references to
10848// args[1]: constructor function for instances to exclude (Mirror)
10849// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010850RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010851 ASSERT(args.length() == 3);
10852
10853 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010854 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010855
10856 // Check parameters.
10857 CONVERT_CHECKED(JSObject, target, args[0]);
10858 Object* instance_filter = args[1];
10859 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
10860 instance_filter->IsJSObject());
10861 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
10862 RUNTIME_ASSERT(max_references >= 0);
10863
10864 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010865 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010866 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867 JSFunction* arguments_function =
10868 JSFunction::cast(arguments_boilerplate->map()->constructor());
10869
10870 // Get the number of referencing objects.
10871 int count;
10872 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010873 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874
10875 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010876 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010877 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010878 if (!maybe_object->ToObject(&object)) return maybe_object;
10879 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880 FixedArray* instances = FixedArray::cast(object);
10881
10882 // Fill the referencing objects.
10883 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000010884 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010885
10886 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010887 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010888 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10889 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010890 if (!maybe_result->ToObject(&result)) return maybe_result;
10891 }
10892 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893 return result;
10894}
10895
10896
10897// Helper function used by Runtime_DebugConstructedBy below.
10898static int DebugConstructedBy(JSFunction* constructor, int max_references,
10899 FixedArray* instances, int instances_size) {
10900 AssertNoAllocation no_alloc;
10901
10902 // Iterate the heap.
10903 int count = 0;
10904 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010905 HeapObject* heap_obj = NULL;
10906 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010907 (max_references == 0 || count < max_references)) {
10908 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010909 if (heap_obj->IsJSObject()) {
10910 JSObject* obj = JSObject::cast(heap_obj);
10911 if (obj->map()->constructor() == constructor) {
10912 // Valid reference found add to instance array if supplied an update
10913 // count.
10914 if (instances != NULL && count < instances_size) {
10915 instances->set(count, obj);
10916 }
10917 count++;
10918 }
10919 }
10920 }
10921
10922 // Return the number of referencing objects found.
10923 return count;
10924}
10925
10926
10927// Scan the heap for objects constructed by a specific function.
10928// args[0]: the constructor to find instances of
10929// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010930RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931 ASSERT(args.length() == 2);
10932
10933 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010934 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010935
10936 // Check parameters.
10937 CONVERT_CHECKED(JSFunction, constructor, args[0]);
10938 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
10939 RUNTIME_ASSERT(max_references >= 0);
10940
10941 // Get the number of referencing objects.
10942 int count;
10943 count = DebugConstructedBy(constructor, max_references, NULL, 0);
10944
10945 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010946 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010947 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010948 if (!maybe_object->ToObject(&object)) return maybe_object;
10949 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950 FixedArray* instances = FixedArray::cast(object);
10951
10952 // Fill the referencing objects.
10953 count = DebugConstructedBy(constructor, max_references, instances, count);
10954
10955 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010956 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010957 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
10958 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010959 if (!maybe_result->ToObject(&result)) return maybe_result;
10960 }
10961 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010962 return result;
10963}
10964
10965
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010966// Find the effective prototype object as returned by __proto__.
10967// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010968RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969 ASSERT(args.length() == 1);
10970
10971 CONVERT_CHECKED(JSObject, obj, args[0]);
10972
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010973 // Use the __proto__ accessor.
10974 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010975}
10976
10977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010978RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000010979 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010980 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010981 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982}
10983
10984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010985RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010986#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010988 ASSERT(args.length() == 1);
10989 // Get the function and make sure it is compiled.
10990 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010991 Handle<SharedFunctionInfo> shared(func->shared());
10992 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010993 return Failure::Exception();
10994 }
10995 func->code()->PrintLn();
10996#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010997 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010998}
ager@chromium.org9085a012009-05-11 19:22:57 +000010999
11000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011001RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011002#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011003 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011004 ASSERT(args.length() == 1);
11005 // Get the function and make sure it is compiled.
11006 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011007 Handle<SharedFunctionInfo> shared(func->shared());
11008 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011009 return Failure::Exception();
11010 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011011 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011012#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011014}
11015
11016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011017RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011018 NoHandleAllocation ha;
11019 ASSERT(args.length() == 1);
11020
11021 CONVERT_CHECKED(JSFunction, f, args[0]);
11022 return f->shared()->inferred_name();
11023}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011024
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011025
11026static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011027 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011028 AssertNoAllocation no_allocations;
11029
11030 int counter = 0;
11031 int buffer_size = buffer->length();
11032 HeapIterator iterator;
11033 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11034 ASSERT(obj != NULL);
11035 if (!obj->IsSharedFunctionInfo()) {
11036 continue;
11037 }
11038 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11039 if (shared->script() != script) {
11040 continue;
11041 }
11042 if (counter < buffer_size) {
11043 buffer->set(counter, shared);
11044 }
11045 counter++;
11046 }
11047 return counter;
11048}
11049
11050// For a script finds all SharedFunctionInfo's in the heap that points
11051// to this script. Returns JSArray of SharedFunctionInfo wrapped
11052// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011053RUNTIME_FUNCTION(MaybeObject*,
11054 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011055 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011056 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011057 CONVERT_CHECKED(JSValue, script_value, args[0]);
11058
11059 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11060
11061 const int kBufferSize = 32;
11062
11063 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011064 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011065 int number = FindSharedFunctionInfosForScript(*script, *array);
11066 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011067 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011068 FindSharedFunctionInfosForScript(*script, *array);
11069 }
11070
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011071 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011072 result->set_length(Smi::FromInt(number));
11073
11074 LiveEdit::WrapSharedFunctionInfos(result);
11075
11076 return *result;
11077}
11078
11079// For a script calculates compilation information about all its functions.
11080// The script source is explicitly specified by the second argument.
11081// The source of the actual script is not used, however it is important that
11082// all generated code keeps references to this particular instance of script.
11083// Returns a JSArray of compilation infos. The array is ordered so that
11084// each function with all its descendant is always stored in a continues range
11085// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011086RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011087 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011088 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011089 CONVERT_CHECKED(JSValue, script, args[0]);
11090 CONVERT_ARG_CHECKED(String, source, 1);
11091 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11092
11093 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11094
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011095 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011096 return Failure::Exception();
11097 }
11098
11099 return result;
11100}
11101
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011102// Changes the source of the script to a new_source.
11103// If old_script_name is provided (i.e. is a String), also creates a copy of
11104// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011105RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011106 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011107 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011108 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11109 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011111
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011112 CONVERT_CHECKED(Script, original_script_pointer,
11113 original_script_value->value());
11114 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011115
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011116 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11117 new_source,
11118 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011119
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011120 if (old_script->IsScript()) {
11121 Handle<Script> script_handle(Script::cast(old_script));
11122 return *(GetScriptWrapper(script_handle));
11123 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011124 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011125 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011126}
11127
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011129RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011130 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011131 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011132 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11133 return LiveEdit::FunctionSourceUpdated(shared_info);
11134}
11135
11136
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011137// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011138RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011139 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011140 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011141 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11142 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11143
ager@chromium.orgac091b72010-05-05 07:34:42 +000011144 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011145}
11146
11147// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011148RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011149 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011150 HandleScope scope(isolate);
11151 Handle<Object> function_object(args[0], isolate);
11152 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011153
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011154 if (function_object->IsJSValue()) {
11155 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11156 if (script_object->IsJSValue()) {
11157 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011158 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011159 }
11160
11161 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11162 } else {
11163 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11164 // and we check it in this function.
11165 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011167 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011168}
11169
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011170
11171// In a code of a parent function replaces original function as embedded object
11172// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011173RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011174 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011175 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011176
11177 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11178 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11179 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11180
11181 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11182 subst_wrapper);
11183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011184 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011185}
11186
11187
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011188// Updates positions of a shared function info (first parameter) according
11189// to script source change. Text change is described in second parameter as
11190// array of groups of 3 numbers:
11191// (change_begin, change_end, change_end_new_position).
11192// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011193RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011194 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011195 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011196 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11197 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11198
ager@chromium.orgac091b72010-05-05 07:34:42 +000011199 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011200}
11201
11202
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011203// For array of SharedFunctionInfo's (each wrapped in JSValue)
11204// checks that none of them have activations on stacks (of any thread).
11205// Returns array of the same length with corresponding results of
11206// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011207RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011208 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011209 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011210 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011211 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011212
ager@chromium.org357bf652010-04-12 11:30:10 +000011213 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011214}
11215
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011216// Compares 2 strings line-by-line, then token-wise and returns diff in form
11217// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11218// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011219RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011220 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011221 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011222 CONVERT_ARG_CHECKED(String, s1, 0);
11223 CONVERT_ARG_CHECKED(String, s2, 1);
11224
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011225 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011226}
11227
11228
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011229// A testing entry. Returns statement position which is the closest to
11230// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011231RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011232 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011233 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011234 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11235 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11236
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011237 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011238
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011239 if (code->kind() != Code::FUNCTION &&
11240 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011241 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011242 }
11243
11244 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011245 int closest_pc = 0;
11246 int distance = kMaxInt;
11247 while (!it.done()) {
11248 int statement_position = static_cast<int>(it.rinfo()->data());
11249 // Check if this break point is closer that what was previously found.
11250 if (source_position <= statement_position &&
11251 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011252 closest_pc =
11253 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011254 distance = statement_position - source_position;
11255 // Check whether we can't get any closer.
11256 if (distance == 0) break;
11257 }
11258 it.next();
11259 }
11260
11261 return Smi::FromInt(closest_pc);
11262}
11263
11264
ager@chromium.org357bf652010-04-12 11:30:10 +000011265// Calls specified function with or without entering the debugger.
11266// This is used in unit tests to run code as if debugger is entered or simply
11267// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011268RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011269 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011270 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011271 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11272 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11273
11274 Handle<Object> result;
11275 bool pending_exception;
11276 {
11277 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011278 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011279 &pending_exception);
11280 } else {
11281 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011282 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011283 &pending_exception);
11284 }
11285 }
11286 if (!pending_exception) {
11287 return *result;
11288 } else {
11289 return Failure::Exception();
11290 }
11291}
11292
11293
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011294// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011295RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011296 CONVERT_CHECKED(String, arg, args[0]);
11297 SmartPointer<char> flags =
11298 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11299 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011300 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011301}
11302
11303
11304// Performs a GC.
11305// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011306RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011307 isolate->heap()->CollectAllGarbage(true);
11308 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011309}
11310
11311
11312// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011313RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011314 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011315 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011316 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011317 }
11318 return Smi::FromInt(usage);
11319}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011320
11321
11322// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011323RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011324#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011325 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011326#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011327 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011328#endif
11329}
11330
11331
11332// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011333RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011334#ifdef LIVE_OBJECT_LIST
11335 return LiveObjectList::Capture();
11336#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011337 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011338#endif
11339}
11340
11341
11342// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011343RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011344#ifdef LIVE_OBJECT_LIST
11345 CONVERT_SMI_CHECKED(id, args[0]);
11346 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011347 return success ? isolate->heap()->true_value() :
11348 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011349#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011350 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011351#endif
11352}
11353
11354
11355// Generates the response to a debugger request for a dump of the objects
11356// contained in the difference between the captured live object lists
11357// specified by id1 and id2.
11358// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11359// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011360RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011361#ifdef LIVE_OBJECT_LIST
11362 HandleScope scope;
11363 CONVERT_SMI_CHECKED(id1, args[0]);
11364 CONVERT_SMI_CHECKED(id2, args[1]);
11365 CONVERT_SMI_CHECKED(start, args[2]);
11366 CONVERT_SMI_CHECKED(count, args[3]);
11367 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11368 EnterDebugger enter_debugger;
11369 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11370#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011371 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011372#endif
11373}
11374
11375
11376// Gets the specified object as requested by the debugger.
11377// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011378RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011379#ifdef LIVE_OBJECT_LIST
11380 CONVERT_SMI_CHECKED(obj_id, args[0]);
11381 Object* result = LiveObjectList::GetObj(obj_id);
11382 return result;
11383#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011384 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011385#endif
11386}
11387
11388
11389// Gets the obj id for the specified address if valid.
11390// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011391RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011392#ifdef LIVE_OBJECT_LIST
11393 HandleScope scope;
11394 CONVERT_ARG_CHECKED(String, address, 0);
11395 Object* result = LiveObjectList::GetObjId(address);
11396 return result;
11397#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011398 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011399#endif
11400}
11401
11402
11403// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011404RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011405#ifdef LIVE_OBJECT_LIST
11406 HandleScope scope;
11407 CONVERT_SMI_CHECKED(obj_id, args[0]);
11408 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11409 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11410 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11411 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11412 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11413
11414 Handle<JSObject> instance_filter;
11415 if (args[1]->IsJSObject()) {
11416 instance_filter = args.at<JSObject>(1);
11417 }
11418 bool verbose = false;
11419 if (args[2]->IsBoolean()) {
11420 verbose = args[2]->IsTrue();
11421 }
11422 int start = 0;
11423 if (args[3]->IsSmi()) {
11424 start = Smi::cast(args[3])->value();
11425 }
11426 int limit = Smi::kMaxValue;
11427 if (args[4]->IsSmi()) {
11428 limit = Smi::cast(args[4])->value();
11429 }
11430
11431 return LiveObjectList::GetObjRetainers(obj_id,
11432 instance_filter,
11433 verbose,
11434 start,
11435 limit,
11436 filter_obj);
11437#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011439#endif
11440}
11441
11442
11443// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011444RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011445#ifdef LIVE_OBJECT_LIST
11446 HandleScope scope;
11447 CONVERT_SMI_CHECKED(obj_id1, args[0]);
11448 CONVERT_SMI_CHECKED(obj_id2, args[1]);
11449 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11450
11451 Handle<JSObject> instance_filter;
11452 if (args[2]->IsJSObject()) {
11453 instance_filter = args.at<JSObject>(2);
11454 }
11455
11456 Object* result =
11457 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
11458 return result;
11459#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011460 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011461#endif
11462}
11463
11464
11465// Generates the response to a debugger request for a list of all
11466// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011467RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011468#ifdef LIVE_OBJECT_LIST
11469 CONVERT_SMI_CHECKED(start, args[0]);
11470 CONVERT_SMI_CHECKED(count, args[1]);
11471 return LiveObjectList::Info(start, count);
11472#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011473 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011474#endif
11475}
11476
11477
11478// Gets a dump of the specified object as requested by the debugger.
11479// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011480RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011481#ifdef LIVE_OBJECT_LIST
11482 HandleScope scope;
11483 CONVERT_SMI_CHECKED(obj_id, args[0]);
11484 Object* result = LiveObjectList::PrintObj(obj_id);
11485 return result;
11486#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011487 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011488#endif
11489}
11490
11491
11492// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011493RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011494#ifdef LIVE_OBJECT_LIST
11495 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011496 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011497#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011499#endif
11500}
11501
11502
11503// Generates the response to a debugger request for a summary of the types
11504// of objects in the difference between the captured live object lists
11505// specified by id1 and id2.
11506// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11507// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011508RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011509#ifdef LIVE_OBJECT_LIST
11510 HandleScope scope;
11511 CONVERT_SMI_CHECKED(id1, args[0]);
11512 CONVERT_SMI_CHECKED(id2, args[1]);
11513 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
11514
11515 EnterDebugger enter_debugger;
11516 return LiveObjectList::Summarize(id1, id2, filter_obj);
11517#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011518 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011519#endif
11520}
11521
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011522#endif // ENABLE_DEBUGGER_SUPPORT
11523
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011524
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011525#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011526RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011527 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011528 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011529
11530 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011531 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11532 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011533 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011534}
11535
11536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011537RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011538 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000011539 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011540
11541 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000011542 CONVERT_CHECKED(Smi, smi_tag, args[1]);
11543 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011544 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011545}
11546
11547#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011548
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011549// Finds the script object from the script data. NOTE: This operation uses
11550// heap traversal to find the function generated for the source position
11551// for the requested break point. For lazily compiled functions several heap
11552// traversals might be required rendering this operation as a rather slow
11553// operation. However for setting break points which is normally done through
11554// some kind of user interaction the performance is not crucial.
11555static Handle<Object> Runtime_GetScriptFromScriptName(
11556 Handle<String> script_name) {
11557 // Scan the heap for Script objects to find the script with the requested
11558 // script data.
11559 Handle<Script> script;
11560 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011561 HeapObject* obj = NULL;
11562 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011563 // If a script is found check if it has the script data requested.
11564 if (obj->IsScript()) {
11565 if (Script::cast(obj)->name()->IsString()) {
11566 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
11567 script = Handle<Script>(Script::cast(obj));
11568 }
11569 }
11570 }
11571 }
11572
11573 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011575
11576 // Return the script found.
11577 return GetScriptWrapper(script);
11578}
11579
11580
11581// Get the script object from script data. NOTE: Regarding performance
11582// see the NOTE for GetScriptFromScriptData.
11583// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011584RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011585 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011586
11587 ASSERT(args.length() == 1);
11588
11589 CONVERT_CHECKED(String, script_name, args[0]);
11590
11591 // Find the requested script.
11592 Handle<Object> result =
11593 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
11594 return *result;
11595}
11596
11597
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011598// Determines whether the given stack frame should be displayed in
11599// a stack trace. The caller is the error constructor that asked
11600// for the stack trace to be collected. The first time a construct
11601// call to this function is encountered it is skipped. The seen_caller
11602// in/out parameter is used to remember if the caller has been seen
11603// yet.
11604static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
11605 bool* seen_caller) {
11606 // Only display JS frames.
11607 if (!raw_frame->is_java_script())
11608 return false;
11609 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
11610 Object* raw_fun = frame->function();
11611 // Not sure when this can happen but skip it just in case.
11612 if (!raw_fun->IsJSFunction())
11613 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011614 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011615 *seen_caller = true;
11616 return false;
11617 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011618 // Skip all frames until we've seen the caller. Also, skip the most
11619 // obvious builtin calls. Some builtin calls (such as Number.ADD
11620 // which is invoked using 'call') are very difficult to recognize
11621 // so we're leaving them in for now.
11622 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011623}
11624
11625
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011626// Collect the raw data for a stack trace. Returns an array of 4
11627// element segments each containing a receiver, function, code and
11628// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011629RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011630 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011631 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011632 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
11633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011634 HandleScope scope(isolate);
11635 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011636
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000011637 limit = Max(limit, 0); // Ensure that limit is not negative.
11638 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011639 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011640 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011641
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011642 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011643 // If the caller parameter is a function we skip frames until we're
11644 // under it before starting to collect.
11645 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011646 int cursor = 0;
11647 int frames_seen = 0;
11648 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011649 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011650 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011651 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011652 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011653 // Set initial size to the maximum inlining level + 1 for the outermost
11654 // function.
11655 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011656 frame->Summarize(&frames);
11657 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011658 if (cursor + 4 > elements->length()) {
11659 int new_capacity = JSObject::NewElementsCapacity(elements->length());
11660 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011661 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011662 for (int i = 0; i < cursor; i++) {
11663 new_elements->set(i, elements->get(i));
11664 }
11665 elements = new_elements;
11666 }
11667 ASSERT(cursor + 4 <= elements->length());
11668
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011669 Handle<Object> recv = frames[i].receiver();
11670 Handle<JSFunction> fun = frames[i].function();
11671 Handle<Code> code = frames[i].code();
11672 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011673 elements->set(cursor++, *recv);
11674 elements->set(cursor++, *fun);
11675 elements->set(cursor++, *code);
11676 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011677 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011678 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011679 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011680 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011681 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011682 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011683 return *result;
11684}
11685
11686
ager@chromium.org3811b432009-10-28 14:53:37 +000011687// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011688RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011689 ASSERT_EQ(args.length(), 0);
11690
11691 NoHandleAllocation ha;
11692
11693 const char* version_string = v8::V8::GetVersion();
11694
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011695 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
11696 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000011697}
11698
11699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011700RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011701 ASSERT(args.length() == 2);
11702 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
11703 Smi::cast(args[1])->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011704 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011705 OS::Abort();
11706 UNREACHABLE();
11707 return NULL;
11708}
11709
11710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011711RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011712 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011713 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011714 Object* key = args[1];
11715
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011716 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011717 Object* o = cache->get(finger_index);
11718 if (o == key) {
11719 // The fastest case: hit the same place again.
11720 return cache->get(finger_index + 1);
11721 }
11722
11723 for (int i = finger_index - 2;
11724 i >= JSFunctionResultCache::kEntriesIndex;
11725 i -= 2) {
11726 o = cache->get(i);
11727 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011728 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011729 return cache->get(i + 1);
11730 }
11731 }
11732
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011733 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011734 ASSERT(size <= cache->length());
11735
11736 for (int i = size - 2; i > finger_index; i -= 2) {
11737 o = cache->get(i);
11738 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011739 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011740 return cache->get(i + 1);
11741 }
11742 }
11743
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011744 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011745 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011746
11747 Handle<JSFunctionResultCache> cache_handle(cache);
11748 Handle<Object> key_handle(key);
11749 Handle<Object> value;
11750 {
11751 Handle<JSFunction> factory(JSFunction::cast(
11752 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
11753 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011754 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011755 // This handle is nor shared, nor used later, so it's safe.
11756 Object** argv[] = { key_handle.location() };
11757 bool pending_exception = false;
11758 value = Execution::Call(factory,
11759 receiver,
11760 1,
11761 argv,
11762 &pending_exception);
11763 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011764 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000011765
11766#ifdef DEBUG
11767 cache_handle->JSFunctionResultCacheVerify();
11768#endif
11769
11770 // Function invocation may have cleared the cache. Reread all the data.
11771 finger_index = cache_handle->finger_index();
11772 size = cache_handle->size();
11773
11774 // If we have spare room, put new data into it, otherwise evict post finger
11775 // entry which is likely to be the least recently used.
11776 int index = -1;
11777 if (size < cache_handle->length()) {
11778 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
11779 index = size;
11780 } else {
11781 index = finger_index + JSFunctionResultCache::kEntrySize;
11782 if (index == cache_handle->length()) {
11783 index = JSFunctionResultCache::kEntriesIndex;
11784 }
11785 }
11786
11787 ASSERT(index % 2 == 0);
11788 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
11789 ASSERT(index < cache_handle->length());
11790
11791 cache_handle->set(index, *key_handle);
11792 cache_handle->set(index + 1, *value);
11793 cache_handle->set_finger_index(index);
11794
11795#ifdef DEBUG
11796 cache_handle->JSFunctionResultCacheVerify();
11797#endif
11798
11799 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011800}
11801
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011803RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011804 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011805 CONVERT_ARG_CHECKED(String, type, 0);
11806 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011807 return *isolate->factory()->NewJSMessageObject(
11808 type,
11809 arguments,
11810 0,
11811 0,
11812 isolate->factory()->undefined_value(),
11813 isolate->factory()->undefined_value(),
11814 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011815}
11816
11817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011818RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011819 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11820 return message->type();
11821}
11822
11823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011824RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011825 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11826 return message->arguments();
11827}
11828
11829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011830RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011831 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11832 return Smi::FromInt(message->start_position());
11833}
11834
11835
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011836RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000011837 CONVERT_CHECKED(JSMessageObject, message, args[0]);
11838 return message->script();
11839}
11840
11841
kasper.lund44510672008-07-25 07:37:58 +000011842#ifdef DEBUG
11843// ListNatives is ONLY used by the fuzz-natives.js in debug mode
11844// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011845RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000011846 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011847 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011848#define COUNT_ENTRY(Name, argc, ressize) + 1
11849 int entry_count = 0
11850 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
11851 INLINE_FUNCTION_LIST(COUNT_ENTRY)
11852 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
11853#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011854 Factory* factory = isolate->factory();
11855 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011856 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011857 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011858#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011859 { \
11860 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011861 Handle<String> name; \
11862 /* Inline runtime functions have an underscore in front of the name. */ \
11863 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011865 Vector<const char>("_" #Name, StrLength("_" #Name))); \
11866 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011867 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011868 Vector<const char>(#Name, StrLength(#Name))); \
11869 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011870 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011871 pair_elements->set(0, *name); \
11872 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011873 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011874 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011875 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011876 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011878 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011879 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000011880 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011882 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011883 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011884 return *result;
11885}
kasper.lund44510672008-07-25 07:37:58 +000011886#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011887
11888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011889RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011890 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011891 CONVERT_CHECKED(String, format, args[0]);
11892 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011893 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011894 LOGGER->LogRuntime(chars, elms);
11895 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000011896}
11897
11898
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011899RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900 UNREACHABLE(); // implemented as macro in the parser
11901 return NULL;
11902}
11903
11904
11905// ----------------------------------------------------------------------------
11906// Implementation of Runtime
11907
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011908#define F(name, number_of_args, result_size) \
11909 { Runtime::k##name, Runtime::RUNTIME, #name, \
11910 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011912
11913#define I(name, number_of_args, result_size) \
11914 { Runtime::kInline##name, Runtime::INLINE, \
11915 "_" #name, NULL, number_of_args, result_size },
11916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011917static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011918 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011919 INLINE_FUNCTION_LIST(I)
11920 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011921};
11922
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011923
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011924MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
11925 Object* dictionary) {
11926 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011927 ASSERT(dictionary != NULL);
11928 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
11929 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011930 Object* name_symbol;
11931 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011933 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
11934 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011935 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011936 { MaybeObject* maybe_dictionary = string_dictionary->Add(
11937 String::cast(name_symbol),
11938 Smi::FromInt(i),
11939 PropertyDetails(NONE, NORMAL));
11940 if (!maybe_dictionary->ToObject(&dictionary)) {
11941 // Non-recoverable failure. Calling code must restart heap
11942 // initialization.
11943 return maybe_dictionary;
11944 }
11945 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011946 }
11947 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948}
11949
11950
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011951const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
11952 Heap* heap = name->GetHeap();
11953 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011954 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011955 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011956 int function_index = Smi::cast(smi_index)->value();
11957 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011958 }
11959 return NULL;
11960}
11961
11962
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011963const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000011964 return &(kIntrinsicFunctions[static_cast<int>(id)]);
11965}
11966
11967
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011968void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011969 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011971 if (failure->IsRetryAfterGC()) {
11972 // Try to do a garbage collection; ignore it if it fails. The C
11973 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011974 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011975 } else {
11976 // Handle last resort GC and make sure to allow future allocations
11977 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011978 isolate->counters()->gc_last_resort_from_js()->Increment();
11979 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000011980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011981}
11982
11983
11984} } // namespace v8::internal