blob: 3e07b998230373201759e445fe14693343f033d9 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000046#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000047#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000048#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000049#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000050#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000052#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000053#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000055#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000056#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000057#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000058#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000059#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060
kasperl@chromium.org71affb52009-05-26 05:44:31 +000061namespace v8 {
62namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000063
64
ager@chromium.org3e875802009-06-29 08:26:34 +000065#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000066 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067
68// Cast the given object to a value of the specified type and store
69// it in a variable with the given name. If the object is not of the
70// expected type call IllegalOperation and return.
71#define CONVERT_CHECKED(Type, name, obj) \
72 RUNTIME_ASSERT(obj->Is##Type()); \
73 Type* name = Type::cast(obj);
74
75#define CONVERT_ARG_CHECKED(Type, name, index) \
76 RUNTIME_ASSERT(args[index]->Is##Type()); \
77 Handle<Type> name = args.at<Type>(index);
78
kasper.lundbd3ec4e2008-07-09 11:06:54 +000079// Cast the given object to a boolean and store it in a variable with
80// the given name. If the object is not a boolean call IllegalOperation
81// and return.
82#define CONVERT_BOOLEAN_CHECKED(name, obj) \
83 RUNTIME_ASSERT(obj->IsBoolean()); \
84 bool name = (obj)->IsTrue();
85
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000086// Cast the given argument to a Smi and store its value in an int variable
87// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000088// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000089#define CONVERT_SMI_ARG_CHECKED(name, index) \
90 RUNTIME_ASSERT(args[index]->IsSmi()); \
91 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000093// Cast the given argument to a double and store it in a variable with
94// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000096#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
97 RUNTIME_ASSERT(args[index]->IsNumber()); \
98 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099
100// Call the specified converter on the object *comand store the result in
101// a variable of the specified type with the given name. If the
102// object is not a Number call IllegalOperation and return.
103#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
104 RUNTIME_ASSERT(obj->IsNumber()); \
105 type name = NumberTo##Type(obj);
106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
109 JSObject* boilerplate) {
110 StackLimitCheck check(isolate);
111 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000115 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000116 if (!maybe_result->ToObject(&result)) return maybe_result;
117 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000118 JSObject* copy = JSObject::cast(result);
119
120 // Deep copy local properties.
121 if (copy->HasFastProperties()) {
122 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000123 for (int i = 0; i < properties->length(); i++) {
124 Object* value = properties->get(i);
125 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000126 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000127 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000128 if (!maybe_result->ToObject(&result)) return maybe_result;
129 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000130 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000131 }
132 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000133 int nof = copy->map()->inobject_properties();
134 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000135 Object* value = copy->InObjectPropertyAt(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
144 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000145 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147 if (!maybe_result->ToObject(&result)) return maybe_result;
148 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000149 FixedArray* names = FixedArray::cast(result);
150 copy->GetLocalPropertyNames(names, 0);
151 for (int i = 0; i < names->length(); i++) {
152 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000153 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000154 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000155 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000156 // Only deep copy fields from the object literal expression.
157 // In particular, don't try to copy the length attribute of
158 // an array.
159 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160 Object* value =
161 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000162 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000164 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000165 if (!maybe_result->ToObject(&result)) return maybe_result;
166 }
167 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000168 // Creating object copy for literals. No strict mode needed.
169 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000170 if (!maybe_result->ToObject(&result)) return maybe_result;
171 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000172 }
173 }
174 }
175
176 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000177 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000178 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000179 switch (copy->GetElementsKind()) {
180 case JSObject::FAST_ELEMENTS: {
181 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 if (elements->map() == heap->fixed_cow_array_map()) {
183 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000184#ifdef DEBUG
185 for (int i = 0; i < elements->length(); i++) {
186 ASSERT(!elements->get(i)->IsJSObject());
187 }
188#endif
189 } else {
190 for (int i = 0; i < elements->length(); i++) {
191 Object* value = elements->get(i);
192 if (value->IsJSObject()) {
193 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
195 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000196 if (!maybe_result->ToObject(&result)) return maybe_result;
197 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000198 elements->set(i, result);
199 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000200 }
201 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000202 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000203 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 case JSObject::DICTIONARY_ELEMENTS: {
205 NumberDictionary* element_dictionary = copy->element_dictionary();
206 int capacity = element_dictionary->Capacity();
207 for (int i = 0; i < capacity; i++) {
208 Object* k = element_dictionary->KeyAt(i);
209 if (element_dictionary->IsKey(k)) {
210 Object* value = element_dictionary->ValueAt(i);
211 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000212 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
214 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000215 if (!maybe_result->ToObject(&result)) return maybe_result;
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 element_dictionary->ValueAtPut(i, result);
218 }
219 }
220 }
221 break;
222 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000223 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
224 UNIMPLEMENTED();
225 break;
226 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
227 case JSObject::EXTERNAL_BYTE_ELEMENTS:
228 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
229 case JSObject::EXTERNAL_SHORT_ELEMENTS:
230 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
231 case JSObject::EXTERNAL_INT_ELEMENTS:
232 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
233 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
234 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
235 case JSObject::FAST_DOUBLE_ELEMENTS:
236 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000237 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000238 }
239 return copy;
240}
241
242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000243RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000244 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000246}
247
248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000249RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000250 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000251 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252}
253
254
ager@chromium.org236ad962008-09-25 09:45:57 +0000255static Handle<Map> ComputeObjectLiteralMap(
256 Handle<Context> context,
257 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000258 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000260 int properties_length = constant_properties->length();
261 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000262 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000263 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000264 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 for (int p = 0; p != properties_length; p += 2) {
266 Object* key = constant_properties->get(p);
267 uint32_t element_index = 0;
268 if (key->IsSymbol()) {
269 number_of_symbol_keys++;
270 } else if (key->ToArrayIndex(&element_index)) {
271 // An index key does not require space in the property backing store.
272 number_of_properties--;
273 } else {
274 // Bail out as a non-symbol non-index key makes caching impossible.
275 // ASSERT to make sure that the if condition after the loop is false.
276 ASSERT(number_of_symbol_keys != number_of_properties);
277 break;
278 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 // If we only have symbols and array indices among keys then we can
281 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000282 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000283 if ((number_of_symbol_keys == number_of_properties) &&
284 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000285 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 Handle<FixedArray> keys =
287 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000288 if (number_of_symbol_keys > 0) {
289 int index = 0;
290 for (int p = 0; p < properties_length; p += 2) {
291 Object* key = constant_properties->get(p);
292 if (key->IsSymbol()) {
293 keys->set(index++, key);
294 }
295 }
296 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000299 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 }
301 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000302 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000304 Handle<Map>(context->object_function()->initial_map()),
305 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000306}
307
308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000309static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000311 Handle<FixedArray> literals,
312 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314
315static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000316 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000317 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000318 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000319 bool should_have_fast_elements,
320 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000321 // Get the global context from the literals array. This is the
322 // context in which the function was created and we use the object
323 // function from this context to create the object literal. We do
324 // not use the object function from the current global context
325 // because this might be the object function from another context
326 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000327 Handle<Context> context =
328 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 // In case we have function literals, we want the object to be in
331 // slow properties mode for now. We don't go in the map cache because
332 // maps with constant functions can't be shared if the functions are
333 // not the same (which is the common case).
334 bool is_result_from_cache = false;
335 Handle<Map> map = has_function_literal
336 ? Handle<Map>(context->object_function()->initial_map())
337 : ComputeObjectLiteralMap(context,
338 constant_properties,
339 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000342
343 // Normalize the elements of the boilerplate to save space if needed.
344 if (!should_have_fast_elements) NormalizeElements(boilerplate);
345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 // Add the constant properties to the boilerplate.
347 int length = constant_properties->length();
348 bool should_transform =
349 !is_result_from_cache && boilerplate->HasFastProperties();
350 if (should_transform || has_function_literal) {
351 // Normalize the properties of object to avoid n^2 behavior
352 // when extending the object multiple properties. Indicate the number of
353 // properties to be added.
354 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
355 }
356
357 for (int index = 0; index < length; index +=2) {
358 Handle<Object> key(constant_properties->get(index+0), isolate);
359 Handle<Object> value(constant_properties->get(index+1), isolate);
360 if (value->IsFixedArray()) {
361 // The value contains the constant_properties of a
362 // simple object or array literal.
363 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
364 value = CreateLiteralBoilerplate(isolate, literals, array);
365 if (value.is_null()) return value;
366 }
367 Handle<Object> result;
368 uint32_t element_index = 0;
369 if (key->IsSymbol()) {
370 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
371 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000372 result = SetOwnElement(boilerplate,
373 element_index,
374 value,
375 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000376 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 Handle<String> name(String::cast(*key));
378 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000379 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
380 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 } else if (key->ToArrayIndex(&element_index)) {
383 // Array index (uint32).
384 result = SetOwnElement(boilerplate,
385 element_index,
386 value,
387 kNonStrictMode);
388 } else {
389 // Non-uint32 number.
390 ASSERT(key->IsNumber());
391 double num = key->Number();
392 char arr[100];
393 Vector<char> buffer(arr, ARRAY_SIZE(arr));
394 const char* str = DoubleToCString(num, buffer);
395 Handle<String> name =
396 isolate->factory()->NewStringFromAscii(CStrVector(str));
397 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
398 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 // If setting the property on the boilerplate throws an
401 // exception, the exception is converted to an empty handle in
402 // the handle based operations. In that case, we need to
403 // convert back to an exception.
404 if (result.is_null()) return result;
405 }
406
407 // Transform to fast properties if necessary. For object literals with
408 // containing function literals we defer this operation until after all
409 // computed properties have been assigned so that we can generate
410 // constant function properties.
411 if (should_transform && !has_function_literal) {
412 TransformToFastProperties(boilerplate,
413 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
415
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000416 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000417}
418
419
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000421 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000422 Handle<FixedArray> literals,
423 Handle<FixedArray> elements) {
424 // Create the JSArray.
425 Handle<JSFunction> constructor(
426 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 const bool is_cow =
430 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000431 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000433
434 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000435 if (is_cow) {
436#ifdef DEBUG
437 // Copy-on-write arrays must be shallow (and simple).
438 for (int i = 0; i < content->length(); i++) {
439 ASSERT(!content->get(i)->IsFixedArray());
440 }
441#endif
442 } else {
443 for (int i = 0; i < content->length(); i++) {
444 if (content->get(i)->IsFixedArray()) {
445 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000446 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000447 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
448 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000450 if (result.is_null()) return result;
451 content->set(i, *result);
452 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 }
454 }
455
456 // Set the elements.
457 Handle<JSArray>::cast(object)->SetContent(*content);
458 return object;
459}
460
461
462static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000464 Handle<FixedArray> literals,
465 Handle<FixedArray> array) {
466 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000467 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000469 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 return CreateObjectLiteralBoilerplate(isolate,
471 literals,
472 elements,
473 true,
474 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000475 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000476 return CreateObjectLiteralBoilerplate(isolate,
477 literals,
478 elements,
479 false,
480 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000481 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000482 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000483 default:
484 UNREACHABLE();
485 return Handle<Object>::null();
486 }
487}
488
489
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000490RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000491 // Takes a FixedArray of elements containing the literal elements of
492 // the array literal and produces JSArray with those elements.
493 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000494 // which contains the context from which to get the Array function
495 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000496 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000497 ASSERT(args.length() == 3);
498 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000499 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000500 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 Handle<Object> object =
503 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000504 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000506 // Update the functions literal and return the boilerplate.
507 literals->set(literals_index, *object);
508 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509}
510
511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000512RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000513 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000515 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000516 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000518 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
520 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000521
522 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000523 Handle<Object> boilerplate(literals->get(literals_index), isolate);
524 if (*boilerplate == isolate->heap()->undefined_value()) {
525 boilerplate = CreateObjectLiteralBoilerplate(isolate,
526 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 should_have_fast_elements,
529 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 if (boilerplate.is_null()) return Failure::Exception();
531 // Update the functions literal and return the boilerplate.
532 literals->set(literals_index, *boilerplate);
533 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000535}
536
537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000538RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000541 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000542 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000544 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
546 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547
548 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 Handle<Object> boilerplate(literals->get(literals_index), isolate);
550 if (*boilerplate == isolate->heap()->undefined_value()) {
551 boilerplate = CreateObjectLiteralBoilerplate(isolate,
552 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000553 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 should_have_fast_elements,
555 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556 if (boilerplate.is_null()) return Failure::Exception();
557 // Update the functions literal and return the boilerplate.
558 literals->set(literals_index, *boilerplate);
559 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561}
562
563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000564RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000566 ASSERT(args.length() == 3);
567 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000568 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
570
571 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 Handle<Object> boilerplate(literals->get(literals_index), isolate);
573 if (*boilerplate == isolate->heap()->undefined_value()) {
574 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 if (boilerplate.is_null()) return Failure::Exception();
576 // Update the functions literal and return the boilerplate.
577 literals->set(literals_index, *boilerplate);
578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580}
581
582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000583RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000585 ASSERT(args.length() == 3);
586 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000587 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
589
590 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 Handle<Object> boilerplate(literals->get(literals_index), isolate);
592 if (*boilerplate == isolate->heap()->undefined_value()) {
593 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594 if (boilerplate.is_null()) return Failure::Exception();
595 // Update the functions literal and return the boilerplate.
596 literals->set(literals_index, *boilerplate);
597 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000598 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000600 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000603}
604
605
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000606RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
607 ASSERT(args.length() == 2);
608 Object* handler = args[0];
609 Object* prototype = args[1];
610 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000611 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000612 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
613}
614
615
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000616RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
617 ASSERT(args.length() == 1);
618 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000619 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000620}
621
622
623RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
624 ASSERT(args.length() == 1);
625 CONVERT_CHECKED(JSProxy, proxy, args[0]);
626 return proxy->handler();
627}
628
629
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000630RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
631 ASSERT(args.length() == 1);
632 CONVERT_CHECKED(JSProxy, proxy, args[0]);
633 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000634 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000635}
636
637
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000638RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
639 HandleScope scope(isolate);
640 ASSERT(args.length() == 1);
641 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
642 ASSERT(weakmap->map()->inobject_properties() == 0);
643 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
644 weakmap->set_table(*table);
645 weakmap->set_next(Smi::FromInt(0));
646 return *weakmap;
647}
648
649
650RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
651 NoHandleAllocation ha;
652 ASSERT(args.length() == 2);
653 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
654 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
655 // because they cannot be cast to JSObject to get an identity hash code.
656 CONVERT_ARG_CHECKED(JSObject, key, 1);
657 return weakmap->table()->Lookup(*key);
658}
659
660
661RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
662 HandleScope scope(isolate);
663 ASSERT(args.length() == 3);
664 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
665 // TODO(mstarzinger): See Runtime_WeakMapGet above.
666 CONVERT_ARG_CHECKED(JSObject, key, 1);
667 Handle<Object> value(args[2]);
668 Handle<ObjectHashTable> table(weakmap->table());
669 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
670 weakmap->set_table(*new_table);
671 return *value;
672}
673
674
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000675RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676 NoHandleAllocation ha;
677 ASSERT(args.length() == 1);
678 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000679 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 return JSObject::cast(obj)->class_name();
681}
682
ager@chromium.org7c537e22008-10-16 08:43:32 +0000683
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000684RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
685 NoHandleAllocation ha;
686 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000687 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
688 Object* obj = input_obj;
689 // We don't expect access checks to be needed on JSProxy objects.
690 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000691 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000692 if (obj->IsAccessCheckNeeded() &&
693 !isolate->MayNamedAccess(JSObject::cast(obj),
694 isolate->heap()->Proto_symbol(),
695 v8::ACCESS_GET)) {
696 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
697 return isolate->heap()->undefined_value();
698 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000699 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000700 } while (obj->IsJSObject() &&
701 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000702 return obj;
703}
704
705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000706RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707 NoHandleAllocation ha;
708 ASSERT(args.length() == 2);
709 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
710 Object* O = args[0];
711 Object* V = args[1];
712 while (true) {
713 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000714 if (prototype->IsNull()) return isolate->heap()->false_value();
715 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000716 V = prototype;
717 }
718}
719
720
ager@chromium.org9085a012009-05-11 19:22:57 +0000721// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000723 NoHandleAllocation ha;
724 ASSERT(args.length() == 2);
725 CONVERT_CHECKED(JSObject, jsobject, args[0]);
726 CONVERT_CHECKED(JSObject, proto, args[1]);
727
728 // Sanity checks. The old prototype (that we are replacing) could
729 // theoretically be null, but if it is not null then check that we
730 // didn't already install a hidden prototype here.
731 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
732 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
733 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
734
735 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000736 Object* map_or_failure;
737 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
738 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
739 return maybe_map_or_failure;
740 }
741 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000742 Map* new_proto_map = Map::cast(map_or_failure);
743
lrn@chromium.org303ada72010-10-27 09:33:13 +0000744 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
745 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
746 return maybe_map_or_failure;
747 }
748 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000749 Map* new_map = Map::cast(map_or_failure);
750
751 // Set proto's prototype to be the old prototype of the object.
752 new_proto_map->set_prototype(jsobject->GetPrototype());
753 proto->set_map(new_proto_map);
754 new_proto_map->set_is_hidden_prototype();
755
756 // Set the object's prototype to proto.
757 new_map->set_prototype(proto);
758 jsobject->set_map(new_map);
759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000760 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000761}
762
763
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000764RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000765 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000766 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000767 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000768 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769}
770
771
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000772// Recursively traverses hidden prototypes if property is not found
773static void GetOwnPropertyImplementation(JSObject* obj,
774 String* name,
775 LookupResult* result) {
776 obj->LocalLookupRealNamedProperty(name, result);
777
778 if (!result->IsProperty()) {
779 Object* proto = obj->GetPrototype();
780 if (proto->IsJSObject() &&
781 JSObject::cast(proto)->map()->is_hidden_prototype())
782 GetOwnPropertyImplementation(JSObject::cast(proto),
783 name, result);
784 }
785}
786
787
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000788static bool CheckAccessException(LookupResult* result,
789 v8::AccessType access_type) {
790 if (result->type() == CALLBACKS) {
791 Object* callback = result->GetCallbackObject();
792 if (callback->IsAccessorInfo()) {
793 AccessorInfo* info = AccessorInfo::cast(callback);
794 bool can_access =
795 (access_type == v8::ACCESS_HAS &&
796 (info->all_can_read() || info->all_can_write())) ||
797 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
798 (access_type == v8::ACCESS_SET && info->all_can_write());
799 return can_access;
800 }
801 }
802
803 return false;
804}
805
806
807static bool CheckAccess(JSObject* obj,
808 String* name,
809 LookupResult* result,
810 v8::AccessType access_type) {
811 ASSERT(result->IsProperty());
812
813 JSObject* holder = result->holder();
814 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000815 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000816 while (true) {
817 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000819 // Access check callback denied the access, but some properties
820 // can have a special permissions which override callbacks descision
821 // (currently see v8::AccessControl).
822 break;
823 }
824
825 if (current == holder) {
826 return true;
827 }
828
829 current = JSObject::cast(current->GetPrototype());
830 }
831
832 // API callbacks can have per callback access exceptions.
833 switch (result->type()) {
834 case CALLBACKS: {
835 if (CheckAccessException(result, access_type)) {
836 return true;
837 }
838 break;
839 }
840 case INTERCEPTOR: {
841 // If the object has an interceptor, try real named properties.
842 // Overwrite the result to fetch the correct property later.
843 holder->LookupRealNamedProperty(name, result);
844 if (result->IsProperty()) {
845 if (CheckAccessException(result, access_type)) {
846 return true;
847 }
848 }
849 break;
850 }
851 default:
852 break;
853 }
854
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000855 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000856 return false;
857}
858
859
860// TODO(1095): we should traverse hidden prototype hierachy as well.
861static bool CheckElementAccess(JSObject* obj,
862 uint32_t index,
863 v8::AccessType access_type) {
864 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000866 return false;
867 }
868
869 return true;
870}
871
872
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000873// Enumerator used as indices into the array returned from GetOwnProperty
874enum PropertyDescriptorIndices {
875 IS_ACCESSOR_INDEX,
876 VALUE_INDEX,
877 GETTER_INDEX,
878 SETTER_INDEX,
879 WRITABLE_INDEX,
880 ENUMERABLE_INDEX,
881 CONFIGURABLE_INDEX,
882 DESCRIPTOR_SIZE
883};
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885// Returns an array with the property description:
886// if args[1] is not a property on args[0]
887// returns undefined
888// if args[1] is a data property on args[0]
889// [false, value, Writeable, Enumerable, Configurable]
890// if args[1] is an accessor on args[0]
891// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000892RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000893 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 Heap* heap = isolate->heap();
895 HandleScope scope(isolate);
896 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
897 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000898 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000899 CONVERT_ARG_CHECKED(JSObject, obj, 0);
900 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000901
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000902 // This could be an element.
903 uint32_t index;
904 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000905 switch (obj->HasLocalElement(index)) {
906 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000908
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000909 case JSObject::STRING_CHARACTER_ELEMENT: {
910 // Special handling of string objects according to ECMAScript 5
911 // 15.5.5.2. Note that this might be a string object with elements
912 // other than the actual string value. This is covered by the
913 // subsequent cases.
914 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
915 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000916 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000919 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 elms->set(WRITABLE_INDEX, heap->false_value());
921 elms->set(ENUMERABLE_INDEX, heap->false_value());
922 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000923 return *desc;
924 }
925
926 case JSObject::INTERCEPTED_ELEMENT:
927 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000929 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000931 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 elms->set(WRITABLE_INDEX, heap->true_value());
933 elms->set(ENUMERABLE_INDEX, heap->true_value());
934 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000935 return *desc;
936 }
937
938 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000939 Handle<JSObject> holder = obj;
940 if (obj->IsJSGlobalProxy()) {
941 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943 ASSERT(proto->IsJSGlobalObject());
944 holder = Handle<JSObject>(JSObject::cast(proto));
945 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000946 FixedArray* elements = FixedArray::cast(holder->elements());
947 NumberDictionary* dictionary = NULL;
948 if (elements->map() == heap->non_strict_arguments_elements_map()) {
949 dictionary = NumberDictionary::cast(elements->get(1));
950 } else {
951 dictionary = NumberDictionary::cast(elements);
952 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000953 int entry = dictionary->FindEntry(index);
954 ASSERT(entry != NumberDictionary::kNotFound);
955 PropertyDetails details = dictionary->DetailsAt(entry);
956 switch (details.type()) {
957 case CALLBACKS: {
958 // This is an accessor property with getter and/or setter.
959 FixedArray* callbacks =
960 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000961 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000962 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
963 elms->set(GETTER_INDEX, callbacks->get(0));
964 }
965 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
966 elms->set(SETTER_INDEX, callbacks->get(1));
967 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000968 break;
969 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000970 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000971 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000972 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000973 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000974 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000975 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000976 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000977 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000978 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000979 default:
980 UNREACHABLE();
981 break;
982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
984 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000985 return *desc;
986 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000987 }
988 }
989
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000990 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000991 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000992
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000993 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000995 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000996
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000997 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000999 }
1000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1002 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001003
1004 bool is_js_accessor = (result.type() == CALLBACKS) &&
1005 (result.GetCallbackObject()->IsFixedArray());
1006
1007 if (is_js_accessor) {
1008 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001010
1011 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1012 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1013 elms->set(GETTER_INDEX, structure->get(0));
1014 }
1015 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1016 elms->set(SETTER_INDEX, structure->get(1));
1017 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001018 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001019 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1020 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001021
1022 PropertyAttributes attrs;
1023 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001024 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001025 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1026 if (!maybe_value->ToObject(&value)) return maybe_value;
1027 }
1028 elms->set(VALUE_INDEX, value);
1029 }
1030
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001031 return *desc;
1032}
1033
1034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001035RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001036 ASSERT(args.length() == 1);
1037 CONVERT_CHECKED(JSObject, obj, args[0]);
1038 return obj->PreventExtensions();
1039}
1040
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001041
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001042RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001043 ASSERT(args.length() == 1);
1044 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001045 if (obj->IsJSGlobalProxy()) {
1046 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001048 ASSERT(proto->IsJSGlobalObject());
1049 obj = JSObject::cast(proto);
1050 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001051 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001052}
1053
1054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001055RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001057 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001058 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1059 CONVERT_ARG_CHECKED(String, pattern, 1);
1060 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001061 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1062 if (result.is_null()) return Failure::Exception();
1063 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064}
1065
1066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001067RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001068 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001070 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001072}
1073
1074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001075RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076 ASSERT(args.length() == 1);
1077 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001078 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001079 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080}
1081
1082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001083RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084 ASSERT(args.length() == 2);
1085 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001087 int index = field->value();
1088 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1089 InstanceType type = templ->map()->instance_type();
1090 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1091 type == OBJECT_TEMPLATE_INFO_TYPE);
1092 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001093 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001094 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1095 } else {
1096 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1097 }
1098 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099}
1100
1101
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001102RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001103 ASSERT(args.length() == 1);
1104 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001105 Map* old_map = object->map();
1106 bool needs_access_checks = old_map->is_access_check_needed();
1107 if (needs_access_checks) {
1108 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001109 Object* new_map;
1110 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1111 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1112 }
ager@chromium.org32912102009-01-16 10:38:43 +00001113
1114 Map::cast(new_map)->set_is_access_check_needed(false);
1115 object->set_map(Map::cast(new_map));
1116 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001117 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001118}
1119
1120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001121RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001122 ASSERT(args.length() == 1);
1123 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001124 Map* old_map = object->map();
1125 if (!old_map->is_access_check_needed()) {
1126 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001127 Object* new_map;
1128 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1129 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1130 }
ager@chromium.org32912102009-01-16 10:38:43 +00001131
1132 Map::cast(new_map)->set_is_access_check_needed(true);
1133 object->set_map(Map::cast(new_map));
1134 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001135 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001136}
1137
1138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001139static Failure* ThrowRedeclarationError(Isolate* isolate,
1140 const char* type,
1141 Handle<String> name) {
1142 HandleScope scope(isolate);
1143 Handle<Object> type_handle =
1144 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 Handle<Object> args[2] = { type_handle, name };
1146 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1148 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149}
1150
1151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001152RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001153 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001154 HandleScope scope(isolate);
1155 Handle<GlobalObject> global = Handle<GlobalObject>(
1156 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157
ager@chromium.org3811b432009-10-28 14:53:37 +00001158 Handle<Context> context = args.at<Context>(0);
1159 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001160 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162 // Traverse the name/value pairs and set the properties.
1163 int length = pairs->length();
1164 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001167 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168
1169 // We have to declare a global const property. To capture we only
1170 // assign to it when evaluating the assignment for "const x =
1171 // <expr>" the initial value is the hole.
1172 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001173 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001174 if (value->IsUndefined() || is_const_property) {
1175 // Lookup the property in the global object, and don't set the
1176 // value of the variable if the property is already there.
1177 LookupResult lookup;
1178 global->Lookup(*name, &lookup);
1179 if (lookup.IsProperty()) {
1180 // Determine if the property is local by comparing the holder
1181 // against the global object. The information will be used to
1182 // avoid throwing re-declaration errors when declaring
1183 // variables or constants that exist in the prototype chain.
1184 bool is_local = (*global == lookup.holder());
1185 // Get the property attributes and determine if the property is
1186 // read-only.
1187 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1188 bool is_read_only = (attributes & READ_ONLY) != 0;
1189 if (lookup.type() == INTERCEPTOR) {
1190 // If the interceptor says the property is there, we
1191 // just return undefined without overwriting the property.
1192 // Otherwise, we continue to setting the property.
1193 if (attributes != ABSENT) {
1194 // Check if the existing property conflicts with regards to const.
1195 if (is_local && (is_read_only || is_const_property)) {
1196 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001197 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 };
1199 // The property already exists without conflicting: Go to
1200 // the next declaration.
1201 continue;
1202 }
1203 // Fall-through and introduce the absent property by using
1204 // SetProperty.
1205 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001206 // For const properties, we treat a callback with this name
1207 // even in the prototype as a conflicting declaration.
1208 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001210 }
1211 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212 if (is_local && (is_read_only || is_const_property)) {
1213 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001214 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 }
1216 // The property already exists without conflicting: Go to
1217 // the next declaration.
1218 continue;
1219 }
1220 }
1221 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001222 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001224 Handle<SharedFunctionInfo> shared =
1225 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001227 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1228 context,
1229 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 value = function;
1231 }
1232
1233 LookupResult lookup;
1234 global->LocalLookup(*name, &lookup);
1235
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001236 // There's a local property that we need to overwrite because
1237 // we're either declaring a function or there's an interceptor
1238 // that claims the property is absent.
1239 //
1240 // Check for conflicting re-declarations. We cannot have
1241 // conflicting types in case of intercepted properties because
1242 // they are absent.
1243 if (lookup.IsProperty() &&
1244 (lookup.type() != INTERCEPTOR) &&
1245 (lookup.IsReadOnly() || is_const_property)) {
1246 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001248 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001250 // Compute the property attributes. According to ECMA-262, section
1251 // 13, page 71, the property must be read-only and
1252 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1253 // property as read-only, so we don't either.
1254 int attr = NONE;
1255 if ((flags & kDeclareGlobalsEvalFlag) == 0) {
1256 attr |= DONT_DELETE;
1257 }
1258 bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
1259 if (is_const_property || (is_native && is_function_declaration)) {
1260 attr |= READ_ONLY;
1261 }
1262
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001263 // Safari does not allow the invocation of callback setters for
1264 // function declarations. To mimic this behavior, we do not allow
1265 // the invocation of setters for function values. This makes a
1266 // difference for global functions with the same names as event
1267 // handlers such as "function onload() {}". Firefox does call the
1268 // onload setter in those case and Safari does not. We follow
1269 // Safari for compatibility.
1270 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001271 // Do not change DONT_DELETE to false from true.
1272 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001274 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001275 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1276
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 RETURN_IF_EMPTY_HANDLE(isolate,
1278 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001279 name,
1280 value,
1281 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001283 StrictModeFlag strict_mode =
1284 ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
1285 : kNonStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001286 RETURN_IF_EMPTY_HANDLE(isolate,
1287 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001288 name,
1289 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001290 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001291 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 }
1293 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001295 ASSERT(!isolate->has_pending_exception());
1296 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297}
1298
1299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001300RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001302 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001303
ager@chromium.org7c537e22008-10-16 08:43:32 +00001304 CONVERT_ARG_CHECKED(Context, context, 0);
1305 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001306 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001307 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001308 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001310 // Declarations are always done in a function or global context.
1311 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
1313 int index;
1314 PropertyAttributes attributes;
1315 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001316 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001317 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001318 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 if (attributes != ABSENT) {
1321 // The name was declared before; check for conflicting
1322 // re-declarations: This is similar to the code in parser.cc in
1323 // the AstBuildingParser::Declare function.
1324 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1325 // Functions are not read-only.
1326 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1327 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001328 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 }
1330
1331 // Initialize it if necessary.
1332 if (*initial_value != NULL) {
1333 if (index >= 0) {
1334 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001335 // the function context or the arguments object.
1336 if (holder->IsContext()) {
1337 ASSERT(holder.is_identical_to(context));
1338 if (((attributes & READ_ONLY) == 0) ||
1339 context->get(index)->IsTheHole()) {
1340 context->set(index, *initial_value);
1341 }
1342 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001343 // The holder is an arguments object.
1344 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001345 Handle<Object> result = SetElement(arguments, index, initial_value,
1346 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001347 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 }
1349 } else {
1350 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001351 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001352 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001354 SetProperty(context_ext, name, initial_value,
1355 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001360 // The property is not in the function context. It needs to be
1361 // "declared" in the function context's extension context, or in the
1362 // global context.
1363 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001364 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001366 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001367 } else {
1368 // The function context's extension context does not exists - allocate
1369 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 context_ext = isolate->factory()->NewJSObject(
1371 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001372 // And store it in the extension slot.
1373 context->set_extension(*context_ext);
1374 }
1375 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 // Declare the property by setting it to the initial value if provided,
1378 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1379 // constant declarations).
1380 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001382 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001383 // Declaring a const context slot is a conflicting declaration if
1384 // there is a callback with that name in a prototype. It is
1385 // allowed to introduce const variables in
1386 // JSContextExtensionObjects. They are treated specially in
1387 // SetProperty and no setters are invoked for those since they are
1388 // not real JSObjects.
1389 if (initial_value->IsTheHole() &&
1390 !context_ext->IsJSContextExtensionObject()) {
1391 LookupResult lookup;
1392 context_ext->Lookup(*name, &lookup);
1393 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001395 }
1396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001397 RETURN_IF_EMPTY_HANDLE(isolate,
1398 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001399 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001400 }
1401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403}
1404
1405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001406RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001408 // args[0] == name
1409 // args[1] == strict_mode
1410 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411
1412 // Determine if we need to assign to the variable if it already
1413 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1415 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416
1417 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001418 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001419 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001420 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001421 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422
1423 // According to ECMA-262, section 12.2, page 62, the property must
1424 // not be deletable.
1425 PropertyAttributes attributes = DONT_DELETE;
1426
1427 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001428 // there, there is a property with this name in the prototype chain.
1429 // We follow Safari and Firefox behavior and only set the property
1430 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001431 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001432 // Note that objects can have hidden prototypes, so we need to traverse
1433 // the whole chain of hidden prototypes to do a 'local' lookup.
1434 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001436 while (true) {
1437 real_holder->LocalLookup(*name, &lookup);
1438 if (lookup.IsProperty()) {
1439 // Determine if this is a redeclaration of something read-only.
1440 if (lookup.IsReadOnly()) {
1441 // If we found readonly property on one of hidden prototypes,
1442 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001443 if (real_holder != isolate->context()->global()) break;
1444 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001445 }
1446
1447 // Determine if this is a redeclaration of an intercepted read-only
1448 // property and figure out if the property exists at all.
1449 bool found = true;
1450 PropertyType type = lookup.type();
1451 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001452 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001453 Handle<JSObject> holder(real_holder);
1454 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1455 real_holder = *holder;
1456 if (intercepted == ABSENT) {
1457 // The interceptor claims the property isn't there. We need to
1458 // make sure to introduce it.
1459 found = false;
1460 } else if ((intercepted & READ_ONLY) != 0) {
1461 // The property is present, but read-only. Since we're trying to
1462 // overwrite it with a variable declaration we must throw a
1463 // re-declaration error. However if we found readonly property
1464 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001465 if (real_holder != isolate->context()->global()) break;
1466 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001467 }
1468 }
1469
1470 if (found && !assign) {
1471 // The global property is there and we're not assigning any value
1472 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001473 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001474 }
1475
1476 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 return real_holder->SetProperty(
1479 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001480 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001481
1482 Object* proto = real_holder->GetPrototype();
1483 if (!proto->IsJSObject())
1484 break;
1485
1486 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1487 break;
1488
1489 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 }
1491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001492 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001493 if (assign) {
1494 return global->SetProperty(*name, args[2], attributes, strict_mode);
1495 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001496 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497}
1498
1499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001500RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 // All constants are declared with an initial value. The name
1502 // of the constant is the first argument and the initial value
1503 // is the second.
1504 RUNTIME_ASSERT(args.length() == 2);
1505 CONVERT_ARG_CHECKED(String, name, 0);
1506 Handle<Object> value = args.at<Object>(1);
1507
1508 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510
1511 // According to ECMA-262, section 12.2, page 62, the property must
1512 // not be deletable. Since it's a const, it must be READ_ONLY too.
1513 PropertyAttributes attributes =
1514 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1515
1516 // Lookup the property locally in the global object. If it isn't
1517 // there, we add the property and take special precautions to always
1518 // add it as a local property even in case of callbacks in the
1519 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001520 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 LookupResult lookup;
1522 global->LocalLookup(*name, &lookup);
1523 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001524 return global->SetLocalPropertyIgnoreAttributes(*name,
1525 *value,
1526 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 }
1528
1529 // Determine if this is a redeclaration of something not
1530 // read-only. In case the result is hidden behind an interceptor we
1531 // need to ask it for the property attributes.
1532 if (!lookup.IsReadOnly()) {
1533 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001534 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 }
1536
1537 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1538
1539 // Throw re-declaration error if the intercepted property is present
1540 // but not read-only.
1541 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001542 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 }
1544
1545 // Restore global object from context (in case of GC) and continue
1546 // with setting the value because the property is either absent or
1547 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001548 HandleScope handle_scope(isolate);
1549 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001551 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552 // property through an interceptor and only do it if it's
1553 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001554 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001555 RETURN_IF_EMPTY_HANDLE(isolate,
1556 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001557 name,
1558 value,
1559 attributes,
1560 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 return *value;
1562 }
1563
1564 // Set the value, but only we're assigning the initial value to a
1565 // constant. For now, we determine this by checking if the
1566 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001567 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 PropertyType type = lookup.type();
1569 if (type == FIELD) {
1570 FixedArray* properties = global->properties();
1571 int index = lookup.GetFieldIndex();
1572 if (properties->get(index)->IsTheHole()) {
1573 properties->set(index, *value);
1574 }
1575 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001576 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1577 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 }
1579 } else {
1580 // Ignore re-initialization of constants that have already been
1581 // assigned a function value.
1582 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1583 }
1584
1585 // Use the set value as the result of the operation.
1586 return *value;
1587}
1588
1589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001590RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592 ASSERT(args.length() == 3);
1593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001594 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001595 ASSERT(!value->IsTheHole());
1596 CONVERT_ARG_CHECKED(Context, context, 1);
1597 Handle<String> name(String::cast(args[2]));
1598
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001599 // Initializations are always done in a function or global context.
1600 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
1602 int index;
1603 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001604 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001605 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001606 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001607 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 // In most situations, the property introduced by the const
1610 // declaration should be present in the context extension object.
1611 // However, because declaration and initialization are separate, the
1612 // property might have been deleted (if it was introduced by eval)
1613 // before we reach the initialization point.
1614 //
1615 // Example:
1616 //
1617 // function f() { eval("delete x; const x;"); }
1618 //
1619 // In that case, the initialization behaves like a normal assignment
1620 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001622 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001623 // Property was found in a context. Perform the assignment if we
1624 // found some non-constant or an uninitialized constant.
1625 Handle<Context> context = Handle<Context>::cast(holder);
1626 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1627 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001628 }
1629 } else {
1630 // The holder is an arguments object.
1631 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001632 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001633 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001634 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001635 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636 }
1637 return *value;
1638 }
1639
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001640 // The property could not be found, we introduce it in the global
1641 // context.
1642 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001643 Handle<JSObject> global = Handle<JSObject>(
1644 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001645 // Strict mode not needed (const disallowed in strict mode).
1646 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001647 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001648 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001649 return *value;
1650 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001652 // The property was present in a context extension object.
1653 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001655 if (*context_ext == context->extension()) {
1656 // This is the property that was introduced by the const
1657 // declaration. Set it if it hasn't been set before. NOTE: We
1658 // cannot use GetProperty() to get the current value as it
1659 // 'unholes' the value.
1660 LookupResult lookup;
1661 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1662 ASSERT(lookup.IsProperty()); // the property was declared
1663 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1664
1665 PropertyType type = lookup.type();
1666 if (type == FIELD) {
1667 FixedArray* properties = context_ext->properties();
1668 int index = lookup.GetFieldIndex();
1669 if (properties->get(index)->IsTheHole()) {
1670 properties->set(index, *value);
1671 }
1672 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001673 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1674 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001675 }
1676 } else {
1677 // We should not reach here. Any real, named property should be
1678 // either a field or a dictionary slot.
1679 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 }
1681 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682 // The property was found in a different context extension object.
1683 // Set it if it is not a read-only property.
1684 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001685 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001686 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001688 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001690 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 return *value;
1693}
1694
1695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001696RUNTIME_FUNCTION(MaybeObject*,
1697 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001699 ASSERT(args.length() == 2);
1700 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001701 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001702 if (object->HasFastProperties()) {
1703 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1704 }
1705 return *object;
1706}
1707
1708
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001709RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001710 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001711 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001712 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1713 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001716 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001717 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001718 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001719 RUNTIME_ASSERT(index >= 0);
1720 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001722 Handle<Object> result = RegExpImpl::Exec(regexp,
1723 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001726 if (result.is_null()) return Failure::Exception();
1727 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001728}
1729
1730
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001731RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001732 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001733 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001734 if (elements_count < 0 ||
1735 elements_count > FixedArray::kMaxLength ||
1736 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001737 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001738 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001739 Object* new_object;
1740 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001742 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1743 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001745 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1746 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1748 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001749 {
1750 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001752 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001753 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 }
1755 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 array->set_elements(elements);
1758 array->set_length(Smi::FromInt(elements_count));
1759 // Write in-object properties after the length of the array.
1760 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1761 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1762 return array;
1763}
1764
1765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001766RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767 AssertNoAllocation no_alloc;
1768 ASSERT(args.length() == 5);
1769 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1770 CONVERT_CHECKED(String, source, args[1]);
1771
1772 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001774
1775 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001776 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777
1778 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780
1781 Map* map = regexp->map();
1782 Object* constructor = map->constructor();
1783 if (constructor->IsJSFunction() &&
1784 JSFunction::cast(constructor)->initial_map() == map) {
1785 // If we still have the original map, set in-object properties directly.
1786 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1787 // TODO(lrn): Consider skipping write barrier on booleans as well.
1788 // Both true and false should be in oldspace at all times.
1789 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1790 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1791 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1792 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1793 Smi::FromInt(0),
1794 SKIP_WRITE_BARRIER);
1795 return regexp;
1796 }
1797
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001799 PropertyAttributes final =
1800 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1801 PropertyAttributes writable =
1802 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001804 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001806 source,
1807 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001808 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001810 global,
1811 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812 ASSERT(!result->IsFailure());
1813 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001814 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001815 ignoreCase,
1816 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001817 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001818 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001819 multiline,
1820 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821 ASSERT(!result->IsFailure());
1822 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001823 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001824 Smi::FromInt(0),
1825 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001826 ASSERT(!result->IsFailure());
1827 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001828 return regexp;
1829}
1830
1831
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001832RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001834 ASSERT(args.length() == 1);
1835 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1836 // This is necessary to enable fast checks for absence of elements
1837 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001838 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001839 return Smi::FromInt(0);
1840}
1841
1842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1844 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001845 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001846 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001847 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1848 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1849 Handle<JSFunction> optimized =
1850 isolate->factory()->NewFunction(key,
1851 JS_OBJECT_TYPE,
1852 JSObject::kHeaderSize,
1853 code,
1854 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001855 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001856 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001857 return optimized;
1858}
1859
1860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001861RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001863 ASSERT(args.length() == 1);
1864 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1865
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001866 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1867 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1868 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1869 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1870 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1871 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1872 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001873
1874 return *holder;
1875}
1876
1877
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001878RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1879 NoHandleAllocation handle_free;
1880 ASSERT(args.length() == 1);
1881 CONVERT_CHECKED(JSFunction, function, args[0]);
1882 SharedFunctionInfo* shared = function->shared();
1883 if (shared->native() || shared->strict_mode()) {
1884 return isolate->heap()->undefined_value();
1885 }
1886 // Returns undefined for strict or native functions, or
1887 // the associated global receiver for "normal" functions.
1888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001890 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001891 return global_context->global()->global_receiver();
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001897 ASSERT(args.length() == 4);
1898 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001899 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001900 Handle<String> pattern = args.at<String>(2);
1901 Handle<String> flags = args.at<String>(3);
1902
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001903 // Get the RegExp function from the context in the literals array.
1904 // This is the RegExp function from the context in which the
1905 // function was created. We do not use the RegExp function from the
1906 // current global context because this might be the RegExp function
1907 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001908 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001909 Handle<JSFunction>(
1910 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 // Compute the regular expression literal.
1912 bool has_pending_exception;
1913 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001914 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1915 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001916 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001917 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 return Failure::Exception();
1919 }
1920 literals->set(index, *regexp);
1921 return *regexp;
1922}
1923
1924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001925RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 NoHandleAllocation ha;
1927 ASSERT(args.length() == 1);
1928
1929 CONVERT_CHECKED(JSFunction, f, args[0]);
1930 return f->shared()->name();
1931}
1932
1933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001934RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001935 NoHandleAllocation ha;
1936 ASSERT(args.length() == 2);
1937
1938 CONVERT_CHECKED(JSFunction, f, args[0]);
1939 CONVERT_CHECKED(String, name, args[1]);
1940 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001941 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001942}
1943
1944
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001945RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1946 NoHandleAllocation ha;
1947 ASSERT(args.length() == 1);
1948 CONVERT_CHECKED(JSFunction, f, args[0]);
1949 return isolate->heap()->ToBoolean(
1950 f->shared()->name_should_print_as_anonymous());
1951}
1952
1953
1954RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1955 NoHandleAllocation ha;
1956 ASSERT(args.length() == 1);
1957 CONVERT_CHECKED(JSFunction, f, args[0]);
1958 f->shared()->set_name_should_print_as_anonymous(true);
1959 return isolate->heap()->undefined_value();
1960}
1961
1962
whesse@chromium.org7b260152011-06-20 15:33:18 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1964 HandleScope scope(isolate);
1965 ASSERT(args.length() == 1);
1966
1967 CONVERT_CHECKED(JSFunction, fun, args[0]);
1968 fun->shared()->set_bound(true);
1969 return isolate->heap()->undefined_value();
1970}
1971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001972RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001973 NoHandleAllocation ha;
1974 ASSERT(args.length() == 1);
1975
1976 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001977 Object* obj = f->RemovePrototype();
1978 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001979
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001980 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001981}
1982
1983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001984RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 ASSERT(args.length() == 1);
1987
1988 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001989 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1990 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001991
1992 return *GetScriptWrapper(Handle<Script>::cast(script));
1993}
1994
1995
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001996RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997 NoHandleAllocation ha;
1998 ASSERT(args.length() == 1);
1999
2000 CONVERT_CHECKED(JSFunction, f, args[0]);
2001 return f->shared()->GetSourceCode();
2002}
2003
2004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002005RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006 NoHandleAllocation ha;
2007 ASSERT(args.length() == 1);
2008
2009 CONVERT_CHECKED(JSFunction, fun, args[0]);
2010 int pos = fun->shared()->start_position();
2011 return Smi::FromInt(pos);
2012}
2013
2014
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002015RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002016 ASSERT(args.length() == 2);
2017
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002018 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002019 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2020
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002021 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2022
2023 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002024 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002025}
2026
2027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002028RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 NoHandleAllocation ha;
2030 ASSERT(args.length() == 2);
2031
2032 CONVERT_CHECKED(JSFunction, fun, args[0]);
2033 CONVERT_CHECKED(String, name, args[1]);
2034 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036}
2037
2038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002039RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 NoHandleAllocation ha;
2041 ASSERT(args.length() == 2);
2042
2043 CONVERT_CHECKED(JSFunction, fun, args[0]);
2044 CONVERT_CHECKED(Smi, length, args[1]);
2045 fun->shared()->set_length(length->value());
2046 return length;
2047}
2048
2049
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002050// Creates a local, readonly, property called length with the correct
2051// length (when read by the user). This effectively overwrites the
2052// interceptor used to normally provide the length.
2053RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2054 NoHandleAllocation ha;
2055 ASSERT(args.length() == 2);
2056 CONVERT_CHECKED(JSFunction, fun, args[0]);
2057 CONVERT_CHECKED(Smi, length, args[1]);
2058 MaybeObject* maybe_name =
2059 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2060 String* name;
2061 if (!maybe_name->To(&name)) return maybe_name;
2062 PropertyAttributes attr =
2063 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2064 return fun->AddProperty(name, length, attr, kNonStrictMode);
2065}
2066
2067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002068RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002069 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070 ASSERT(args.length() == 2);
2071
2072 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002073 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002074 Object* obj;
2075 { MaybeObject* maybe_obj =
2076 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2077 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002079 return args[0]; // return TOS
2080}
2081
2082
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002083RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2084 NoHandleAllocation ha;
2085 RUNTIME_ASSERT(args.length() == 1);
2086 CONVERT_CHECKED(JSFunction, function, args[0]);
2087
2088 MaybeObject* maybe_name =
2089 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2090 String* name;
2091 if (!maybe_name->To(&name)) return maybe_name;
2092
2093 if (function->HasFastProperties()) {
2094 // Construct a new field descriptor with updated attributes.
2095 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2096 int index = instance_desc->Search(name);
2097 ASSERT(index != DescriptorArray::kNotFound);
2098 PropertyDetails details(instance_desc->GetDetails(index));
2099 CallbacksDescriptor new_desc(name,
2100 instance_desc->GetValue(index),
2101 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2102 details.index());
2103 // Construct a new field descriptors array containing the new descriptor.
2104 Object* descriptors_unchecked;
2105 { MaybeObject* maybe_descriptors_unchecked =
2106 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2107 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2108 return maybe_descriptors_unchecked;
2109 }
2110 }
2111 DescriptorArray* new_descriptors =
2112 DescriptorArray::cast(descriptors_unchecked);
2113 // Create a new map featuring the new field descriptors array.
2114 Object* map_unchecked;
2115 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2116 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2117 return maybe_map_unchecked;
2118 }
2119 }
2120 Map* new_map = Map::cast(map_unchecked);
2121 new_map->set_instance_descriptors(new_descriptors);
2122 function->set_map(new_map);
2123 } else { // Dictionary properties.
2124 // Directly manipulate the property details.
2125 int entry = function->property_dictionary()->FindEntry(name);
2126 ASSERT(entry != StringDictionary::kNotFound);
2127 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2128 PropertyDetails new_details(
2129 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2130 details.type(),
2131 details.index());
2132 function->property_dictionary()->DetailsAtPut(entry, new_details);
2133 }
2134 return function;
2135}
2136
2137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002138RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002139 NoHandleAllocation ha;
2140 ASSERT(args.length() == 1);
2141
2142 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002143 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002144}
2145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002147RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002148 NoHandleAllocation ha;
2149 ASSERT(args.length() == 1);
2150
2151 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002152 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002153}
2154
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002156RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00002157 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002158 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 ASSERT(args.length() == 2);
2160
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002161 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 Handle<Object> code = args.at<Object>(1);
2163
2164 Handle<Context> context(target->context());
2165
2166 if (!code->IsNull()) {
2167 RUNTIME_ASSERT(code->IsJSFunction());
2168 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002169 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170
2171 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 return Failure::Exception();
2173 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002174 // Since we don't store the source for this we should never
2175 // optimize this.
2176 shared->code()->set_optimizable(false);
2177
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002178 // Set the code, scope info, formal parameter count,
2179 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002180 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002181 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002182 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002183 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002185 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002186 // Set the source code of the target function to undefined.
2187 // SetCode is only used for built-in constructors like String,
2188 // Array, and Object, and some web code
2189 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002190 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002191 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002192 // Clear the optimization hints related to the compiled code as these are no
2193 // longer valid when the code is overwritten.
2194 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195 context = Handle<Context>(fun->context());
2196
2197 // Make sure we get a fresh copy of the literal vector to avoid
2198 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002199 int number_of_literals = fun->NumberOfLiterals();
2200 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002201 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002202 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002203 // Insert the object, regexp and array functions in the literals
2204 // array prefix. These are the functions that will be used when
2205 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002206 literals->set(JSFunction::kLiteralGlobalContextIndex,
2207 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002209 // It's okay to skip the write barrier here because the literals
2210 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002211 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002213 }
2214
2215 target->set_context(*context);
2216 return *target;
2217}
2218
2219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002220RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002222 ASSERT(args.length() == 2);
2223 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002224 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002225 RUNTIME_ASSERT(num >= 0);
2226 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002228}
2229
2230
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2232 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002233 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002234 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002235 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002236 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002237 }
2238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002240}
2241
2242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002243RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002244 NoHandleAllocation ha;
2245 ASSERT(args.length() == 2);
2246
2247 CONVERT_CHECKED(String, subject, args[0]);
2248 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002249 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002251 uint32_t i = 0;
2252 if (index->IsSmi()) {
2253 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002255 i = value;
2256 } else {
2257 ASSERT(index->IsHeapNumber());
2258 double value = HeapNumber::cast(index)->value();
2259 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002260 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002261
2262 // Flatten the string. If someone wants to get a char at an index
2263 // in a cons string, it is likely that more indices will be
2264 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002265 Object* flat;
2266 { MaybeObject* maybe_flat = subject->TryFlatten();
2267 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2268 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002269 subject = String::cast(flat);
2270
2271 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002272 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002273 }
2274
2275 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002276}
2277
2278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002279RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002280 NoHandleAllocation ha;
2281 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002282 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002283}
2284
lrn@chromium.org25156de2010-04-06 13:10:27 +00002285
2286class FixedArrayBuilder {
2287 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2289 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 length_(0) {
2291 // Require a non-zero initial size. Ensures that doubling the size to
2292 // extend the array will work.
2293 ASSERT(initial_capacity > 0);
2294 }
2295
2296 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2297 : array_(backing_store),
2298 length_(0) {
2299 // Require a non-zero initial size. Ensures that doubling the size to
2300 // extend the array will work.
2301 ASSERT(backing_store->length() > 0);
2302 }
2303
2304 bool HasCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 return (length >= required_length);
2308 }
2309
2310 void EnsureCapacity(int elements) {
2311 int length = array_->length();
2312 int required_length = length_ + elements;
2313 if (length < required_length) {
2314 int new_length = length;
2315 do {
2316 new_length *= 2;
2317 } while (new_length < required_length);
2318 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002319 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 array_->CopyTo(0, *extended_array, 0, length_);
2321 array_ = extended_array;
2322 }
2323 }
2324
2325 void Add(Object* value) {
2326 ASSERT(length_ < capacity());
2327 array_->set(length_, value);
2328 length_++;
2329 }
2330
2331 void Add(Smi* value) {
2332 ASSERT(length_ < capacity());
2333 array_->set(length_, value);
2334 length_++;
2335 }
2336
2337 Handle<FixedArray> array() {
2338 return array_;
2339 }
2340
2341 int length() {
2342 return length_;
2343 }
2344
2345 int capacity() {
2346 return array_->length();
2347 }
2348
2349 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002350 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002351 result_array->set_length(Smi::FromInt(length_));
2352 return result_array;
2353 }
2354
2355 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2356 target_array->set_elements(*array_);
2357 target_array->set_length(Smi::FromInt(length_));
2358 return target_array;
2359 }
2360
2361 private:
2362 Handle<FixedArray> array_;
2363 int length_;
2364};
2365
2366
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002368const int kStringBuilderConcatHelperLengthBits = 11;
2369const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002370
2371template <typename schar>
2372static inline void StringBuilderConcatHelper(String*,
2373 schar*,
2374 FixedArray*,
2375 int);
2376
lrn@chromium.org25156de2010-04-06 13:10:27 +00002377typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2378 StringBuilderSubstringLength;
2379typedef BitField<int,
2380 kStringBuilderConcatHelperLengthBits,
2381 kStringBuilderConcatHelperPositionBits>
2382 StringBuilderSubstringPosition;
2383
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384
2385class ReplacementStringBuilder {
2386 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002387 ReplacementStringBuilder(Heap* heap,
2388 Handle<String> subject,
2389 int estimated_part_count)
2390 : heap_(heap),
2391 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002394 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002395 // Require a non-zero initial size. Ensures that doubling the size to
2396 // extend the array will work.
2397 ASSERT(estimated_part_count > 0);
2398 }
2399
lrn@chromium.org25156de2010-04-06 13:10:27 +00002400 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2401 int from,
2402 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403 ASSERT(from >= 0);
2404 int length = to - from;
2405 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002406 if (StringBuilderSubstringLength::is_valid(length) &&
2407 StringBuilderSubstringPosition::is_valid(from)) {
2408 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2409 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002411 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002412 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 builder->Add(Smi::FromInt(-length));
2414 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002415 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002416 }
2417
2418
2419 void EnsureCapacity(int elements) {
2420 array_builder_.EnsureCapacity(elements);
2421 }
2422
2423
2424 void AddSubjectSlice(int from, int to) {
2425 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 }
2428
2429
2430 void AddString(Handle<String> string) {
2431 int length = string->length();
2432 ASSERT(length > 0);
2433 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002434 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002435 is_ascii_ = false;
2436 }
2437 IncrementCharacterCount(length);
2438 }
2439
2440
2441 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002442 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002443 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 }
2445
2446 Handle<String> joined_string;
2447 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002448 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002449 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002450 char* char_buffer = seq->GetChars();
2451 StringBuilderConcatHelper(*subject_,
2452 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 *array_builder_.array(),
2454 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002455 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 } else {
2457 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002458 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002459 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 uc16* char_buffer = seq->GetChars();
2461 StringBuilderConcatHelper(*subject_,
2462 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002463 *array_builder_.array(),
2464 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002465 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002466 }
2467 return joined_string;
2468 }
2469
2470
2471 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002472 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473 V8::FatalProcessOutOfMemory("String.replace result too large.");
2474 }
2475 character_count_ += by;
2476 }
2477
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002479 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002480 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002481
lrn@chromium.org25156de2010-04-06 13:10:27 +00002482 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002483 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2484 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002485 }
2486
2487
ager@chromium.org04921a82011-06-27 13:21:41 +00002488 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2489 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002490 }
2491
2492
2493 void AddElement(Object* element) {
2494 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002495 ASSERT(array_builder_.capacity() > array_builder_.length());
2496 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002497 }
2498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002499 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002500 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002501 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002502 int character_count_;
2503 bool is_ascii_;
2504};
2505
2506
2507class CompiledReplacement {
2508 public:
2509 CompiledReplacement()
2510 : parts_(1), replacement_substrings_(0) {}
2511
2512 void Compile(Handle<String> replacement,
2513 int capture_count,
2514 int subject_length);
2515
2516 void Apply(ReplacementStringBuilder* builder,
2517 int match_from,
2518 int match_to,
2519 Handle<JSArray> last_match_info);
2520
2521 // Number of distinct parts of the replacement pattern.
2522 int parts() {
2523 return parts_.length();
2524 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002525
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002526 private:
2527 enum PartType {
2528 SUBJECT_PREFIX = 1,
2529 SUBJECT_SUFFIX,
2530 SUBJECT_CAPTURE,
2531 REPLACEMENT_SUBSTRING,
2532 REPLACEMENT_STRING,
2533
2534 NUMBER_OF_PART_TYPES
2535 };
2536
2537 struct ReplacementPart {
2538 static inline ReplacementPart SubjectMatch() {
2539 return ReplacementPart(SUBJECT_CAPTURE, 0);
2540 }
2541 static inline ReplacementPart SubjectCapture(int capture_index) {
2542 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2543 }
2544 static inline ReplacementPart SubjectPrefix() {
2545 return ReplacementPart(SUBJECT_PREFIX, 0);
2546 }
2547 static inline ReplacementPart SubjectSuffix(int subject_length) {
2548 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2549 }
2550 static inline ReplacementPart ReplacementString() {
2551 return ReplacementPart(REPLACEMENT_STRING, 0);
2552 }
2553 static inline ReplacementPart ReplacementSubString(int from, int to) {
2554 ASSERT(from >= 0);
2555 ASSERT(to > from);
2556 return ReplacementPart(-from, to);
2557 }
2558
2559 // If tag <= 0 then it is the negation of a start index of a substring of
2560 // the replacement pattern, otherwise it's a value from PartType.
2561 ReplacementPart(int tag, int data)
2562 : tag(tag), data(data) {
2563 // Must be non-positive or a PartType value.
2564 ASSERT(tag < NUMBER_OF_PART_TYPES);
2565 }
2566 // Either a value of PartType or a non-positive number that is
2567 // the negation of an index into the replacement string.
2568 int tag;
2569 // The data value's interpretation depends on the value of tag:
2570 // tag == SUBJECT_PREFIX ||
2571 // tag == SUBJECT_SUFFIX: data is unused.
2572 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2573 // tag == REPLACEMENT_SUBSTRING ||
2574 // tag == REPLACEMENT_STRING: data is index into array of substrings
2575 // of the replacement string.
2576 // tag <= 0: Temporary representation of the substring of the replacement
2577 // string ranging over -tag .. data.
2578 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2579 // substring objects.
2580 int data;
2581 };
2582
2583 template<typename Char>
2584 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2585 Vector<Char> characters,
2586 int capture_count,
2587 int subject_length) {
2588 int length = characters.length();
2589 int last = 0;
2590 for (int i = 0; i < length; i++) {
2591 Char c = characters[i];
2592 if (c == '$') {
2593 int next_index = i + 1;
2594 if (next_index == length) { // No next character!
2595 break;
2596 }
2597 Char c2 = characters[next_index];
2598 switch (c2) {
2599 case '$':
2600 if (i > last) {
2601 // There is a substring before. Include the first "$".
2602 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2603 last = next_index + 1; // Continue after the second "$".
2604 } else {
2605 // Let the next substring start with the second "$".
2606 last = next_index;
2607 }
2608 i = next_index;
2609 break;
2610 case '`':
2611 if (i > last) {
2612 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2613 }
2614 parts->Add(ReplacementPart::SubjectPrefix());
2615 i = next_index;
2616 last = i + 1;
2617 break;
2618 case '\'':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '&':
2627 if (i > last) {
2628 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2629 }
2630 parts->Add(ReplacementPart::SubjectMatch());
2631 i = next_index;
2632 last = i + 1;
2633 break;
2634 case '0':
2635 case '1':
2636 case '2':
2637 case '3':
2638 case '4':
2639 case '5':
2640 case '6':
2641 case '7':
2642 case '8':
2643 case '9': {
2644 int capture_ref = c2 - '0';
2645 if (capture_ref > capture_count) {
2646 i = next_index;
2647 continue;
2648 }
2649 int second_digit_index = next_index + 1;
2650 if (second_digit_index < length) {
2651 // Peek ahead to see if we have two digits.
2652 Char c3 = characters[second_digit_index];
2653 if ('0' <= c3 && c3 <= '9') { // Double digits.
2654 int double_digit_ref = capture_ref * 10 + c3 - '0';
2655 if (double_digit_ref <= capture_count) {
2656 next_index = second_digit_index;
2657 capture_ref = double_digit_ref;
2658 }
2659 }
2660 }
2661 if (capture_ref > 0) {
2662 if (i > last) {
2663 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2664 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002665 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002666 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2667 last = next_index + 1;
2668 }
2669 i = next_index;
2670 break;
2671 }
2672 default:
2673 i = next_index;
2674 break;
2675 }
2676 }
2677 }
2678 if (length > last) {
2679 if (last == 0) {
2680 parts->Add(ReplacementPart::ReplacementString());
2681 } else {
2682 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2683 }
2684 }
2685 }
2686
2687 ZoneList<ReplacementPart> parts_;
2688 ZoneList<Handle<String> > replacement_substrings_;
2689};
2690
2691
2692void CompiledReplacement::Compile(Handle<String> replacement,
2693 int capture_count,
2694 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002695 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002696 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002697 String::FlatContent content = replacement->GetFlatContent();
2698 ASSERT(content.IsFlat());
2699 if (content.IsAscii()) {
2700 ParseReplacementPattern(&parts_,
2701 content.ToAsciiVector(),
2702 capture_count,
2703 subject_length);
2704 } else {
2705 ASSERT(content.IsTwoByte());
2706 ParseReplacementPattern(&parts_,
2707 content.ToUC16Vector(),
2708 capture_count,
2709 subject_length);
2710 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002711 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002712 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002713 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002714 int substring_index = 0;
2715 for (int i = 0, n = parts_.length(); i < n; i++) {
2716 int tag = parts_[i].tag;
2717 if (tag <= 0) { // A replacement string slice.
2718 int from = -tag;
2719 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002720 replacement_substrings_.Add(
2721 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722 parts_[i].tag = REPLACEMENT_SUBSTRING;
2723 parts_[i].data = substring_index;
2724 substring_index++;
2725 } else if (tag == REPLACEMENT_STRING) {
2726 replacement_substrings_.Add(replacement);
2727 parts_[i].data = substring_index;
2728 substring_index++;
2729 }
2730 }
2731}
2732
2733
2734void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2735 int match_from,
2736 int match_to,
2737 Handle<JSArray> last_match_info) {
2738 for (int i = 0, n = parts_.length(); i < n; i++) {
2739 ReplacementPart part = parts_[i];
2740 switch (part.tag) {
2741 case SUBJECT_PREFIX:
2742 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2743 break;
2744 case SUBJECT_SUFFIX: {
2745 int subject_length = part.data;
2746 if (match_to < subject_length) {
2747 builder->AddSubjectSlice(match_to, subject_length);
2748 }
2749 break;
2750 }
2751 case SUBJECT_CAPTURE: {
2752 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002753 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002754 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2755 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2756 if (from >= 0 && to > from) {
2757 builder->AddSubjectSlice(from, to);
2758 }
2759 break;
2760 }
2761 case REPLACEMENT_SUBSTRING:
2762 case REPLACEMENT_STRING:
2763 builder->AddString(replacement_substrings_[part.data]);
2764 break;
2765 default:
2766 UNREACHABLE();
2767 }
2768 }
2769}
2770
2771
2772
lrn@chromium.org303ada72010-10-27 09:33:13 +00002773MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002774 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002775 String* subject,
2776 JSRegExp* regexp,
2777 String* replacement,
2778 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002779 ASSERT(subject->IsFlat());
2780 ASSERT(replacement->IsFlat());
2781
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002782 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002783
2784 int length = subject->length();
2785 Handle<String> subject_handle(subject);
2786 Handle<JSRegExp> regexp_handle(regexp);
2787 Handle<String> replacement_handle(replacement);
2788 Handle<JSArray> last_match_info_handle(last_match_info);
2789 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2790 subject_handle,
2791 0,
2792 last_match_info_handle);
2793 if (match.is_null()) {
2794 return Failure::Exception();
2795 }
2796 if (match->IsNull()) {
2797 return *subject_handle;
2798 }
2799
2800 int capture_count = regexp_handle->CaptureCount();
2801
2802 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002803 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002804 CompiledReplacement compiled_replacement;
2805 compiled_replacement.Compile(replacement_handle,
2806 capture_count,
2807 length);
2808
2809 bool is_global = regexp_handle->GetFlags().is_global();
2810
2811 // Guessing the number of parts that the final result string is built
2812 // from. Global regexps can match any number of times, so we guess
2813 // conservatively.
2814 int expected_parts =
2815 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002816 ReplacementStringBuilder builder(isolate->heap(),
2817 subject_handle,
2818 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002819
2820 // Index of end of last match.
2821 int prev = 0;
2822
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002823 // Number of parts added by compiled replacement plus preceeding
2824 // string and possibly suffix after last match. It is possible for
2825 // all components to use two elements when encoded as two smis.
2826 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002827 bool matched = true;
2828 do {
2829 ASSERT(last_match_info_handle->HasFastElements());
2830 // Increase the capacity of the builder before entering local handle-scope,
2831 // so its internal buffer can safely allocate a new handle if it grows.
2832 builder.EnsureCapacity(parts_added_per_loop);
2833
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002834 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002835 int start, end;
2836 {
2837 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002838 FixedArray* match_info_array =
2839 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002840
2841 ASSERT_EQ(capture_count * 2 + 2,
2842 RegExpImpl::GetLastCaptureCount(match_info_array));
2843 start = RegExpImpl::GetCapture(match_info_array, 0);
2844 end = RegExpImpl::GetCapture(match_info_array, 1);
2845 }
2846
2847 if (prev < start) {
2848 builder.AddSubjectSlice(prev, start);
2849 }
2850 compiled_replacement.Apply(&builder,
2851 start,
2852 end,
2853 last_match_info_handle);
2854 prev = end;
2855
2856 // Only continue checking for global regexps.
2857 if (!is_global) break;
2858
2859 // Continue from where the match ended, unless it was an empty match.
2860 int next = end;
2861 if (start == end) {
2862 next = end + 1;
2863 if (next > length) break;
2864 }
2865
2866 match = RegExpImpl::Exec(regexp_handle,
2867 subject_handle,
2868 next,
2869 last_match_info_handle);
2870 if (match.is_null()) {
2871 return Failure::Exception();
2872 }
2873 matched = !match->IsNull();
2874 } while (matched);
2875
2876 if (prev < length) {
2877 builder.AddSubjectSlice(prev, length);
2878 }
2879
2880 return *(builder.ToString());
2881}
2882
2883
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002884template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002885MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002886 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002887 String* subject,
2888 JSRegExp* regexp,
2889 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002890 ASSERT(subject->IsFlat());
2891
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002892 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002893
2894 Handle<String> subject_handle(subject);
2895 Handle<JSRegExp> regexp_handle(regexp);
2896 Handle<JSArray> last_match_info_handle(last_match_info);
2897 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2898 subject_handle,
2899 0,
2900 last_match_info_handle);
2901 if (match.is_null()) return Failure::Exception();
2902 if (match->IsNull()) return *subject_handle;
2903
2904 ASSERT(last_match_info_handle->HasFastElements());
2905
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002906 int start, end;
2907 {
2908 AssertNoAllocation match_info_array_is_not_in_a_handle;
2909 FixedArray* match_info_array =
2910 FixedArray::cast(last_match_info_handle->elements());
2911
2912 start = RegExpImpl::GetCapture(match_info_array, 0);
2913 end = RegExpImpl::GetCapture(match_info_array, 1);
2914 }
2915
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002916 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002917 int new_length = length - (end - start);
2918 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002919 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002920 }
2921 Handle<ResultSeqString> answer;
2922 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 answer = Handle<ResultSeqString>::cast(
2924 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002925 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002926 answer = Handle<ResultSeqString>::cast(
2927 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002928 }
2929
2930 // If the regexp isn't global, only match once.
2931 if (!regexp_handle->GetFlags().is_global()) {
2932 if (start > 0) {
2933 String::WriteToFlat(*subject_handle,
2934 answer->GetChars(),
2935 0,
2936 start);
2937 }
2938 if (end < length) {
2939 String::WriteToFlat(*subject_handle,
2940 answer->GetChars() + start,
2941 end,
2942 length);
2943 }
2944 return *answer;
2945 }
2946
2947 int prev = 0; // Index of end of last match.
2948 int next = 0; // Start of next search (prev unless last match was empty).
2949 int position = 0;
2950
2951 do {
2952 if (prev < start) {
2953 // Add substring subject[prev;start] to answer string.
2954 String::WriteToFlat(*subject_handle,
2955 answer->GetChars() + position,
2956 prev,
2957 start);
2958 position += start - prev;
2959 }
2960 prev = end;
2961 next = end;
2962 // Continue from where the match ended, unless it was an empty match.
2963 if (start == end) {
2964 next++;
2965 if (next > length) break;
2966 }
2967 match = RegExpImpl::Exec(regexp_handle,
2968 subject_handle,
2969 next,
2970 last_match_info_handle);
2971 if (match.is_null()) return Failure::Exception();
2972 if (match->IsNull()) break;
2973
2974 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002975 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002976 {
2977 AssertNoAllocation match_info_array_is_not_in_a_handle;
2978 FixedArray* match_info_array =
2979 FixedArray::cast(last_match_info_handle->elements());
2980 start = RegExpImpl::GetCapture(match_info_array, 0);
2981 end = RegExpImpl::GetCapture(match_info_array, 1);
2982 }
2983 } while (true);
2984
2985 if (prev < length) {
2986 // Add substring subject[prev;length] to answer string.
2987 String::WriteToFlat(*subject_handle,
2988 answer->GetChars() + position,
2989 prev,
2990 length);
2991 position += length - prev;
2992 }
2993
2994 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002995 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002996 }
2997
2998 // Shorten string and fill
2999 int string_size = ResultSeqString::SizeFor(position);
3000 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3001 int delta = allocated_string_size - string_size;
3002
3003 answer->set_length(position);
3004 if (delta == 0) return *answer;
3005
3006 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003007 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003008
3009 return *answer;
3010}
3011
3012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003013RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003014 ASSERT(args.length() == 4);
3015
3016 CONVERT_CHECKED(String, subject, args[0]);
3017 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003018 Object* flat_subject;
3019 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3020 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3021 return maybe_flat_subject;
3022 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003023 }
3024 subject = String::cast(flat_subject);
3025 }
3026
3027 CONVERT_CHECKED(String, replacement, args[2]);
3028 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003029 Object* flat_replacement;
3030 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3031 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3032 return maybe_flat_replacement;
3033 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003034 }
3035 replacement = String::cast(flat_replacement);
3036 }
3037
3038 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3039 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3040
3041 ASSERT(last_match_info->HasFastElements());
3042
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003043 if (replacement->length() == 0) {
3044 if (subject->HasOnlyAsciiChars()) {
3045 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003046 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003047 } else {
3048 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003049 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003050 }
3051 }
3052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003053 return StringReplaceRegExpWithString(isolate,
3054 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003055 regexp,
3056 replacement,
3057 last_match_info);
3058}
3059
3060
ager@chromium.org7c537e22008-10-16 08:43:32 +00003061// Perform string match of pattern on subject, starting at start index.
3062// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003063// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003064int Runtime::StringMatch(Isolate* isolate,
3065 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003066 Handle<String> pat,
3067 int start_index) {
3068 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003069 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003070
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003071 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003072 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003073
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003074 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003075 if (start_index + pattern_length > subject_length) return -1;
3076
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003077 if (!sub->IsFlat()) FlattenString(sub);
3078 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003079
ager@chromium.org7c537e22008-10-16 08:43:32 +00003080 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003081 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003082 String::FlatContent seq_sub = sub->GetFlatContent();
3083 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003084
ager@chromium.org7c537e22008-10-16 08:43:32 +00003085 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003086 if (seq_pat.IsAscii()) {
3087 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3088 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003089 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003090 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003091 pat_vector,
3092 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003093 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003094 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003095 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 pat_vector,
3097 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003098 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003099 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3100 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003101 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003102 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003103 pat_vector,
3104 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003105 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003106 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003107 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003108 pat_vector,
3109 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003110}
3111
3112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003113RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003114 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003115 ASSERT(args.length() == 3);
3116
ager@chromium.org7c537e22008-10-16 08:43:32 +00003117 CONVERT_ARG_CHECKED(String, sub, 0);
3118 CONVERT_ARG_CHECKED(String, pat, 1);
3119
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003120 Object* index = args[2];
3121 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003122 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003123
ager@chromium.org870a0b62008-11-04 11:43:05 +00003124 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003125 int position =
3126 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003127 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003128}
3129
3130
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003131template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003132static int StringMatchBackwards(Vector<const schar> subject,
3133 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003134 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003135 int pattern_length = pattern.length();
3136 ASSERT(pattern_length >= 1);
3137 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003138
3139 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003140 for (int i = 0; i < pattern_length; i++) {
3141 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003142 if (c > String::kMaxAsciiCharCode) {
3143 return -1;
3144 }
3145 }
3146 }
3147
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003148 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003149 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003150 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003151 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003152 while (j < pattern_length) {
3153 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003154 break;
3155 }
3156 j++;
3157 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003158 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003159 return i;
3160 }
3161 }
3162 return -1;
3163}
3164
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003165RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003166 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003167 ASSERT(args.length() == 3);
3168
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003169 CONVERT_ARG_CHECKED(String, sub, 0);
3170 CONVERT_ARG_CHECKED(String, pat, 1);
3171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003172 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003173 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003174 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003175
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003176 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003177 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003178
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003179 if (start_index + pat_length > sub_length) {
3180 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003181 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003182
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003183 if (pat_length == 0) {
3184 return Smi::FromInt(start_index);
3185 }
3186
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003187 if (!sub->IsFlat()) FlattenString(sub);
3188 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003189
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003190 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003191 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3192
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003193 String::FlatContent sub_content = sub->GetFlatContent();
3194 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003195
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003196 if (pat_content.IsAscii()) {
3197 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3198 if (sub_content.IsAscii()) {
3199 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003200 pat_vector,
3201 start_index);
3202 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003203 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003204 pat_vector,
3205 start_index);
3206 }
3207 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003208 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3209 if (sub_content.IsAscii()) {
3210 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003211 pat_vector,
3212 start_index);
3213 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003214 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003215 pat_vector,
3216 start_index);
3217 }
3218 }
3219
3220 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003221}
3222
3223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003224RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003225 NoHandleAllocation ha;
3226 ASSERT(args.length() == 2);
3227
3228 CONVERT_CHECKED(String, str1, args[0]);
3229 CONVERT_CHECKED(String, str2, args[1]);
3230
3231 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003232 int str1_length = str1->length();
3233 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003234
3235 // Decide trivial cases without flattening.
3236 if (str1_length == 0) {
3237 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3238 return Smi::FromInt(-str2_length);
3239 } else {
3240 if (str2_length == 0) return Smi::FromInt(str1_length);
3241 }
3242
3243 int end = str1_length < str2_length ? str1_length : str2_length;
3244
3245 // No need to flatten if we are going to find the answer on the first
3246 // character. At this point we know there is at least one character
3247 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003248 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003249 if (d != 0) return Smi::FromInt(d);
3250
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003251 str1->TryFlatten();
3252 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003254 StringInputBuffer& buf1 =
3255 *isolate->runtime_state()->string_locale_compare_buf1();
3256 StringInputBuffer& buf2 =
3257 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258
3259 buf1.Reset(str1);
3260 buf2.Reset(str2);
3261
3262 for (int i = 0; i < end; i++) {
3263 uint16_t char1 = buf1.GetNext();
3264 uint16_t char2 = buf2.GetNext();
3265 if (char1 != char2) return Smi::FromInt(char1 - char2);
3266 }
3267
3268 return Smi::FromInt(str1_length - str2_length);
3269}
3270
3271
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003272RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003273 NoHandleAllocation ha;
3274 ASSERT(args.length() == 3);
3275
3276 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003277 int start, end;
3278 // We have a fast integer-only case here to avoid a conversion to double in
3279 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003280 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3281 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3282 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3283 start = from_number;
3284 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003285 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003286 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3287 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003288 start = FastD2I(from_number);
3289 end = FastD2I(to_number);
3290 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003291 RUNTIME_ASSERT(end >= start);
3292 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003293 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003294 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003295 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296}
3297
3298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003299RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003300 ASSERT_EQ(3, args.length());
3301
3302 CONVERT_ARG_CHECKED(String, subject, 0);
3303 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3304 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3305 HandleScope handles;
3306
3307 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3308
3309 if (match.is_null()) {
3310 return Failure::Exception();
3311 }
3312 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003313 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003314 }
3315 int length = subject->length();
3316
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003317 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003318 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003319 int start;
3320 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003321 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003322 {
3323 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003324 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003325 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3326 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3327 }
3328 offsets.Add(start);
3329 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003330 if (start == end) if (++end > length) break;
3331 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003332 if (match.is_null()) {
3333 return Failure::Exception();
3334 }
3335 } while (!match->IsNull());
3336 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003337 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003338 Handle<String> substring = isolate->factory()->
3339 NewSubString(subject, offsets.at(0), offsets.at(1));
3340 elements->set(0, *substring);
3341 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003342 int from = offsets.at(i * 2);
3343 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003344 Handle<String> substring = isolate->factory()->
3345 NewProperSubString(subject, from, to);
3346 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003347 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003348 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003349 result->set_length(Smi::FromInt(matches));
3350 return *result;
3351}
3352
3353
lrn@chromium.org25156de2010-04-06 13:10:27 +00003354// Two smis before and after the match, for very long strings.
3355const int kMaxBuilderEntriesPerRegExpMatch = 5;
3356
3357
3358static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3359 Handle<JSArray> last_match_info,
3360 int match_start,
3361 int match_end) {
3362 // Fill last_match_info with a single capture.
3363 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3364 AssertNoAllocation no_gc;
3365 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3366 RegExpImpl::SetLastCaptureCount(elements, 2);
3367 RegExpImpl::SetLastInput(elements, *subject);
3368 RegExpImpl::SetLastSubject(elements, *subject);
3369 RegExpImpl::SetCapture(elements, 0, match_start);
3370 RegExpImpl::SetCapture(elements, 1, match_end);
3371}
3372
3373
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003374template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375static bool SearchStringMultiple(Isolate* isolate,
3376 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003377 Vector<const PatternChar> pattern,
3378 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003379 FixedArrayBuilder* builder,
3380 int* match_pos) {
3381 int pos = *match_pos;
3382 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003383 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003384 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003385 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003386 while (pos <= max_search_start) {
3387 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3388 *match_pos = pos;
3389 return false;
3390 }
3391 // Position of end of previous match.
3392 int match_end = pos + pattern_length;
3393 int new_pos = search.Search(subject, match_end);
3394 if (new_pos >= 0) {
3395 // A match.
3396 if (new_pos > match_end) {
3397 ReplacementStringBuilder::AddSubjectSlice(builder,
3398 match_end,
3399 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003400 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003401 pos = new_pos;
3402 builder->Add(pattern_string);
3403 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003404 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003405 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003406 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003407
lrn@chromium.org25156de2010-04-06 13:10:27 +00003408 if (pos < max_search_start) {
3409 ReplacementStringBuilder::AddSubjectSlice(builder,
3410 pos + pattern_length,
3411 subject_length);
3412 }
3413 *match_pos = pos;
3414 return true;
3415}
3416
3417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003418static bool SearchStringMultiple(Isolate* isolate,
3419 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003420 Handle<String> pattern,
3421 Handle<JSArray> last_match_info,
3422 FixedArrayBuilder* builder) {
3423 ASSERT(subject->IsFlat());
3424 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003425
3426 // Treating as if a previous match was before first character.
3427 int match_pos = -pattern->length();
3428
3429 for (;;) { // Break when search complete.
3430 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3431 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003432 String::FlatContent subject_content = subject->GetFlatContent();
3433 String::FlatContent pattern_content = pattern->GetFlatContent();
3434 if (subject_content.IsAscii()) {
3435 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3436 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003437 if (SearchStringMultiple(isolate,
3438 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003439 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003440 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003441 builder,
3442 &match_pos)) break;
3443 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003444 if (SearchStringMultiple(isolate,
3445 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003446 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003447 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003448 builder,
3449 &match_pos)) break;
3450 }
3451 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003452 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3453 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003454 if (SearchStringMultiple(isolate,
3455 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003456 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003457 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003458 builder,
3459 &match_pos)) break;
3460 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003461 if (SearchStringMultiple(isolate,
3462 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003463 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003464 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003465 builder,
3466 &match_pos)) break;
3467 }
3468 }
3469 }
3470
3471 if (match_pos >= 0) {
3472 SetLastMatchInfoNoCaptures(subject,
3473 last_match_info,
3474 match_pos,
3475 match_pos + pattern->length());
3476 return true;
3477 }
3478 return false; // No matches at all.
3479}
3480
3481
3482static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003483 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003484 Handle<String> subject,
3485 Handle<JSRegExp> regexp,
3486 Handle<JSArray> last_match_array,
3487 FixedArrayBuilder* builder) {
3488 ASSERT(subject->IsFlat());
3489 int match_start = -1;
3490 int match_end = 0;
3491 int pos = 0;
3492 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3493 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3494
3495 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003496 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003497 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003498 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003499
3500 for (;;) { // Break on failure, return on exception.
3501 RegExpImpl::IrregexpResult result =
3502 RegExpImpl::IrregexpExecOnce(regexp,
3503 subject,
3504 pos,
3505 register_vector);
3506 if (result == RegExpImpl::RE_SUCCESS) {
3507 match_start = register_vector[0];
3508 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3509 if (match_end < match_start) {
3510 ReplacementStringBuilder::AddSubjectSlice(builder,
3511 match_end,
3512 match_start);
3513 }
3514 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003515 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003516 if (!first) {
3517 builder->Add(*isolate->factory()->NewProperSubString(subject,
3518 match_start,
3519 match_end));
3520 } else {
3521 builder->Add(*isolate->factory()->NewSubString(subject,
3522 match_start,
3523 match_end));
3524 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003525 if (match_start != match_end) {
3526 pos = match_end;
3527 } else {
3528 pos = match_end + 1;
3529 if (pos > subject_length) break;
3530 }
3531 } else if (result == RegExpImpl::RE_FAILURE) {
3532 break;
3533 } else {
3534 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3535 return result;
3536 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003537 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003538 }
3539
3540 if (match_start >= 0) {
3541 if (match_end < subject_length) {
3542 ReplacementStringBuilder::AddSubjectSlice(builder,
3543 match_end,
3544 subject_length);
3545 }
3546 SetLastMatchInfoNoCaptures(subject,
3547 last_match_array,
3548 match_start,
3549 match_end);
3550 return RegExpImpl::RE_SUCCESS;
3551 } else {
3552 return RegExpImpl::RE_FAILURE; // No matches at all.
3553 }
3554}
3555
3556
3557static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003559 Handle<String> subject,
3560 Handle<JSRegExp> regexp,
3561 Handle<JSArray> last_match_array,
3562 FixedArrayBuilder* builder) {
3563
3564 ASSERT(subject->IsFlat());
3565 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3566 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3567
3568 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003569 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003570
3571 RegExpImpl::IrregexpResult result =
3572 RegExpImpl::IrregexpExecOnce(regexp,
3573 subject,
3574 0,
3575 register_vector);
3576
3577 int capture_count = regexp->CaptureCount();
3578 int subject_length = subject->length();
3579
3580 // Position to search from.
3581 int pos = 0;
3582 // End of previous match. Differs from pos if match was empty.
3583 int match_end = 0;
3584 if (result == RegExpImpl::RE_SUCCESS) {
3585 // Need to keep a copy of the previous match for creating last_match_info
3586 // at the end, so we have two vectors that we swap between.
3587 OffsetsVector registers2(required_registers);
3588 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003589 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003590 do {
3591 int match_start = register_vector[0];
3592 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3593 if (match_end < match_start) {
3594 ReplacementStringBuilder::AddSubjectSlice(builder,
3595 match_end,
3596 match_start);
3597 }
3598 match_end = register_vector[1];
3599
3600 {
3601 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003602 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003603 // Arguments array to replace function is match, captures, index and
3604 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 Handle<FixedArray> elements =
3606 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003607 Handle<String> match;
3608 if (!first) {
3609 match = isolate->factory()->NewProperSubString(subject,
3610 match_start,
3611 match_end);
3612 } else {
3613 match = isolate->factory()->NewSubString(subject,
3614 match_start,
3615 match_end);
3616 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003617 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003618 for (int i = 1; i <= capture_count; i++) {
3619 int start = register_vector[i * 2];
3620 if (start >= 0) {
3621 int end = register_vector[i * 2 + 1];
3622 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003623 Handle<String> substring;
3624 if (!first) {
3625 substring = isolate->factory()->NewProperSubString(subject,
3626 start,
3627 end);
3628 } else {
3629 substring = isolate->factory()->NewSubString(subject, start, end);
3630 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003631 elements->set(i, *substring);
3632 } else {
3633 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003635 }
3636 }
3637 elements->set(capture_count + 1, Smi::FromInt(match_start));
3638 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003639 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003640 }
3641 // Swap register vectors, so the last successful match is in
3642 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003643 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003644 prev_register_vector = register_vector;
3645 register_vector = tmp;
3646
3647 if (match_end > match_start) {
3648 pos = match_end;
3649 } else {
3650 pos = match_end + 1;
3651 if (pos > subject_length) {
3652 break;
3653 }
3654 }
3655
3656 result = RegExpImpl::IrregexpExecOnce(regexp,
3657 subject,
3658 pos,
3659 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003660 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003661 } while (result == RegExpImpl::RE_SUCCESS);
3662
3663 if (result != RegExpImpl::RE_EXCEPTION) {
3664 // Finished matching, with at least one match.
3665 if (match_end < subject_length) {
3666 ReplacementStringBuilder::AddSubjectSlice(builder,
3667 match_end,
3668 subject_length);
3669 }
3670
3671 int last_match_capture_count = (capture_count + 1) * 2;
3672 int last_match_array_size =
3673 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3674 last_match_array->EnsureSize(last_match_array_size);
3675 AssertNoAllocation no_gc;
3676 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3677 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3678 RegExpImpl::SetLastSubject(elements, *subject);
3679 RegExpImpl::SetLastInput(elements, *subject);
3680 for (int i = 0; i < last_match_capture_count; i++) {
3681 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3682 }
3683 return RegExpImpl::RE_SUCCESS;
3684 }
3685 }
3686 // No matches at all, return failure or exception result directly.
3687 return result;
3688}
3689
3690
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003691RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003694
3695 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003696 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003697 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3698 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3699 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3700
3701 ASSERT(last_match_info->HasFastElements());
3702 ASSERT(regexp->GetFlags().is_global());
3703 Handle<FixedArray> result_elements;
3704 if (result_array->HasFastElements()) {
3705 result_elements =
3706 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003707 }
3708 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003709 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003710 }
3711 FixedArrayBuilder builder(result_elements);
3712
3713 if (regexp->TypeTag() == JSRegExp::ATOM) {
3714 Handle<String> pattern(
3715 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003716 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003717 if (SearchStringMultiple(isolate, subject, pattern,
3718 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 return *builder.ToJSArray(result_array);
3720 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003721 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003722 }
3723
3724 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3725
3726 RegExpImpl::IrregexpResult result;
3727 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003728 result = SearchRegExpNoCaptureMultiple(isolate,
3729 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003730 regexp,
3731 last_match_info,
3732 &builder);
3733 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003734 result = SearchRegExpMultiple(isolate,
3735 subject,
3736 regexp,
3737 last_match_info,
3738 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003739 }
3740 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003742 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3743 return Failure::Exception();
3744}
3745
3746
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003747RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 NoHandleAllocation ha;
3749 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003750 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003751 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003753 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003754 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003755 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003756 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003757 // Character array used for conversion.
3758 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return isolate->heap()->
3760 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003761 }
3762 }
3763
3764 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003765 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003767 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003768 }
3769 if (isinf(value)) {
3770 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003771 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003773 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003775 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003776 MaybeObject* result =
3777 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003778 DeleteArray(str);
3779 return result;
3780}
3781
3782
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003783RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003784 NoHandleAllocation ha;
3785 ASSERT(args.length() == 2);
3786
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003787 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003789 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003790 }
3791 if (isinf(value)) {
3792 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003794 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003795 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003796 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003797 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 int f = FastD2I(f_number);
3799 RUNTIME_ASSERT(f >= 0);
3800 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801 MaybeObject* res =
3802 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003803 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003804 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805}
3806
3807
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003808RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003809 NoHandleAllocation ha;
3810 ASSERT(args.length() == 2);
3811
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003812 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003813 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003814 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003815 }
3816 if (isinf(value)) {
3817 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003818 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003820 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003821 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003822 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003823 int f = FastD2I(f_number);
3824 RUNTIME_ASSERT(f >= -1 && f <= 20);
3825 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003826 MaybeObject* res =
3827 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003829 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830}
3831
3832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003833RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003834 NoHandleAllocation ha;
3835 ASSERT(args.length() == 2);
3836
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003837 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003839 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003840 }
3841 if (isinf(value)) {
3842 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003843 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003844 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003845 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003846 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003847 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003848 int f = FastD2I(f_number);
3849 RUNTIME_ASSERT(f >= 1 && f <= 21);
3850 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003851 MaybeObject* res =
3852 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003854 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003855}
3856
3857
3858// Returns a single character string where first character equals
3859// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003860static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003861 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003862 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003863 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003864 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003866 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003867}
3868
3869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003870MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3871 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003872 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003873 // Handle [] indexing on Strings
3874 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003875 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3876 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003877 }
3878
3879 // Handle [] indexing on String objects
3880 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003881 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3882 Handle<Object> result =
3883 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3884 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003885 }
3886
3887 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003888 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889 return prototype->GetElement(index);
3890 }
3891
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003892 return GetElement(object, index);
3893}
3894
3895
lrn@chromium.org303ada72010-10-27 09:33:13 +00003896MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003897 return object->GetElement(index);
3898}
3899
3900
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003901MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3902 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003903 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003904 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003905
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003906 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003907 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003908 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 isolate->factory()->NewTypeError("non_object_property_load",
3910 HandleVector(args, 2));
3911 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003912 }
3913
3914 // Check if the given key is an array index.
3915 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003916 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003917 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918 }
3919
3920 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003921 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003922 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003923 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003924 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003925 bool has_pending_exception = false;
3926 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003927 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003929 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003930 }
3931
ager@chromium.org32912102009-01-16 10:38:43 +00003932 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003933 // the element if so.
3934 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003935 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003936 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003937 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 }
3939}
3940
3941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003942RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003943 NoHandleAllocation ha;
3944 ASSERT(args.length() == 2);
3945
3946 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003947 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003949 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003950}
3951
3952
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003953// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003954RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003955 NoHandleAllocation ha;
3956 ASSERT(args.length() == 2);
3957
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003958 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003959 // itself.
3960 //
3961 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003962 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003963 // global proxy object never has properties. This is the case
3964 // because the global proxy object forwards everything to its hidden
3965 // prototype including local lookups.
3966 //
3967 // Additionally, we need to make sure that we do not cache results
3968 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003969 if (args[0]->IsJSObject() &&
3970 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003971 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003972 args[1]->IsString()) {
3973 JSObject* receiver = JSObject::cast(args[0]);
3974 String* key = String::cast(args[1]);
3975 if (receiver->HasFastProperties()) {
3976 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003977 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003978 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3979 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003980 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003981 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003983 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003984 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003985 LookupResult result;
3986 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003987 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003988 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003989 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003990 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003991 }
3992 } else {
3993 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003994 StringDictionary* dictionary = receiver->property_dictionary();
3995 int entry = dictionary->FindEntry(key);
3996 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003997 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003998 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003999 if (!receiver->IsGlobalObject()) return value;
4000 value = JSGlobalPropertyCell::cast(value)->value();
4001 if (!value->IsTheHole()) return value;
4002 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004003 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004004 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004005 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4006 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004008 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004009 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004010 if (index >= 0 && index < str->length()) {
4011 Handle<Object> result = GetCharAt(str, index);
4012 return *result;
4013 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004014 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004015
4016 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004017 return Runtime::GetObjectProperty(isolate,
4018 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004019 args.at<Object>(1));
4020}
4021
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004022// Implements part of 8.12.9 DefineOwnProperty.
4023// There are 3 cases that lead here:
4024// Step 4b - define a new accessor property.
4025// Steps 9c & 12 - replace an existing data property with an accessor property.
4026// Step 12 - update an existing accessor property with an accessor or generic
4027// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004028RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004029 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004031 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4032 CONVERT_CHECKED(String, name, args[1]);
4033 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004034 Object* fun = args[3];
4035 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004036 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4037 int unchecked = flag_attr->value();
4038 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4039 RUNTIME_ASSERT(!obj->IsNull());
4040 LookupResult result;
4041 obj->LocalLookupRealNamedProperty(name, &result);
4042
4043 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4044 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4045 // delete it to avoid running into trouble in DefineAccessor, which
4046 // handles this incorrectly if the property is readonly (does nothing)
4047 if (result.IsProperty() &&
4048 (result.type() == FIELD || result.type() == NORMAL
4049 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004050 Object* ok;
4051 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004052 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004053 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4054 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004055 }
4056 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4057}
4058
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004059// Implements part of 8.12.9 DefineOwnProperty.
4060// There are 3 cases that lead here:
4061// Step 4a - define a new data property.
4062// Steps 9b & 12 - replace an existing accessor property with a data property.
4063// Step 12 - update an existing data property with a data or generic
4064// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004065RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004066 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004067 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004068 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4069 CONVERT_ARG_CHECKED(String, name, 1);
4070 Handle<Object> obj_value = args.at<Object>(2);
4071
4072 CONVERT_CHECKED(Smi, flag, args[3]);
4073 int unchecked = flag->value();
4074 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4075
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004076 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4077
4078 // Check if this is an element.
4079 uint32_t index;
4080 bool is_element = name->AsArrayIndex(&index);
4081
4082 // Special case for elements if any of the flags are true.
4083 // If elements are in fast case we always implicitly assume that:
4084 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4085 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4086 is_element) {
4087 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004088 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004089 // We do not need to do access checks here since these has already
4090 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004091 Handle<Object> proto(js_object->GetPrototype());
4092 // If proxy is detached, ignore the assignment. Alternatively,
4093 // we could throw an exception.
4094 if (proto->IsNull()) return *obj_value;
4095 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004096 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004097 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004098 // Make sure that we never go back to fast case.
4099 dictionary->set_requires_slow_elements();
4100 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004101 Handle<NumberDictionary> extended_dictionary =
4102 NumberDictionarySet(dictionary, index, obj_value, details);
4103 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004104 if (js_object->GetElementsKind() ==
4105 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4106 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4107 } else {
4108 js_object->set_elements(*extended_dictionary);
4109 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004110 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004111 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004112 }
4113
ager@chromium.org5c838252010-02-19 08:53:10 +00004114 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004115 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004116
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004117 // To be compatible with safari we do not change the value on API objects
4118 // in defineProperty. Firefox disagrees here, and actually changes the value.
4119 if (result.IsProperty() &&
4120 (result.type() == CALLBACKS) &&
4121 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004122 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004123 }
4124
ager@chromium.org5c838252010-02-19 08:53:10 +00004125 // Take special care when attributes are different and there is already
4126 // a property. For simplicity we normalize the property which enables us
4127 // to not worry about changing the instance_descriptor and creating a new
4128 // map. The current version of SetObjectProperty does not handle attributes
4129 // correctly in the case where a property is a field and is reset with
4130 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004131 if (result.IsProperty() &&
4132 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004133 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004134 if (js_object->IsJSGlobalProxy()) {
4135 // Since the result is a property, the prototype will exist so
4136 // we don't have to check for null.
4137 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004138 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004139 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004140 // Use IgnoreAttributes version since a readonly property may be
4141 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004142 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4143 *obj_value,
4144 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004145 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004147 return Runtime::ForceSetObjectProperty(isolate,
4148 js_object,
4149 name,
4150 obj_value,
4151 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004152}
4153
4154
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004155// Special case for elements if any of the flags are true.
4156// If elements are in fast case we always implicitly assume that:
4157// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4158static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4159 Handle<JSObject> js_object,
4160 uint32_t index,
4161 Handle<Object> value,
4162 PropertyAttributes attr) {
4163 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004164 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004165 // Make sure that we never go back to fast case.
4166 dictionary->set_requires_slow_elements();
4167 PropertyDetails details = PropertyDetails(attr, NORMAL);
4168 Handle<NumberDictionary> extended_dictionary =
4169 NumberDictionarySet(dictionary, index, value, details);
4170 if (*extended_dictionary != *dictionary) {
4171 js_object->set_elements(*extended_dictionary);
4172 }
4173 return *value;
4174}
4175
4176
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4178 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004179 Handle<Object> key,
4180 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004181 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004182 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004184
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004186 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004188 isolate->factory()->NewTypeError("non_object_property_store",
4189 HandleVector(args, 2));
4190 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 }
4192
4193 // If the object isn't a JavaScript object, we ignore the store.
4194 if (!object->IsJSObject()) return *value;
4195
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4197
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004198 // Check if the given key is an array index.
4199 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004200 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4202 // of a string using [] notation. We need to support this too in
4203 // JavaScript.
4204 // In the case of a String object we just need to redirect the assignment to
4205 // the underlying string if the index is in range. Since the underlying
4206 // string does nothing with the assignment then we can ignore such
4207 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004208 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004212 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4213 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4214 }
4215
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004216 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004217 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 return *value;
4219 }
4220
4221 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004222 Handle<Object> result;
4223 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004224 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4225 return NormalizeObjectSetElement(isolate,
4226 js_object,
4227 index,
4228 value,
4229 attr);
4230 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004231 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004233 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004234 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004235 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004236 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004237 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004238 return *value;
4239 }
4240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242 bool has_pending_exception = false;
4243 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4244 if (has_pending_exception) return Failure::Exception();
4245 Handle<String> name = Handle<String>::cast(converted);
4246
4247 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004248 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004249 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004250 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004251 }
4252}
4253
4254
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004255MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4256 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004257 Handle<Object> key,
4258 Handle<Object> value,
4259 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004260 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004261
4262 // Check if the given key is an array index.
4263 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004264 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004265 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4266 // of a string using [] notation. We need to support this too in
4267 // JavaScript.
4268 // In the case of a String object we just need to redirect the assignment to
4269 // the underlying string if the index is in range. Since the underlying
4270 // string does nothing with the assignment then we can ignore such
4271 // assignments.
4272 if (js_object->IsStringObjectWithCharacterAt(index)) {
4273 return *value;
4274 }
4275
whesse@chromium.org7b260152011-06-20 15:33:18 +00004276 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004277 }
4278
4279 if (key->IsString()) {
4280 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004281 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004282 } else {
4283 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004284 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004285 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4286 *value,
4287 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004288 }
4289 }
4290
4291 // Call-back into JavaScript to convert the key to a string.
4292 bool has_pending_exception = false;
4293 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4294 if (has_pending_exception) return Failure::Exception();
4295 Handle<String> name = Handle<String>::cast(converted);
4296
4297 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004298 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004299 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004300 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004301 }
4302}
4303
4304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004305MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004306 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004307 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004308 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004309
4310 // Check if the given key is an array index.
4311 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004312 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004313 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4314 // characters of a string using [] notation. In the case of a
4315 // String object we just need to redirect the deletion to the
4316 // underlying string if the index is in range. Since the
4317 // underlying string does nothing with the deletion, we can ignore
4318 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004319 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004321 }
4322
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004323 return JSObject::cast(*receiver)->DeleteElement(
4324 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004325 }
4326
4327 Handle<String> key_string;
4328 if (key->IsString()) {
4329 key_string = Handle<String>::cast(key);
4330 } else {
4331 // Call-back into JavaScript to convert the key to a string.
4332 bool has_pending_exception = false;
4333 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4334 if (has_pending_exception) return Failure::Exception();
4335 key_string = Handle<String>::cast(converted);
4336 }
4337
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004338 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004339 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004340}
4341
4342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004343RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004344 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004345 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346
4347 Handle<Object> object = args.at<Object>(0);
4348 Handle<Object> key = args.at<Object>(1);
4349 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004350 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004351 RUNTIME_ASSERT(
4352 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004353 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004354 PropertyAttributes attributes =
4355 static_cast<PropertyAttributes>(unchecked_attributes);
4356
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004357 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004358 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004359 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004360 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4361 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004362 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004363 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004365 return Runtime::SetObjectProperty(isolate,
4366 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004367 key,
4368 value,
4369 attributes,
4370 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004371}
4372
4373
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004374// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004375// This is used to decide if we should transform null and undefined
4376// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004377RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004378 NoHandleAllocation ha;
4379 RUNTIME_ASSERT(args.length() == 1);
4380
4381 Handle<Object> object = args.at<Object>(0);
4382
4383 if (object->IsJSFunction()) {
4384 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004385 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004386 }
4387 return isolate->heap()->undefined_value();
4388}
4389
4390
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004391// Set a local property, even if it is READ_ONLY. If the property does not
4392// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004393RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004394 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004395 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004396 CONVERT_CHECKED(JSObject, object, args[0]);
4397 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004398 // Compute attributes.
4399 PropertyAttributes attributes = NONE;
4400 if (args.length() == 4) {
4401 CONVERT_CHECKED(Smi, value_obj, args[3]);
4402 int unchecked_value = value_obj->value();
4403 // Only attribute bits should be set.
4404 RUNTIME_ASSERT(
4405 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4406 attributes = static_cast<PropertyAttributes>(unchecked_value);
4407 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004409 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004410 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004411}
4412
4413
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004414RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004415 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004416 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004417
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004418 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004419 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004420 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004421 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004422 ? JSReceiver::STRICT_DELETION
4423 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004424}
4425
4426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004427static Object* HasLocalPropertyImplementation(Isolate* isolate,
4428 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004429 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004431 // Handle hidden prototypes. If there's a hidden prototype above this thing
4432 // then we have to check it for properties, because they are supposed to
4433 // look like they are on this object.
4434 Handle<Object> proto(object->GetPrototype());
4435 if (proto->IsJSObject() &&
4436 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004437 return HasLocalPropertyImplementation(isolate,
4438 Handle<JSObject>::cast(proto),
4439 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004440 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004441 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004442}
4443
4444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004445RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 NoHandleAllocation ha;
4447 ASSERT(args.length() == 2);
4448 CONVERT_CHECKED(String, key, args[1]);
4449
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004450 uint32_t index;
4451 const bool key_is_array_index = key->AsArrayIndex(&index);
4452
ager@chromium.org9085a012009-05-11 19:22:57 +00004453 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004454 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004455 if (obj->IsJSObject()) {
4456 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004457 // Fast case: either the key is a real named property or it is not
4458 // an array index and there are no interceptors or hidden
4459 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004460 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004461 Map* map = object->map();
4462 if (!key_is_array_index &&
4463 !map->has_named_interceptor() &&
4464 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4465 return isolate->heap()->false_value();
4466 }
4467 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004468 HandleScope scope(isolate);
4469 return HasLocalPropertyImplementation(isolate,
4470 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004471 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004472 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004474 String* string = String::cast(obj);
4475 if (index < static_cast<uint32_t>(string->length())) {
4476 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004477 }
4478 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004480}
4481
4482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004483RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 NoHandleAllocation na;
4485 ASSERT(args.length() == 2);
4486
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004487 // Only JS receivers can have properties.
4488 if (args[0]->IsJSReceiver()) {
4489 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004491 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004493 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494}
4495
4496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004497RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004498 NoHandleAllocation na;
4499 ASSERT(args.length() == 2);
4500
4501 // Only JS objects can have elements.
4502 if (args[0]->IsJSObject()) {
4503 JSObject* object = JSObject::cast(args[0]);
4504 CONVERT_CHECKED(Smi, index_obj, args[1]);
4505 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004506 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004508 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004509}
4510
4511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004512RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513 NoHandleAllocation ha;
4514 ASSERT(args.length() == 2);
4515
4516 CONVERT_CHECKED(JSObject, object, args[0]);
4517 CONVERT_CHECKED(String, key, args[1]);
4518
4519 uint32_t index;
4520 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004521 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004522 }
4523
ager@chromium.org870a0b62008-11-04 11:43:05 +00004524 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004525 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004526}
4527
4528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004529RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004530 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004531 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004532 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004533 return *GetKeysFor(object);
4534}
4535
4536
4537// Returns either a FixedArray as Runtime_GetPropertyNames,
4538// or, if the given object has an enum cache that contains
4539// all enumerable properties of the object and its prototypes
4540// have none, the map of the object. This is used to speed up
4541// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004542RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543 ASSERT(args.length() == 1);
4544
4545 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4546
4547 if (raw_object->IsSimpleEnum()) return raw_object->map();
4548
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004549 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004551 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4552 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553
4554 // Test again, since cache may have been built by preceding call.
4555 if (object->IsSimpleEnum()) return object->map();
4556
4557 return *content;
4558}
4559
4560
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004561// Find the length of the prototype chain that is to to handled as one. If a
4562// prototype object is hidden it is to be viewed as part of the the object it
4563// is prototype for.
4564static int LocalPrototypeChainLength(JSObject* obj) {
4565 int count = 1;
4566 Object* proto = obj->GetPrototype();
4567 while (proto->IsJSObject() &&
4568 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4569 count++;
4570 proto = JSObject::cast(proto)->GetPrototype();
4571 }
4572 return count;
4573}
4574
4575
4576// Return the names of the local named properties.
4577// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004578RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004579 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004580 ASSERT(args.length() == 1);
4581 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004582 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004583 }
4584 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4585
4586 // Skip the global proxy as it has no properties and always delegates to the
4587 // real global object.
4588 if (obj->IsJSGlobalProxy()) {
4589 // Only collect names if access is permitted.
4590 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004591 !isolate->MayNamedAccess(*obj,
4592 isolate->heap()->undefined_value(),
4593 v8::ACCESS_KEYS)) {
4594 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4595 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004596 }
4597 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4598 }
4599
4600 // Find the number of objects making up this.
4601 int length = LocalPrototypeChainLength(*obj);
4602
4603 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004604 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004605 int total_property_count = 0;
4606 Handle<JSObject> jsproto = obj;
4607 for (int i = 0; i < length; i++) {
4608 // Only collect names if access is permitted.
4609 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004610 !isolate->MayNamedAccess(*jsproto,
4611 isolate->heap()->undefined_value(),
4612 v8::ACCESS_KEYS)) {
4613 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4614 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004615 }
4616 int n;
4617 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4618 local_property_count[i] = n;
4619 total_property_count += n;
4620 if (i < length - 1) {
4621 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4622 }
4623 }
4624
4625 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004626 Handle<FixedArray> names =
4627 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004628
4629 // Get the property names.
4630 jsproto = obj;
4631 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004632 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004633 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004634 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4635 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004636 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004637 proto_with_hidden_properties++;
4638 }
4639 if (i < length - 1) {
4640 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4641 }
4642 }
4643
4644 // Filter out name of hidden propeties object.
4645 if (proto_with_hidden_properties > 0) {
4646 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004647 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004648 names->length() - proto_with_hidden_properties);
4649 int dest_pos = 0;
4650 for (int i = 0; i < total_property_count; i++) {
4651 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004652 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004653 continue;
4654 }
4655 names->set(dest_pos++, name);
4656 }
4657 }
4658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004659 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004660}
4661
4662
4663// Return the names of the local indexed properties.
4664// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004665RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004666 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004667 ASSERT(args.length() == 1);
4668 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004669 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004670 }
4671 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4672
4673 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004674 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004675 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004676 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004677}
4678
4679
4680// Return information on whether an object has a named or indexed interceptor.
4681// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004682RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004683 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004684 ASSERT(args.length() == 1);
4685 if (!args[0]->IsJSObject()) {
4686 return Smi::FromInt(0);
4687 }
4688 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4689
4690 int result = 0;
4691 if (obj->HasNamedInterceptor()) result |= 2;
4692 if (obj->HasIndexedInterceptor()) result |= 1;
4693
4694 return Smi::FromInt(result);
4695}
4696
4697
4698// Return property names from named interceptor.
4699// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004700RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004701 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004702 ASSERT(args.length() == 1);
4703 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4704
4705 if (obj->HasNamedInterceptor()) {
4706 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4707 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4708 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004710}
4711
4712
4713// Return element names from indexed interceptor.
4714// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004716 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004717 ASSERT(args.length() == 1);
4718 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4719
4720 if (obj->HasIndexedInterceptor()) {
4721 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4722 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4723 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004724 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004725}
4726
4727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004728RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004729 ASSERT_EQ(args.length(), 1);
4730 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004731 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004732 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004733
4734 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004735 // Do access checks before going to the global object.
4736 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004738 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004739 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4740 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004741 }
4742
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004743 Handle<Object> proto(object->GetPrototype());
4744 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004746 object = Handle<JSObject>::cast(proto);
4747 }
4748
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004749 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4750 LOCAL_ONLY);
4751 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4752 // property array and since the result is mutable we have to create
4753 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004754 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004756 for (int i = 0; i < length; i++) {
4757 Object* entry = contents->get(i);
4758 if (entry->IsString()) {
4759 copy->set(i, entry);
4760 } else {
4761 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004762 HandleScope scope(isolate);
4763 Handle<Object> entry_handle(entry, isolate);
4764 Handle<Object> entry_str =
4765 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004766 copy->set(i, *entry_str);
4767 }
4768 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004770}
4771
4772
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004773RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774 NoHandleAllocation ha;
4775 ASSERT(args.length() == 1);
4776
4777 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004778 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004779 it.AdvanceToArgumentsFrame();
4780 JavaScriptFrame* frame = it.frame();
4781
4782 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004783 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784
4785 // Try to convert the key to an index. If successful and within
4786 // index return the the argument from the frame.
4787 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004788 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789 return frame->GetParameter(index);
4790 }
4791
4792 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794 bool exception = false;
4795 Handle<Object> converted =
4796 Execution::ToString(args.at<Object>(0), &exception);
4797 if (exception) return Failure::Exception();
4798 Handle<String> key = Handle<String>::cast(converted);
4799
4800 // Try to convert the string key into an array index.
4801 if (key->AsArrayIndex(&index)) {
4802 if (index < n) {
4803 return frame->GetParameter(index);
4804 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004805 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004806 }
4807 }
4808
4809 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004810 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4811 if (key->Equals(isolate->heap()->callee_symbol())) {
4812 Object* function = frame->function();
4813 if (function->IsJSFunction() &&
4814 JSFunction::cast(function)->shared()->strict_mode()) {
4815 return isolate->Throw(*isolate->factory()->NewTypeError(
4816 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4817 }
4818 return function;
4819 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820
4821 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004822 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823}
4824
4825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004826RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004827 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004828
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004829 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004830 Handle<Object> object = args.at<Object>(0);
4831 if (object->IsJSObject()) {
4832 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004833 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004834 MaybeObject* ok = js_object->TransformToFastProperties(0);
4835 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004836 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004837 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004838 return *object;
4839}
4840
4841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004842RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004843 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004844
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004845 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004846 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004847 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004848 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004849 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004850 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004851 return *object;
4852}
4853
4854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004855RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856 NoHandleAllocation ha;
4857 ASSERT(args.length() == 1);
4858
4859 return args[0]->ToBoolean();
4860}
4861
4862
4863// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4864// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004865RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 NoHandleAllocation ha;
4867
4868 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870 HeapObject* heap_obj = HeapObject::cast(obj);
4871
4872 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004873 if (heap_obj->map()->is_undetectable()) {
4874 return isolate->heap()->undefined_symbol();
4875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004876
4877 InstanceType instance_type = heap_obj->map()->instance_type();
4878 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004879 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004880 }
4881
4882 switch (instance_type) {
4883 case ODDBALL_TYPE:
4884 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004885 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886 }
4887 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004888 return FLAG_harmony_typeof
4889 ? isolate->heap()->null_symbol()
4890 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004891 }
4892 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004893 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004894 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004895 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896 default:
4897 // For any kind of object not handled above, the spec rule for
4898 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004899 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004900 }
4901}
4902
4903
lrn@chromium.org25156de2010-04-06 13:10:27 +00004904static bool AreDigits(const char*s, int from, int to) {
4905 for (int i = from; i < to; i++) {
4906 if (s[i] < '0' || s[i] > '9') return false;
4907 }
4908
4909 return true;
4910}
4911
4912
4913static int ParseDecimalInteger(const char*s, int from, int to) {
4914 ASSERT(to - from < 10); // Overflow is not possible.
4915 ASSERT(from < to);
4916 int d = s[from] - '0';
4917
4918 for (int i = from + 1; i < to; i++) {
4919 d = 10 * d + (s[i] - '0');
4920 }
4921
4922 return d;
4923}
4924
4925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004926RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927 NoHandleAllocation ha;
4928 ASSERT(args.length() == 1);
4929 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004930 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004931
4932 // Fast case: short integer or some sorts of junk values.
4933 int len = subject->length();
4934 if (subject->IsSeqAsciiString()) {
4935 if (len == 0) return Smi::FromInt(0);
4936
4937 char const* data = SeqAsciiString::cast(subject)->GetChars();
4938 bool minus = (data[0] == '-');
4939 int start_pos = (minus ? 1 : 0);
4940
4941 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004942 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004943 } else if (data[start_pos] > '9') {
4944 // Fast check for a junk value. A valid string may start from a
4945 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4946 // the 'I' character ('Infinity'). All of that have codes not greater than
4947 // '9' except 'I'.
4948 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004949 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004950 }
4951 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4952 // The maximal/minimal smi has 10 digits. If the string has less digits we
4953 // know it will fit into the smi-data type.
4954 int d = ParseDecimalInteger(data, start_pos, len);
4955 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004956 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004957 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004958 } else if (!subject->HasHashCode() &&
4959 len <= String::kMaxArrayIndexSize &&
4960 (len == 1 || data[0] != '0')) {
4961 // String hash is not calculated yet but all the data are present.
4962 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004963 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004964#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004965 subject->Hash(); // Force hash calculation.
4966 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4967 static_cast<int>(hash));
4968#endif
4969 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004970 }
4971 return Smi::FromInt(d);
4972 }
4973 }
4974
4975 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004976 return isolate->heap()->NumberFromDouble(
4977 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004978}
4979
4980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004981RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004982 NoHandleAllocation ha;
4983 ASSERT(args.length() == 1);
4984
4985 CONVERT_CHECKED(JSArray, codes, args[0]);
4986 int length = Smi::cast(codes->length())->value();
4987
4988 // Check if the string can be ASCII.
4989 int i;
4990 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004991 Object* element;
4992 { MaybeObject* maybe_element = codes->GetElement(i);
4993 // We probably can't get an exception here, but just in order to enforce
4994 // the checking of inputs in the runtime calls we check here.
4995 if (!maybe_element->ToObject(&element)) return maybe_element;
4996 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004997 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4998 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4999 break;
5000 }
5001
lrn@chromium.org303ada72010-10-27 09:33:13 +00005002 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005003 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005004 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005006 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005007 }
5008
lrn@chromium.org303ada72010-10-27 09:33:13 +00005009 Object* object = NULL;
5010 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 String* result = String::cast(object);
5012 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005013 Object* element;
5014 { MaybeObject* maybe_element = codes->GetElement(i);
5015 if (!maybe_element->ToObject(&element)) return maybe_element;
5016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005017 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005018 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005019 }
5020 return result;
5021}
5022
5023
5024// kNotEscaped is generated by the following:
5025//
5026// #!/bin/perl
5027// for (my $i = 0; $i < 256; $i++) {
5028// print "\n" if $i % 16 == 0;
5029// my $c = chr($i);
5030// my $escaped = 1;
5031// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5032// print $escaped ? "0, " : "1, ";
5033// }
5034
5035
5036static bool IsNotEscaped(uint16_t character) {
5037 // Only for 8 bit characters, the rest are always escaped (in a different way)
5038 ASSERT(character < 256);
5039 static const char kNotEscaped[256] = {
5040 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5041 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5043 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5044 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5045 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5046 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5047 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5048 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5049 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5050 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5051 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5052 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5053 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5054 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5055 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5056 };
5057 return kNotEscaped[character] != 0;
5058}
5059
5060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005061RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005062 const char hex_chars[] = "0123456789ABCDEF";
5063 NoHandleAllocation ha;
5064 ASSERT(args.length() == 1);
5065 CONVERT_CHECKED(String, source, args[0]);
5066
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005067 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005068
5069 int escaped_length = 0;
5070 int length = source->length();
5071 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 Access<StringInputBuffer> buffer(
5073 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005074 buffer->Reset(source);
5075 while (buffer->has_more()) {
5076 uint16_t character = buffer->GetNext();
5077 if (character >= 256) {
5078 escaped_length += 6;
5079 } else if (IsNotEscaped(character)) {
5080 escaped_length++;
5081 } else {
5082 escaped_length += 3;
5083 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005084 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005085 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005086 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005088 return Failure::OutOfMemoryException();
5089 }
5090 }
5091 }
5092 // No length change implies no change. Return original string if no change.
5093 if (escaped_length == length) {
5094 return source;
5095 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005096 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005097 { MaybeObject* maybe_o =
5098 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005099 if (!maybe_o->ToObject(&o)) return maybe_o;
5100 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005101 String* destination = String::cast(o);
5102 int dest_position = 0;
5103
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005104 Access<StringInputBuffer> buffer(
5105 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005106 buffer->Rewind();
5107 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005108 uint16_t chr = buffer->GetNext();
5109 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005110 destination->Set(dest_position, '%');
5111 destination->Set(dest_position+1, 'u');
5112 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5113 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5114 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5115 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005116 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005117 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005118 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005119 dest_position++;
5120 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005121 destination->Set(dest_position, '%');
5122 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5123 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124 dest_position += 3;
5125 }
5126 }
5127 return destination;
5128}
5129
5130
5131static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5132 static const signed char kHexValue['g'] = {
5133 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5134 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5135 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5136 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5137 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5138 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5139 -1, 10, 11, 12, 13, 14, 15 };
5140
5141 if (character1 > 'f') return -1;
5142 int hi = kHexValue[character1];
5143 if (hi == -1) return -1;
5144 if (character2 > 'f') return -1;
5145 int lo = kHexValue[character2];
5146 if (lo == -1) return -1;
5147 return (hi << 4) + lo;
5148}
5149
5150
ager@chromium.org870a0b62008-11-04 11:43:05 +00005151static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005152 int i,
5153 int length,
5154 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005155 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005156 int32_t hi = 0;
5157 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005158 if (character == '%' &&
5159 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005160 source->Get(i + 1) == 'u' &&
5161 (hi = TwoDigitHex(source->Get(i + 2),
5162 source->Get(i + 3))) != -1 &&
5163 (lo = TwoDigitHex(source->Get(i + 4),
5164 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005165 *step = 6;
5166 return (hi << 8) + lo;
5167 } else if (character == '%' &&
5168 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005169 (lo = TwoDigitHex(source->Get(i + 1),
5170 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005171 *step = 3;
5172 return lo;
5173 } else {
5174 *step = 1;
5175 return character;
5176 }
5177}
5178
5179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005180RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181 NoHandleAllocation ha;
5182 ASSERT(args.length() == 1);
5183 CONVERT_CHECKED(String, source, args[0]);
5184
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005185 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186
5187 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005188 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005189
5190 int unescaped_length = 0;
5191 for (int i = 0; i < length; unescaped_length++) {
5192 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005193 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005194 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 i += step;
5197 }
5198
5199 // No length change implies no change. Return original string if no change.
5200 if (unescaped_length == length)
5201 return source;
5202
lrn@chromium.org303ada72010-10-27 09:33:13 +00005203 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 { MaybeObject* maybe_o =
5205 ascii ?
5206 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5207 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005208 if (!maybe_o->ToObject(&o)) return maybe_o;
5209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005210 String* destination = String::cast(o);
5211
5212 int dest_position = 0;
5213 for (int i = 0; i < length; dest_position++) {
5214 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005215 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216 i += step;
5217 }
5218 return destination;
5219}
5220
5221
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005222static const unsigned int kQuoteTableLength = 128u;
5223
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005224static const int kJsonQuotesCharactersPerEntry = 8;
5225static const char* const JsonQuotes =
5226 "\\u0000 \\u0001 \\u0002 \\u0003 "
5227 "\\u0004 \\u0005 \\u0006 \\u0007 "
5228 "\\b \\t \\n \\u000b "
5229 "\\f \\r \\u000e \\u000f "
5230 "\\u0010 \\u0011 \\u0012 \\u0013 "
5231 "\\u0014 \\u0015 \\u0016 \\u0017 "
5232 "\\u0018 \\u0019 \\u001a \\u001b "
5233 "\\u001c \\u001d \\u001e \\u001f "
5234 " ! \\\" # "
5235 "$ % & ' "
5236 "( ) * + "
5237 ", - . / "
5238 "0 1 2 3 "
5239 "4 5 6 7 "
5240 "8 9 : ; "
5241 "< = > ? "
5242 "@ A B C "
5243 "D E F G "
5244 "H I J K "
5245 "L M N O "
5246 "P Q R S "
5247 "T U V W "
5248 "X Y Z [ "
5249 "\\\\ ] ^ _ "
5250 "` a b c "
5251 "d e f g "
5252 "h i j k "
5253 "l m n o "
5254 "p q r s "
5255 "t u v w "
5256 "x y z { "
5257 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005258
5259
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005260// For a string that is less than 32k characters it should always be
5261// possible to allocate it in new space.
5262static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5263
5264
5265// Doing JSON quoting cannot make the string more than this many times larger.
5266static const int kJsonQuoteWorstCaseBlowup = 6;
5267
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005268static const int kSpaceForQuotesAndComma = 3;
5269static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005270
5271// Covers the entire ASCII range (all other characters are unchanged by JSON
5272// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005273static const byte JsonQuoteLengths[kQuoteTableLength] = {
5274 6, 6, 6, 6, 6, 6, 6, 6,
5275 2, 2, 2, 6, 2, 2, 6, 6,
5276 6, 6, 6, 6, 6, 6, 6, 6,
5277 6, 6, 6, 6, 6, 6, 6, 6,
5278 1, 1, 2, 1, 1, 1, 1, 1,
5279 1, 1, 1, 1, 1, 1, 1, 1,
5280 1, 1, 1, 1, 1, 1, 1, 1,
5281 1, 1, 1, 1, 1, 1, 1, 1,
5282 1, 1, 1, 1, 1, 1, 1, 1,
5283 1, 1, 1, 1, 1, 1, 1, 1,
5284 1, 1, 1, 1, 1, 1, 1, 1,
5285 1, 1, 1, 1, 2, 1, 1, 1,
5286 1, 1, 1, 1, 1, 1, 1, 1,
5287 1, 1, 1, 1, 1, 1, 1, 1,
5288 1, 1, 1, 1, 1, 1, 1, 1,
5289 1, 1, 1, 1, 1, 1, 1, 1,
5290};
5291
5292
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005293template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005294MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005295
5296
5297template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005298MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5299 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005300}
5301
5302
5303template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005304MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5305 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005306}
5307
5308
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005309template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005310static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5311 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005312 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005313 const Char* read_cursor = characters.start();
5314 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005315 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005316 int quoted_length = kSpaceForQuotes;
5317 while (read_cursor < end) {
5318 Char c = *(read_cursor++);
5319 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5320 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005321 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005322 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005323 }
5324 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005325 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5326 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005327 Object* new_object;
5328 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005329 return new_alloc;
5330 }
5331 StringType* new_string = StringType::cast(new_object);
5332
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005333 Char* write_cursor = reinterpret_cast<Char*>(
5334 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005335 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005336 *(write_cursor++) = '"';
5337
5338 read_cursor = characters.start();
5339 while (read_cursor < end) {
5340 Char c = *(read_cursor++);
5341 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5342 *(write_cursor++) = c;
5343 } else {
5344 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5345 const char* replacement = JsonQuotes +
5346 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5347 for (int i = 0; i < len; i++) {
5348 *write_cursor++ = *replacement++;
5349 }
5350 }
5351 }
5352 *(write_cursor++) = '"';
5353 return new_string;
5354}
5355
5356
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005357template <typename SinkChar, typename SourceChar>
5358static inline SinkChar* WriteQuoteJsonString(
5359 Isolate* isolate,
5360 SinkChar* write_cursor,
5361 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005362 // SinkChar is only char if SourceChar is guaranteed to be char.
5363 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005364 const SourceChar* read_cursor = characters.start();
5365 const SourceChar* end = read_cursor + characters.length();
5366 *(write_cursor++) = '"';
5367 while (read_cursor < end) {
5368 SourceChar c = *(read_cursor++);
5369 if (sizeof(SourceChar) > 1u &&
5370 static_cast<unsigned>(c) >= kQuoteTableLength) {
5371 *(write_cursor++) = static_cast<SinkChar>(c);
5372 } else {
5373 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5374 const char* replacement = JsonQuotes +
5375 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5376 write_cursor[0] = replacement[0];
5377 if (len > 1) {
5378 write_cursor[1] = replacement[1];
5379 if (len > 2) {
5380 ASSERT(len == 6);
5381 write_cursor[2] = replacement[2];
5382 write_cursor[3] = replacement[3];
5383 write_cursor[4] = replacement[4];
5384 write_cursor[5] = replacement[5];
5385 }
5386 }
5387 write_cursor += len;
5388 }
5389 }
5390 *(write_cursor++) = '"';
5391 return write_cursor;
5392}
5393
5394
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005395template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005396static MaybeObject* QuoteJsonString(Isolate* isolate,
5397 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005398 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005399 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005400 int worst_case_length =
5401 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005402 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005403 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005404 }
5405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005406 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5407 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005408 Object* new_object;
5409 if (!new_alloc->ToObject(&new_object)) {
5410 return new_alloc;
5411 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005412 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005413 // Even if our string is small enough to fit in new space we still have to
5414 // handle it being allocated in old space as may happen in the third
5415 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5416 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005417 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005418 }
5419 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005420 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005421
5422 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5423 Char* write_cursor = reinterpret_cast<Char*>(
5424 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005425 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005426 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5427 write_cursor,
5428 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005429 int final_length = static_cast<int>(
5430 write_cursor - reinterpret_cast<Char*>(
5431 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005432 isolate->heap()->new_space()->
5433 template ShrinkStringAtAllocationBoundary<StringType>(
5434 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005435 return new_string;
5436}
5437
5438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005439RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005440 NoHandleAllocation ha;
5441 CONVERT_CHECKED(String, str, args[0]);
5442 if (!str->IsFlat()) {
5443 MaybeObject* try_flatten = str->TryFlatten();
5444 Object* flat;
5445 if (!try_flatten->ToObject(&flat)) {
5446 return try_flatten;
5447 }
5448 str = String::cast(flat);
5449 ASSERT(str->IsFlat());
5450 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005451 String::FlatContent flat = str->GetFlatContent();
5452 ASSERT(flat.IsFlat());
5453 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005454 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005455 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005456 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005457 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005458 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005459 }
5460}
5461
5462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005463RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005464 NoHandleAllocation ha;
5465 CONVERT_CHECKED(String, str, args[0]);
5466 if (!str->IsFlat()) {
5467 MaybeObject* try_flatten = str->TryFlatten();
5468 Object* flat;
5469 if (!try_flatten->ToObject(&flat)) {
5470 return try_flatten;
5471 }
5472 str = String::cast(flat);
5473 ASSERT(str->IsFlat());
5474 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005475 String::FlatContent flat = str->GetFlatContent();
5476 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005477 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005478 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005479 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005480 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005481 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005482 }
5483}
5484
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005485
5486template <typename Char, typename StringType>
5487static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5488 FixedArray* array,
5489 int worst_case_length) {
5490 int length = array->length();
5491
5492 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5493 worst_case_length);
5494 Object* new_object;
5495 if (!new_alloc->ToObject(&new_object)) {
5496 return new_alloc;
5497 }
5498 if (!isolate->heap()->new_space()->Contains(new_object)) {
5499 // Even if our string is small enough to fit in new space we still have to
5500 // handle it being allocated in old space as may happen in the third
5501 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5502 // CEntryStub::GenerateCore.
5503 return isolate->heap()->undefined_value();
5504 }
5505 AssertNoAllocation no_gc;
5506 StringType* new_string = StringType::cast(new_object);
5507 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5508
5509 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5510 Char* write_cursor = reinterpret_cast<Char*>(
5511 new_string->address() + SeqAsciiString::kHeaderSize);
5512 *(write_cursor++) = '[';
5513 for (int i = 0; i < length; i++) {
5514 if (i != 0) *(write_cursor++) = ',';
5515 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005516 String::FlatContent content = str->GetFlatContent();
5517 ASSERT(content.IsFlat());
5518 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005519 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5520 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005521 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005522 } else {
5523 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5524 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005525 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005526 }
5527 }
5528 *(write_cursor++) = ']';
5529
5530 int final_length = static_cast<int>(
5531 write_cursor - reinterpret_cast<Char*>(
5532 new_string->address() + SeqAsciiString::kHeaderSize));
5533 isolate->heap()->new_space()->
5534 template ShrinkStringAtAllocationBoundary<StringType>(
5535 new_string, final_length);
5536 return new_string;
5537}
5538
5539
5540RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5541 NoHandleAllocation ha;
5542 ASSERT(args.length() == 1);
5543 CONVERT_CHECKED(JSArray, array, args[0]);
5544
5545 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5546 FixedArray* elements = FixedArray::cast(array->elements());
5547 int n = elements->length();
5548 bool ascii = true;
5549 int total_length = 0;
5550
5551 for (int i = 0; i < n; i++) {
5552 Object* elt = elements->get(i);
5553 if (!elt->IsString()) return isolate->heap()->undefined_value();
5554 String* element = String::cast(elt);
5555 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5556 total_length += element->length();
5557 if (ascii && element->IsTwoByteRepresentation()) {
5558 ascii = false;
5559 }
5560 }
5561
5562 int worst_case_length =
5563 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5564 + total_length * kJsonQuoteWorstCaseBlowup;
5565
5566 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5567 return isolate->heap()->undefined_value();
5568 }
5569
5570 if (ascii) {
5571 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5572 elements,
5573 worst_case_length);
5574 } else {
5575 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5576 elements,
5577 worst_case_length);
5578 }
5579}
5580
5581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005582RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583 NoHandleAllocation ha;
5584
5585 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005586 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005587
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005588 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005589
lrn@chromium.org25156de2010-04-06 13:10:27 +00005590 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005591 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005592 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005593}
5594
5595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005596RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597 NoHandleAllocation ha;
5598 CONVERT_CHECKED(String, str, args[0]);
5599
5600 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005601 double value = StringToDouble(isolate->unicode_cache(),
5602 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005603
5604 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005605 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005606}
5607
5608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005609template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005610MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005611 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005612 String* s,
5613 int length,
5614 int input_string_length,
5615 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005616 // We try this twice, once with the assumption that the result is no longer
5617 // than the input and, if that assumption breaks, again with the exact
5618 // length. This may not be pretty, but it is nicer than what was here before
5619 // and I hereby claim my vaffel-is.
5620 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005621 // Allocate the resulting string.
5622 //
5623 // NOTE: This assumes that the upper/lower case of an ascii
5624 // character is also ascii. This is currently the case, but it
5625 // might break in the future if we implement more context and locale
5626 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005627 Object* o;
5628 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005629 ? isolate->heap()->AllocateRawAsciiString(length)
5630 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005631 if (!maybe_o->ToObject(&o)) return maybe_o;
5632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005633 String* result = String::cast(o);
5634 bool has_changed_character = false;
5635
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005636 // Convert all characters to upper case, assuming that they will fit
5637 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005638 Access<StringInputBuffer> buffer(
5639 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005640 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005641 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005642 // We can assume that the string is not empty
5643 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005644 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005645 bool has_next = buffer->has_more();
5646 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005647 int char_length = mapping->get(current, next, chars);
5648 if (char_length == 0) {
5649 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005650 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651 i++;
5652 } else if (char_length == 1) {
5653 // Common case: converting the letter resulted in one character.
5654 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005655 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005656 has_changed_character = true;
5657 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005658 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005659 // We've assumed that the result would be as long as the
5660 // input but here is a character that converts to several
5661 // characters. No matter, we calculate the exact length
5662 // of the result and try the whole thing again.
5663 //
5664 // Note that this leaves room for optimization. We could just
5665 // memcpy what we already have to the result string. Also,
5666 // the result string is the last object allocated we could
5667 // "realloc" it and probably, in the vast majority of cases,
5668 // extend the existing string to be able to hold the full
5669 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005670 int next_length = 0;
5671 if (has_next) {
5672 next_length = mapping->get(next, 0, chars);
5673 if (next_length == 0) next_length = 1;
5674 }
5675 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005676 while (buffer->has_more()) {
5677 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005678 // NOTE: we use 0 as the next character here because, while
5679 // the next character may affect what a character converts to,
5680 // it does not in any case affect the length of what it convert
5681 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005682 int char_length = mapping->get(current, 0, chars);
5683 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005684 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005685 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005687 return Failure::OutOfMemoryException();
5688 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005689 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005690 // Try again with the real length.
5691 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005692 } else {
5693 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005694 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005695 i++;
5696 }
5697 has_changed_character = true;
5698 }
5699 current = next;
5700 }
5701 if (has_changed_character) {
5702 return result;
5703 } else {
5704 // If we didn't actually change anything in doing the conversion
5705 // we simple return the result and let the converted string
5706 // become garbage; there is no reason to keep two identical strings
5707 // alive.
5708 return s;
5709 }
5710}
5711
5712
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713namespace {
5714
lrn@chromium.org303ada72010-10-27 09:33:13 +00005715static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5716
5717
5718// Given a word and two range boundaries returns a word with high bit
5719// set in every byte iff the corresponding input byte was strictly in
5720// the range (m, n). All the other bits in the result are cleared.
5721// This function is only useful when it can be inlined and the
5722// boundaries are statically known.
5723// Requires: all bytes in the input word and the boundaries must be
5724// ascii (less than 0x7F).
5725static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5726 // Every byte in an ascii string is less than or equal to 0x7F.
5727 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5728 // Use strict inequalities since in edge cases the function could be
5729 // further simplified.
5730 ASSERT(0 < m && m < n && n < 0x7F);
5731 // Has high bit set in every w byte less than n.
5732 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5733 // Has high bit set in every w byte greater than m.
5734 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5735 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5736}
5737
5738
5739enum AsciiCaseConversion {
5740 ASCII_TO_LOWER,
5741 ASCII_TO_UPPER
5742};
5743
5744
5745template <AsciiCaseConversion dir>
5746struct FastAsciiConverter {
5747 static bool Convert(char* dst, char* src, int length) {
5748#ifdef DEBUG
5749 char* saved_dst = dst;
5750 char* saved_src = src;
5751#endif
5752 // We rely on the distance between upper and lower case letters
5753 // being a known power of 2.
5754 ASSERT('a' - 'A' == (1 << 5));
5755 // Boundaries for the range of input characters than require conversion.
5756 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5757 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5758 bool changed = false;
5759 char* const limit = src + length;
5760#ifdef V8_HOST_CAN_READ_UNALIGNED
5761 // Process the prefix of the input that requires no conversion one
5762 // (machine) word at a time.
5763 while (src <= limit - sizeof(uintptr_t)) {
5764 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5765 if (AsciiRangeMask(w, lo, hi) != 0) {
5766 changed = true;
5767 break;
5768 }
5769 *reinterpret_cast<uintptr_t*>(dst) = w;
5770 src += sizeof(uintptr_t);
5771 dst += sizeof(uintptr_t);
5772 }
5773 // Process the remainder of the input performing conversion when
5774 // required one word at a time.
5775 while (src <= limit - sizeof(uintptr_t)) {
5776 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5777 uintptr_t m = AsciiRangeMask(w, lo, hi);
5778 // The mask has high (7th) bit set in every byte that needs
5779 // conversion and we know that the distance between cases is
5780 // 1 << 5.
5781 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5782 src += sizeof(uintptr_t);
5783 dst += sizeof(uintptr_t);
5784 }
5785#endif
5786 // Process the last few bytes of the input (or the whole input if
5787 // unaligned access is not supported).
5788 while (src < limit) {
5789 char c = *src;
5790 if (lo < c && c < hi) {
5791 c ^= (1 << 5);
5792 changed = true;
5793 }
5794 *dst = c;
5795 ++src;
5796 ++dst;
5797 }
5798#ifdef DEBUG
5799 CheckConvert(saved_dst, saved_src, length, changed);
5800#endif
5801 return changed;
5802 }
5803
5804#ifdef DEBUG
5805 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5806 bool expected_changed = false;
5807 for (int i = 0; i < length; i++) {
5808 if (dst[i] == src[i]) continue;
5809 expected_changed = true;
5810 if (dir == ASCII_TO_LOWER) {
5811 ASSERT('A' <= src[i] && src[i] <= 'Z');
5812 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5813 } else {
5814 ASSERT(dir == ASCII_TO_UPPER);
5815 ASSERT('a' <= src[i] && src[i] <= 'z');
5816 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5817 }
5818 }
5819 ASSERT(expected_changed == changed);
5820 }
5821#endif
5822};
5823
5824
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005825struct ToLowerTraits {
5826 typedef unibrow::ToLowercase UnibrowConverter;
5827
lrn@chromium.org303ada72010-10-27 09:33:13 +00005828 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005829};
5830
5831
5832struct ToUpperTraits {
5833 typedef unibrow::ToUppercase UnibrowConverter;
5834
lrn@chromium.org303ada72010-10-27 09:33:13 +00005835 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005836};
5837
5838} // namespace
5839
5840
5841template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005842MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005843 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005844 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005845 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005846 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005847 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005848 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005849
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005850 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005851 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005852 if (length == 0) return s;
5853
5854 // Simpler handling of ascii strings.
5855 //
5856 // NOTE: This assumes that the upper/lower case of an ascii
5857 // character is also ascii. This is currently the case, but it
5858 // might break in the future if we implement more context and locale
5859 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005860 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005861 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005862 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005863 if (!maybe_o->ToObject(&o)) return maybe_o;
5864 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005865 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005866 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005867 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005868 return has_changed_character ? result : s;
5869 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005870
lrn@chromium.org303ada72010-10-27 09:33:13 +00005871 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005872 { MaybeObject* maybe_answer =
5873 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005874 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5875 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005876 if (answer->IsSmi()) {
5877 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005878 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005879 ConvertCaseHelper(isolate,
5880 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005881 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5882 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005883 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005884 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005885}
5886
5887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005888RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005889 return ConvertCase<ToLowerTraits>(
5890 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005891}
5892
5893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005894RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005895 return ConvertCase<ToUpperTraits>(
5896 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897}
5898
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005899
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005900static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5901 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5902}
5903
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005904
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005905RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005906 NoHandleAllocation ha;
5907 ASSERT(args.length() == 3);
5908
5909 CONVERT_CHECKED(String, s, args[0]);
5910 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5911 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5912
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005913 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005914 int length = s->length();
5915
5916 int left = 0;
5917 if (trimLeft) {
5918 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5919 left++;
5920 }
5921 }
5922
5923 int right = length;
5924 if (trimRight) {
5925 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5926 right--;
5927 }
5928 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005929 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005930}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005931
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005932
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005933void FindAsciiStringIndices(Vector<const char> subject,
5934 char pattern,
5935 ZoneList<int>* indices,
5936 unsigned int limit) {
5937 ASSERT(limit > 0);
5938 // Collect indices of pattern in subject using memchr.
5939 // Stop after finding at most limit values.
5940 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5941 const char* subject_end = subject_start + subject.length();
5942 const char* pos = subject_start;
5943 while (limit > 0) {
5944 pos = reinterpret_cast<const char*>(
5945 memchr(pos, pattern, subject_end - pos));
5946 if (pos == NULL) return;
5947 indices->Add(static_cast<int>(pos - subject_start));
5948 pos++;
5949 limit--;
5950 }
5951}
5952
5953
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005954template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005955void FindStringIndices(Isolate* isolate,
5956 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005957 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005958 ZoneList<int>* indices,
5959 unsigned int limit) {
5960 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005961 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005962 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005963 int pattern_length = pattern.length();
5964 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005965 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005966 while (limit > 0) {
5967 index = search.Search(subject, index);
5968 if (index < 0) return;
5969 indices->Add(index);
5970 index += pattern_length;
5971 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005972 }
5973}
5974
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005976RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005977 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005978 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005979 CONVERT_ARG_CHECKED(String, subject, 0);
5980 CONVERT_ARG_CHECKED(String, pattern, 1);
5981 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5982
5983 int subject_length = subject->length();
5984 int pattern_length = pattern->length();
5985 RUNTIME_ASSERT(pattern_length > 0);
5986
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00005987 if (limit == 0xffffffffu) {
5988 Handle<Object> cached_answer(StringSplitCache::Lookup(
5989 isolate->heap()->string_split_cache(),
5990 *subject,
5991 *pattern));
5992 if (*cached_answer != Smi::FromInt(0)) {
5993 Handle<JSArray> result =
5994 isolate->factory()->NewJSArrayWithElements(
5995 Handle<FixedArray>::cast(cached_answer));
5996 return *result;
5997 }
5998 }
5999
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006000 // The limit can be very large (0xffffffffu), but since the pattern
6001 // isn't empty, we can never create more parts than ~half the length
6002 // of the subject.
6003
6004 if (!subject->IsFlat()) FlattenString(subject);
6005
6006 static const int kMaxInitialListCapacity = 16;
6007
danno@chromium.org40cb8782011-05-25 07:58:50 +00006008 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006009
6010 // Find (up to limit) indices of separator and end-of-string in subject
6011 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6012 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006013 if (!pattern->IsFlat()) FlattenString(pattern);
6014
6015 // No allocation block.
6016 {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006017 AssertNoAllocation no_gc;
6018 String::FlatContent subject_content = subject->GetFlatContent();
6019 String::FlatContent pattern_content = pattern->GetFlatContent();
6020 ASSERT(subject_content.IsFlat());
6021 ASSERT(pattern_content.IsFlat());
6022 if (subject_content.IsAscii()) {
6023 Vector<const char> subject_vector = subject_content.ToAsciiVector();
6024 if (pattern_content.IsAscii()) {
6025 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00006026 if (pattern_vector.length() == 1) {
6027 FindAsciiStringIndices(subject_vector,
6028 pattern_vector[0],
6029 &indices,
6030 limit);
6031 } else {
6032 FindStringIndices(isolate,
6033 subject_vector,
6034 pattern_vector,
6035 &indices,
6036 limit);
6037 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006038 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006039 FindStringIndices(isolate,
6040 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006041 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006042 &indices,
6043 limit);
6044 }
6045 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006046 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006047 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006048 FindStringIndices(isolate,
6049 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006050 pattern_content.ToAsciiVector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006051 &indices,
6052 limit);
6053 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006054 FindStringIndices(isolate,
6055 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006056 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006057 &indices,
6058 limit);
6059 }
6060 }
6061 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006062
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006063 if (static_cast<uint32_t>(indices.length()) < limit) {
6064 indices.Add(subject_length);
6065 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006066
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006067 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006068
6069 // Create JSArray of substrings separated by separator.
6070 int part_count = indices.length();
6071
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006072 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006073 result->set_length(Smi::FromInt(part_count));
6074
6075 ASSERT(result->HasFastElements());
6076
6077 if (part_count == 1 && indices.at(0) == subject_length) {
6078 FixedArray::cast(result->elements())->set(0, *subject);
6079 return *result;
6080 }
6081
6082 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6083 int part_start = 0;
6084 for (int i = 0; i < part_count; i++) {
6085 HandleScope local_loop_handle;
6086 int part_end = indices.at(i);
6087 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006088 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006089 elements->set(i, *substring);
6090 part_start = part_end + pattern_length;
6091 }
6092
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006093 if (limit == 0xffffffffu) {
6094 StringSplitCache::Enter(isolate->heap(),
6095 isolate->heap()->string_split_cache(),
6096 *subject,
6097 *pattern,
6098 *elements);
6099 }
6100
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006101 return *result;
6102}
6103
6104
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006105// Copies ascii characters to the given fixed array looking up
6106// one-char strings in the cache. Gives up on the first char that is
6107// not in the cache and fills the remainder with smi zeros. Returns
6108// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006109static int CopyCachedAsciiCharsToArray(Heap* heap,
6110 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006111 FixedArray* elements,
6112 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006113 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006114 FixedArray* ascii_cache = heap->single_character_string_cache();
6115 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006116 int i;
6117 for (i = 0; i < length; ++i) {
6118 Object* value = ascii_cache->get(chars[i]);
6119 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006120 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006121 elements->set(i, value, SKIP_WRITE_BARRIER);
6122 }
6123 if (i < length) {
6124 ASSERT(Smi::FromInt(0) == 0);
6125 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6126 }
6127#ifdef DEBUG
6128 for (int j = 0; j < length; ++j) {
6129 Object* element = elements->get(j);
6130 ASSERT(element == Smi::FromInt(0) ||
6131 (element->IsString() && String::cast(element)->LooksValid()));
6132 }
6133#endif
6134 return i;
6135}
6136
6137
6138// Converts a String to JSArray.
6139// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006140RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006141 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006142 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006143 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006144 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006145
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006146 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006147 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006148
6149 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006150 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006151 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006152 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006153 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006154 { MaybeObject* maybe_obj =
6155 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006156 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6157 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006158 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006159 String::FlatContent content = s->GetFlatContent();
6160 if (content.IsAscii()) {
6161 Vector<const char> chars = content.ToAsciiVector();
6162 // Note, this will initialize all elements (not only the prefix)
6163 // to prevent GC from seeing partially initialized array.
6164 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6165 chars.start(),
6166 *elements,
6167 length);
6168 } else {
6169 MemsetPointer(elements->data_start(),
6170 isolate->heap()->undefined_value(),
6171 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006172 }
6173 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006174 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006175 }
6176 for (int i = position; i < length; ++i) {
6177 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6178 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006179 }
6180
6181#ifdef DEBUG
6182 for (int i = 0; i < length; ++i) {
6183 ASSERT(String::cast(elements->get(i))->length() == 1);
6184 }
6185#endif
6186
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006187 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006188}
6189
6190
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006191RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006192 NoHandleAllocation ha;
6193 ASSERT(args.length() == 1);
6194 CONVERT_CHECKED(String, value, args[0]);
6195 return value->ToObject();
6196}
6197
6198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006199bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006200 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006202 return char_length == 0;
6203}
6204
6205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006206RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006207 NoHandleAllocation ha;
6208 ASSERT(args.length() == 1);
6209
6210 Object* number = args[0];
6211 RUNTIME_ASSERT(number->IsNumber());
6212
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006213 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006214}
6215
6216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006217RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006218 NoHandleAllocation ha;
6219 ASSERT(args.length() == 1);
6220
6221 Object* number = args[0];
6222 RUNTIME_ASSERT(number->IsNumber());
6223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006224 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006225}
6226
6227
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006228RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006229 NoHandleAllocation ha;
6230 ASSERT(args.length() == 1);
6231
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006232 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006233
6234 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6235 if (number > 0 && number <= Smi::kMaxValue) {
6236 return Smi::FromInt(static_cast<int>(number));
6237 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006238 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239}
6240
6241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006242RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006243 NoHandleAllocation ha;
6244 ASSERT(args.length() == 1);
6245
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006246 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006247
6248 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6249 if (number > 0 && number <= Smi::kMaxValue) {
6250 return Smi::FromInt(static_cast<int>(number));
6251 }
6252
6253 double double_value = DoubleToInteger(number);
6254 // Map both -0 and +0 to +0.
6255 if (double_value == 0) double_value = 0;
6256
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006257 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006258}
6259
6260
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006261RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262 NoHandleAllocation ha;
6263 ASSERT(args.length() == 1);
6264
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006265 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006267}
6268
6269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006270RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006271 NoHandleAllocation ha;
6272 ASSERT(args.length() == 1);
6273
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006274 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006275
6276 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6277 if (number > 0 && number <= Smi::kMaxValue) {
6278 return Smi::FromInt(static_cast<int>(number));
6279 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006280 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006281}
6282
6283
ager@chromium.org870a0b62008-11-04 11:43:05 +00006284// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6285// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006286RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006287 NoHandleAllocation ha;
6288 ASSERT(args.length() == 1);
6289
6290 Object* obj = args[0];
6291 if (obj->IsSmi()) {
6292 return obj;
6293 }
6294 if (obj->IsHeapNumber()) {
6295 double value = HeapNumber::cast(obj)->value();
6296 int int_value = FastD2I(value);
6297 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6298 return Smi::FromInt(int_value);
6299 }
6300 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006301 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006302}
6303
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006305RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006306 NoHandleAllocation ha;
6307 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006308 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006309}
6310
6311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006312RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006313 NoHandleAllocation ha;
6314 ASSERT(args.length() == 2);
6315
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006316 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6317 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006318 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006319}
6320
6321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006322RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006323 NoHandleAllocation ha;
6324 ASSERT(args.length() == 2);
6325
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006326 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6327 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006328 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006329}
6330
6331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006332RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333 NoHandleAllocation ha;
6334 ASSERT(args.length() == 2);
6335
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006336 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6337 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006338 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006339}
6340
6341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006342RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343 NoHandleAllocation ha;
6344 ASSERT(args.length() == 1);
6345
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006346 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006347 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006348}
6349
6350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006351RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006352 NoHandleAllocation ha;
6353 ASSERT(args.length() == 0);
6354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006356}
6357
6358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006359RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360 NoHandleAllocation ha;
6361 ASSERT(args.length() == 2);
6362
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006363 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6364 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006365 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006366}
6367
6368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006369RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370 NoHandleAllocation ha;
6371 ASSERT(args.length() == 2);
6372
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006373 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6374 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375
ager@chromium.org3811b432009-10-28 14:53:37 +00006376 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006377 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006378 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006379}
6380
6381
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006382RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006383 NoHandleAllocation ha;
6384 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006385 CONVERT_CHECKED(String, str1, args[0]);
6386 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006387 isolate->counters()->string_add_runtime()->Increment();
6388 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006389}
6390
6391
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006392template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006393static inline void StringBuilderConcatHelper(String* special,
6394 sinkchar* sink,
6395 FixedArray* fixed_array,
6396 int array_length) {
6397 int position = 0;
6398 for (int i = 0; i < array_length; i++) {
6399 Object* element = fixed_array->get(i);
6400 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006401 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006402 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006403 int pos;
6404 int len;
6405 if (encoded_slice > 0) {
6406 // Position and length encoded in one smi.
6407 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6408 len = StringBuilderSubstringLength::decode(encoded_slice);
6409 } else {
6410 // Position and length encoded in two smis.
6411 Object* obj = fixed_array->get(++i);
6412 ASSERT(obj->IsSmi());
6413 pos = Smi::cast(obj)->value();
6414 len = -encoded_slice;
6415 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006416 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006417 sink + position,
6418 pos,
6419 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006420 position += len;
6421 } else {
6422 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006423 int element_length = string->length();
6424 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006425 position += element_length;
6426 }
6427 }
6428}
6429
6430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006431RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006432 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006433 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006434 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006435 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006436 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006437 return Failure::OutOfMemoryException();
6438 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006439 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006440 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006441
6442 // This assumption is used by the slice encoding in one or two smis.
6443 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6444
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006445 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006446 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006447 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006448 }
6449 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006450 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006452 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453
6454 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006455 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006456 } else if (array_length == 1) {
6457 Object* first = fixed_array->get(0);
6458 if (first->IsString()) return first;
6459 }
6460
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006461 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006462 int position = 0;
6463 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006464 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006465 Object* elt = fixed_array->get(i);
6466 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006467 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006468 int smi_value = Smi::cast(elt)->value();
6469 int pos;
6470 int len;
6471 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006472 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006473 pos = StringBuilderSubstringPosition::decode(smi_value);
6474 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006475 } else {
6476 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006477 len = -smi_value;
6478 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006479 i++;
6480 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006481 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006482 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006483 Object* next_smi = fixed_array->get(i);
6484 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006485 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006486 }
6487 pos = Smi::cast(next_smi)->value();
6488 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006489 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006490 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006491 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006492 ASSERT(pos >= 0);
6493 ASSERT(len >= 0);
6494 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006495 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006496 }
6497 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006498 } else if (elt->IsString()) {
6499 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006500 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006501 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006502 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006503 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006504 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006505 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006506 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006507 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006508 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006510 return Failure::OutOfMemoryException();
6511 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006512 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513 }
6514
6515 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006518 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006519 { MaybeObject* maybe_object =
6520 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006521 if (!maybe_object->ToObject(&object)) return maybe_object;
6522 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006523 SeqAsciiString* answer = SeqAsciiString::cast(object);
6524 StringBuilderConcatHelper(special,
6525 answer->GetChars(),
6526 fixed_array,
6527 array_length);
6528 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006529 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006530 { MaybeObject* maybe_object =
6531 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006532 if (!maybe_object->ToObject(&object)) return maybe_object;
6533 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006534 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6535 StringBuilderConcatHelper(special,
6536 answer->GetChars(),
6537 fixed_array,
6538 array_length);
6539 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006541}
6542
6543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006544RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006545 NoHandleAllocation ha;
6546 ASSERT(args.length() == 3);
6547 CONVERT_CHECKED(JSArray, array, args[0]);
6548 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006549 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006550 return Failure::OutOfMemoryException();
6551 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006552 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006553 CONVERT_CHECKED(String, separator, args[2]);
6554
6555 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006556 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006557 }
6558 FixedArray* fixed_array = FixedArray::cast(array->elements());
6559 if (fixed_array->length() < array_length) {
6560 array_length = fixed_array->length();
6561 }
6562
6563 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006564 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006565 } else if (array_length == 1) {
6566 Object* first = fixed_array->get(0);
6567 if (first->IsString()) return first;
6568 }
6569
6570 int separator_length = separator->length();
6571 int max_nof_separators =
6572 (String::kMaxLength + separator_length - 1) / separator_length;
6573 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006575 return Failure::OutOfMemoryException();
6576 }
6577 int length = (array_length - 1) * separator_length;
6578 for (int i = 0; i < array_length; i++) {
6579 Object* element_obj = fixed_array->get(i);
6580 if (!element_obj->IsString()) {
6581 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006582 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006583 }
6584 String* element = String::cast(element_obj);
6585 int increment = element->length();
6586 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006588 return Failure::OutOfMemoryException();
6589 }
6590 length += increment;
6591 }
6592
6593 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 { MaybeObject* maybe_object =
6595 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006596 if (!maybe_object->ToObject(&object)) return maybe_object;
6597 }
6598 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6599
6600 uc16* sink = answer->GetChars();
6601#ifdef DEBUG
6602 uc16* end = sink + length;
6603#endif
6604
6605 String* first = String::cast(fixed_array->get(0));
6606 int first_length = first->length();
6607 String::WriteToFlat(first, sink, 0, first_length);
6608 sink += first_length;
6609
6610 for (int i = 1; i < array_length; i++) {
6611 ASSERT(sink + separator_length <= end);
6612 String::WriteToFlat(separator, sink, 0, separator_length);
6613 sink += separator_length;
6614
6615 String* element = String::cast(fixed_array->get(i));
6616 int element_length = element->length();
6617 ASSERT(sink + element_length <= end);
6618 String::WriteToFlat(element, sink, 0, element_length);
6619 sink += element_length;
6620 }
6621 ASSERT(sink == end);
6622
6623 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6624 return answer;
6625}
6626
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006627template <typename Char>
6628static void JoinSparseArrayWithSeparator(FixedArray* elements,
6629 int elements_length,
6630 uint32_t array_length,
6631 String* separator,
6632 Vector<Char> buffer) {
6633 int previous_separator_position = 0;
6634 int separator_length = separator->length();
6635 int cursor = 0;
6636 for (int i = 0; i < elements_length; i += 2) {
6637 int position = NumberToInt32(elements->get(i));
6638 String* string = String::cast(elements->get(i + 1));
6639 int string_length = string->length();
6640 if (string->length() > 0) {
6641 while (previous_separator_position < position) {
6642 String::WriteToFlat<Char>(separator, &buffer[cursor],
6643 0, separator_length);
6644 cursor += separator_length;
6645 previous_separator_position++;
6646 }
6647 String::WriteToFlat<Char>(string, &buffer[cursor],
6648 0, string_length);
6649 cursor += string->length();
6650 }
6651 }
6652 if (separator_length > 0) {
6653 // Array length must be representable as a signed 32-bit number,
6654 // otherwise the total string length would have been too large.
6655 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6656 int last_array_index = static_cast<int>(array_length - 1);
6657 while (previous_separator_position < last_array_index) {
6658 String::WriteToFlat<Char>(separator, &buffer[cursor],
6659 0, separator_length);
6660 cursor += separator_length;
6661 previous_separator_position++;
6662 }
6663 }
6664 ASSERT(cursor <= buffer.length());
6665}
6666
6667
6668RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6669 NoHandleAllocation ha;
6670 ASSERT(args.length() == 3);
6671 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6672 RUNTIME_ASSERT(elements_array->HasFastElements());
6673 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6674 CONVERT_CHECKED(String, separator, args[2]);
6675 // elements_array is fast-mode JSarray of alternating positions
6676 // (increasing order) and strings.
6677 // array_length is length of original array (used to add separators);
6678 // separator is string to put between elements. Assumed to be non-empty.
6679
6680 // Find total length of join result.
6681 int string_length = 0;
6682 bool is_ascii = true;
6683 int max_string_length = SeqAsciiString::kMaxLength;
6684 bool overflow = false;
6685 CONVERT_NUMBER_CHECKED(int, elements_length,
6686 Int32, elements_array->length());
6687 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6688 FixedArray* elements = FixedArray::cast(elements_array->elements());
6689 for (int i = 0; i < elements_length; i += 2) {
6690 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6691 CONVERT_CHECKED(String, string, elements->get(i + 1));
6692 int length = string->length();
6693 if (is_ascii && !string->IsAsciiRepresentation()) {
6694 is_ascii = false;
6695 max_string_length = SeqTwoByteString::kMaxLength;
6696 }
6697 if (length > max_string_length ||
6698 max_string_length - length < string_length) {
6699 overflow = true;
6700 break;
6701 }
6702 string_length += length;
6703 }
6704 int separator_length = separator->length();
6705 if (!overflow && separator_length > 0) {
6706 if (array_length <= 0x7fffffffu) {
6707 int separator_count = static_cast<int>(array_length) - 1;
6708 int remaining_length = max_string_length - string_length;
6709 if ((remaining_length / separator_length) >= separator_count) {
6710 string_length += separator_length * (array_length - 1);
6711 } else {
6712 // Not room for the separators within the maximal string length.
6713 overflow = true;
6714 }
6715 } else {
6716 // Nonempty separator and at least 2^31-1 separators necessary
6717 // means that the string is too large to create.
6718 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6719 overflow = true;
6720 }
6721 }
6722 if (overflow) {
6723 // Throw OutOfMemory exception for creating too large a string.
6724 V8::FatalProcessOutOfMemory("Array join result too large.");
6725 }
6726
6727 if (is_ascii) {
6728 MaybeObject* result_allocation =
6729 isolate->heap()->AllocateRawAsciiString(string_length);
6730 if (result_allocation->IsFailure()) return result_allocation;
6731 SeqAsciiString* result_string =
6732 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6733 JoinSparseArrayWithSeparator<char>(elements,
6734 elements_length,
6735 array_length,
6736 separator,
6737 Vector<char>(result_string->GetChars(),
6738 string_length));
6739 return result_string;
6740 } else {
6741 MaybeObject* result_allocation =
6742 isolate->heap()->AllocateRawTwoByteString(string_length);
6743 if (result_allocation->IsFailure()) return result_allocation;
6744 SeqTwoByteString* result_string =
6745 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6746 JoinSparseArrayWithSeparator<uc16>(elements,
6747 elements_length,
6748 array_length,
6749 separator,
6750 Vector<uc16>(result_string->GetChars(),
6751 string_length));
6752 return result_string;
6753 }
6754}
6755
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006757RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758 NoHandleAllocation ha;
6759 ASSERT(args.length() == 2);
6760
6761 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6762 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006763 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764}
6765
6766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006767RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768 NoHandleAllocation ha;
6769 ASSERT(args.length() == 2);
6770
6771 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6772 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006774}
6775
6776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006777RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006778 NoHandleAllocation ha;
6779 ASSERT(args.length() == 2);
6780
6781 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6782 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006783 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784}
6785
6786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006787RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006788 NoHandleAllocation ha;
6789 ASSERT(args.length() == 1);
6790
6791 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006792 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006793}
6794
6795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006796RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006797 NoHandleAllocation ha;
6798 ASSERT(args.length() == 2);
6799
6800 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6801 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006802 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006803}
6804
6805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006806RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807 NoHandleAllocation ha;
6808 ASSERT(args.length() == 2);
6809
6810 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6811 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006812 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813}
6814
6815
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006816RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817 NoHandleAllocation ha;
6818 ASSERT(args.length() == 2);
6819
6820 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6821 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006822 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823}
6824
6825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006826RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006827 NoHandleAllocation ha;
6828 ASSERT(args.length() == 2);
6829
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006830 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6831 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006832 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6833 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6834 if (x == y) return Smi::FromInt(EQUAL);
6835 Object* result;
6836 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6837 result = Smi::FromInt(EQUAL);
6838 } else {
6839 result = Smi::FromInt(NOT_EQUAL);
6840 }
6841 return result;
6842}
6843
6844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006845RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846 NoHandleAllocation ha;
6847 ASSERT(args.length() == 2);
6848
6849 CONVERT_CHECKED(String, x, args[0]);
6850 CONVERT_CHECKED(String, y, args[1]);
6851
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006852 bool not_equal = !x->Equals(y);
6853 // This is slightly convoluted because the value that signifies
6854 // equality is 0 and inequality is 1 so we have to negate the result
6855 // from String::Equals.
6856 ASSERT(not_equal == 0 || not_equal == 1);
6857 STATIC_CHECK(EQUAL == 0);
6858 STATIC_CHECK(NOT_EQUAL == 1);
6859 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006860}
6861
6862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006863RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006864 NoHandleAllocation ha;
6865 ASSERT(args.length() == 3);
6866
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006867 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6868 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869 if (isnan(x) || isnan(y)) return args[2];
6870 if (x == y) return Smi::FromInt(EQUAL);
6871 if (isless(x, y)) return Smi::FromInt(LESS);
6872 return Smi::FromInt(GREATER);
6873}
6874
6875
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006876// Compare two Smis as if they were converted to strings and then
6877// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006878RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006879 NoHandleAllocation ha;
6880 ASSERT(args.length() == 2);
6881
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006882 // Extract the integer values from the Smis.
6883 CONVERT_CHECKED(Smi, x, args[0]);
6884 CONVERT_CHECKED(Smi, y, args[1]);
6885 int x_value = x->value();
6886 int y_value = y->value();
6887
6888 // If the integers are equal so are the string representations.
6889 if (x_value == y_value) return Smi::FromInt(EQUAL);
6890
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006891 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006892 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006893 if (x_value == 0 || y_value == 0)
6894 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006895
ager@chromium.org32912102009-01-16 10:38:43 +00006896 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006897 // smallest because the char code of '-' is less than the char code
6898 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006899
6900 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6901 // architectures using 32-bit Smis.
6902 uint32_t x_scaled = x_value;
6903 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006904 if (x_value < 0 || y_value < 0) {
6905 if (y_value >= 0) return Smi::FromInt(LESS);
6906 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006907 x_scaled = -x_value;
6908 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006909 }
6910
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006911 static const uint32_t kPowersOf10[] = {
6912 1, 10, 100, 1000, 10*1000, 100*1000,
6913 1000*1000, 10*1000*1000, 100*1000*1000,
6914 1000*1000*1000
6915 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006916
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006917 // If the integers have the same number of decimal digits they can be
6918 // compared directly as the numeric order is the same as the
6919 // lexicographic order. If one integer has fewer digits, it is scaled
6920 // by some power of 10 to have the same number of digits as the longer
6921 // integer. If the scaled integers are equal it means the shorter
6922 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006923
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006924 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6925 int x_log2 = IntegerLog2(x_scaled);
6926 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6927 x_log10 -= x_scaled < kPowersOf10[x_log10];
6928
6929 int y_log2 = IntegerLog2(y_scaled);
6930 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6931 y_log10 -= y_scaled < kPowersOf10[y_log10];
6932
6933 int tie = EQUAL;
6934
6935 if (x_log10 < y_log10) {
6936 // X has fewer digits. We would like to simply scale up X but that
6937 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6938 // be scaled up to 9_000_000_000. So we scale up by the next
6939 // smallest power and scale down Y to drop one digit. It is OK to
6940 // drop one digit from the longer integer since the final digit is
6941 // past the length of the shorter integer.
6942 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6943 y_scaled /= 10;
6944 tie = LESS;
6945 } else if (y_log10 < x_log10) {
6946 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6947 x_scaled /= 10;
6948 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006949 }
6950
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006951 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6952 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6953 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006954}
6955
6956
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006957static Object* StringInputBufferCompare(RuntimeState* state,
6958 String* x,
6959 String* y) {
6960 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6961 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006962 bufx.Reset(x);
6963 bufy.Reset(y);
6964 while (bufx.has_more() && bufy.has_more()) {
6965 int d = bufx.GetNext() - bufy.GetNext();
6966 if (d < 0) return Smi::FromInt(LESS);
6967 else if (d > 0) return Smi::FromInt(GREATER);
6968 }
6969
6970 // x is (non-trivial) prefix of y:
6971 if (bufy.has_more()) return Smi::FromInt(LESS);
6972 // y is prefix of x:
6973 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6974}
6975
6976
6977static Object* FlatStringCompare(String* x, String* y) {
6978 ASSERT(x->IsFlat());
6979 ASSERT(y->IsFlat());
6980 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6981 int prefix_length = x->length();
6982 if (y->length() < prefix_length) {
6983 prefix_length = y->length();
6984 equal_prefix_result = Smi::FromInt(GREATER);
6985 } else if (y->length() > prefix_length) {
6986 equal_prefix_result = Smi::FromInt(LESS);
6987 }
6988 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006989 String::FlatContent x_content = x->GetFlatContent();
6990 String::FlatContent y_content = y->GetFlatContent();
6991 if (x_content.IsAscii()) {
6992 Vector<const char> x_chars = x_content.ToAsciiVector();
6993 if (y_content.IsAscii()) {
6994 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006995 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006996 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006997 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006998 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6999 }
7000 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007001 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7002 if (y_content.IsAscii()) {
7003 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007004 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7005 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007006 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007007 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7008 }
7009 }
7010 Object* result;
7011 if (r == 0) {
7012 result = equal_prefix_result;
7013 } else {
7014 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7015 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007016 ASSERT(result ==
7017 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007018 return result;
7019}
7020
7021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007022RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023 NoHandleAllocation ha;
7024 ASSERT(args.length() == 2);
7025
7026 CONVERT_CHECKED(String, x, args[0]);
7027 CONVERT_CHECKED(String, y, args[1]);
7028
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007029 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007030
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031 // A few fast case tests before we flatten.
7032 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007033 if (y->length() == 0) {
7034 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007036 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007037 return Smi::FromInt(LESS);
7038 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007039
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007040 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007041 if (d < 0) return Smi::FromInt(LESS);
7042 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043
lrn@chromium.org303ada72010-10-27 09:33:13 +00007044 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007045 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007046 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7047 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007048 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007049 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7050 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007051
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007052 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007053 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007054}
7055
7056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007057RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 NoHandleAllocation ha;
7059 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007060 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007062 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007064}
7065
7066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007067RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 NoHandleAllocation ha;
7069 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007070 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007072 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074}
7075
7076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007077RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078 NoHandleAllocation ha;
7079 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007080 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007082 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007083 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084}
7085
7086
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007087static const double kPiDividedBy4 = 0.78539816339744830962;
7088
7089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007090RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091 NoHandleAllocation ha;
7092 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007093 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007094
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007095 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7096 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007097 double result;
7098 if (isinf(x) && isinf(y)) {
7099 // Make sure that the result in case of two infinite arguments
7100 // is a multiple of Pi / 4. The sign of the result is determined
7101 // by the first argument (x) and the sign of the second argument
7102 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103 int multiplier = (x < 0) ? -1 : 1;
7104 if (y < 0) multiplier *= 3;
7105 result = multiplier * kPiDividedBy4;
7106 } else {
7107 result = atan2(x, y);
7108 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007109 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110}
7111
7112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007113RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114 NoHandleAllocation ha;
7115 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007116 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007118 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007119 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007120}
7121
7122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007123RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007124 NoHandleAllocation ha;
7125 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007126 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007127
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007128 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007129 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130}
7131
7132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007133RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007134 NoHandleAllocation ha;
7135 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007136 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007137
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007138 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007139 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007140}
7141
7142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007143RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007144 NoHandleAllocation ha;
7145 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007146 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007147
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007148 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007149 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007150}
7151
7152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007153RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007154 NoHandleAllocation ha;
7155 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007156 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007157
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007158 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007159 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007160}
7161
7162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007163RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007164 NoHandleAllocation ha;
7165 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007166 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007167
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007168 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007169
7170 // If the second argument is a smi, it is much faster to call the
7171 // custom powi() function than the generic pow().
7172 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007173 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007174 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007175 }
7176
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007177 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007178 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007179}
7180
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007181// Fast version of Math.pow if we know that y is not an integer and
7182// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007183RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007184 NoHandleAllocation ha;
7185 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007186 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7187 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007188 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007189 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007190 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007191 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007192 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007193 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007194 }
7195}
7196
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007198RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007199 NoHandleAllocation ha;
7200 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007201 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007202
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007203 if (!args[0]->IsHeapNumber()) {
7204 // Must be smi. Return the argument unchanged for all the other types
7205 // to make fuzz-natives test happy.
7206 return args[0];
7207 }
7208
7209 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7210
7211 double value = number->value();
7212 int exponent = number->get_exponent();
7213 int sign = number->get_sign();
7214
danno@chromium.org160a7b02011-04-18 15:51:38 +00007215 if (exponent < -1) {
7216 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7217 if (sign) return isolate->heap()->minus_zero_value();
7218 return Smi::FromInt(0);
7219 }
7220
7221 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7222 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7223 // agument holds for 32-bit smis).
7224 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007225 return Smi::FromInt(static_cast<int>(value + 0.5));
7226 }
7227
7228 // If the magnitude is big enough, there's no place for fraction part. If we
7229 // try to add 0.5 to this number, 1.0 will be added instead.
7230 if (exponent >= 52) {
7231 return number;
7232 }
7233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007234 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007235
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007236 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007237 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007238}
7239
7240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007241RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007242 NoHandleAllocation ha;
7243 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007244 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007245
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007246 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007247 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007248}
7249
7250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007251RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007252 NoHandleAllocation ha;
7253 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007254 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007255
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007256 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007257 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007258}
7259
7260
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007261RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007262 NoHandleAllocation ha;
7263 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007264 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007266 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007267 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007268}
7269
7270
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007271static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007272 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7273 181, 212, 243, 273, 304, 334};
7274 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7275 182, 213, 244, 274, 305, 335};
7276
7277 year += month / 12;
7278 month %= 12;
7279 if (month < 0) {
7280 year--;
7281 month += 12;
7282 }
7283
7284 ASSERT(month >= 0);
7285 ASSERT(month < 12);
7286
7287 // year_delta is an arbitrary number such that:
7288 // a) year_delta = -1 (mod 400)
7289 // b) year + year_delta > 0 for years in the range defined by
7290 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7291 // Jan 1 1970. This is required so that we don't run into integer
7292 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007293 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007294 // operations.
7295 static const int year_delta = 399999;
7296 static const int base_day = 365 * (1970 + year_delta) +
7297 (1970 + year_delta) / 4 -
7298 (1970 + year_delta) / 100 +
7299 (1970 + year_delta) / 400;
7300
7301 int year1 = year + year_delta;
7302 int day_from_year = 365 * year1 +
7303 year1 / 4 -
7304 year1 / 100 +
7305 year1 / 400 -
7306 base_day;
7307
7308 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007309 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007310 }
7311
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007312 return day_from_year + day_from_month_leap[month] + day - 1;
7313}
7314
7315
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007316RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007317 NoHandleAllocation ha;
7318 ASSERT(args.length() == 3);
7319
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007320 CONVERT_SMI_ARG_CHECKED(year, 0);
7321 CONVERT_SMI_ARG_CHECKED(month, 1);
7322 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007323
7324 return Smi::FromInt(MakeDay(year, month, date));
7325}
7326
7327
7328static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7329static const int kDaysIn4Years = 4 * 365 + 1;
7330static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7331static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7332static const int kDays1970to2000 = 30 * 365 + 7;
7333static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7334 kDays1970to2000;
7335static const int kYearsOffset = 400000;
7336
7337static const char kDayInYear[] = {
7338 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7339 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7340 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7341 22, 23, 24, 25, 26, 27, 28,
7342 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7343 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7344 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7345 22, 23, 24, 25, 26, 27, 28, 29, 30,
7346 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7347 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7348 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7349 22, 23, 24, 25, 26, 27, 28, 29, 30,
7350 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7351 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7352 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7353 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7354 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7355 22, 23, 24, 25, 26, 27, 28, 29, 30,
7356 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7357 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7358 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7359 22, 23, 24, 25, 26, 27, 28, 29, 30,
7360 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7361 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7362
7363 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7364 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7365 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7366 22, 23, 24, 25, 26, 27, 28,
7367 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7368 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7369 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7370 22, 23, 24, 25, 26, 27, 28, 29, 30,
7371 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7372 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7373 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7374 22, 23, 24, 25, 26, 27, 28, 29, 30,
7375 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7376 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7377 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7378 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7379 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7380 22, 23, 24, 25, 26, 27, 28, 29, 30,
7381 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7382 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7383 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7384 22, 23, 24, 25, 26, 27, 28, 29, 30,
7385 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7386 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7387
7388 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7389 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7390 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7391 22, 23, 24, 25, 26, 27, 28, 29,
7392 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7393 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7394 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7395 22, 23, 24, 25, 26, 27, 28, 29, 30,
7396 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7397 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7398 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7399 22, 23, 24, 25, 26, 27, 28, 29, 30,
7400 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7401 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7402 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7403 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7404 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7405 22, 23, 24, 25, 26, 27, 28, 29, 30,
7406 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7407 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7408 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7409 22, 23, 24, 25, 26, 27, 28, 29, 30,
7410 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7411 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7412
7413 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7414 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7415 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7416 22, 23, 24, 25, 26, 27, 28,
7417 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7418 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7419 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7420 22, 23, 24, 25, 26, 27, 28, 29, 30,
7421 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7422 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7423 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7424 22, 23, 24, 25, 26, 27, 28, 29, 30,
7425 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7426 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7427 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7428 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7429 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7430 22, 23, 24, 25, 26, 27, 28, 29, 30,
7431 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7432 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7433 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7434 22, 23, 24, 25, 26, 27, 28, 29, 30,
7435 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7436 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7437
7438static const char kMonthInYear[] = {
7439 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,
7440 0, 0, 0, 0, 0, 0,
7441 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,
7442 1, 1, 1,
7443 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,
7444 2, 2, 2, 2, 2, 2,
7445 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,
7446 3, 3, 3, 3, 3,
7447 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,
7448 4, 4, 4, 4, 4, 4,
7449 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,
7450 5, 5, 5, 5, 5,
7451 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,
7452 6, 6, 6, 6, 6, 6,
7453 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,
7454 7, 7, 7, 7, 7, 7,
7455 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,
7456 8, 8, 8, 8, 8,
7457 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,
7458 9, 9, 9, 9, 9, 9,
7459 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7460 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7461 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7462 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7463
7464 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,
7465 0, 0, 0, 0, 0, 0,
7466 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,
7467 1, 1, 1,
7468 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,
7469 2, 2, 2, 2, 2, 2,
7470 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,
7471 3, 3, 3, 3, 3,
7472 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,
7473 4, 4, 4, 4, 4, 4,
7474 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,
7475 5, 5, 5, 5, 5,
7476 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,
7477 6, 6, 6, 6, 6, 6,
7478 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,
7479 7, 7, 7, 7, 7, 7,
7480 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,
7481 8, 8, 8, 8, 8,
7482 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,
7483 9, 9, 9, 9, 9, 9,
7484 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7485 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7486 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7487 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7488
7489 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,
7490 0, 0, 0, 0, 0, 0,
7491 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,
7492 1, 1, 1, 1,
7493 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,
7494 2, 2, 2, 2, 2, 2,
7495 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,
7496 3, 3, 3, 3, 3,
7497 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,
7498 4, 4, 4, 4, 4, 4,
7499 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,
7500 5, 5, 5, 5, 5,
7501 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,
7502 6, 6, 6, 6, 6, 6,
7503 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,
7504 7, 7, 7, 7, 7, 7,
7505 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,
7506 8, 8, 8, 8, 8,
7507 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,
7508 9, 9, 9, 9, 9, 9,
7509 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7510 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7511 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7512 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7513
7514 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,
7515 0, 0, 0, 0, 0, 0,
7516 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,
7517 1, 1, 1,
7518 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,
7519 2, 2, 2, 2, 2, 2,
7520 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,
7521 3, 3, 3, 3, 3,
7522 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,
7523 4, 4, 4, 4, 4, 4,
7524 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,
7525 5, 5, 5, 5, 5,
7526 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,
7527 6, 6, 6, 6, 6, 6,
7528 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,
7529 7, 7, 7, 7, 7, 7,
7530 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,
7531 8, 8, 8, 8, 8,
7532 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,
7533 9, 9, 9, 9, 9, 9,
7534 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7535 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7536 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7537 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7538
7539
7540// This function works for dates from 1970 to 2099.
7541static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007542 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007543#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007544 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007545#endif
7546
7547 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7548 date %= kDaysIn4Years;
7549
7550 month = kMonthInYear[date];
7551 day = kDayInYear[date];
7552
7553 ASSERT(MakeDay(year, month, day) == save_date);
7554}
7555
7556
7557static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007558 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007559#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007560 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007561#endif
7562
7563 date += kDaysOffset;
7564 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7565 date %= kDaysIn400Years;
7566
7567 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7568
7569 date--;
7570 int yd1 = date / kDaysIn100Years;
7571 date %= kDaysIn100Years;
7572 year += 100 * yd1;
7573
7574 date++;
7575 int yd2 = date / kDaysIn4Years;
7576 date %= kDaysIn4Years;
7577 year += 4 * yd2;
7578
7579 date--;
7580 int yd3 = date / 365;
7581 date %= 365;
7582 year += yd3;
7583
7584 bool is_leap = (!yd1 || yd2) && !yd3;
7585
7586 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007587 ASSERT(is_leap || (date >= 0));
7588 ASSERT((date < 365) || (is_leap && (date < 366)));
7589 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7590 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7591 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007592
7593 if (is_leap) {
7594 day = kDayInYear[2*365 + 1 + date];
7595 month = kMonthInYear[2*365 + 1 + date];
7596 } else {
7597 day = kDayInYear[date];
7598 month = kMonthInYear[date];
7599 }
7600
7601 ASSERT(MakeDay(year, month, day) == save_date);
7602}
7603
7604
7605static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007606 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007607 if (date >= 0 && date < 32 * kDaysIn4Years) {
7608 DateYMDFromTimeAfter1970(date, year, month, day);
7609 } else {
7610 DateYMDFromTimeSlow(date, year, month, day);
7611 }
7612}
7613
7614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007615RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007616 NoHandleAllocation ha;
7617 ASSERT(args.length() == 2);
7618
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007619 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007620 CONVERT_CHECKED(JSArray, res_array, args[1]);
7621
7622 int year, month, day;
7623 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7624
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007625 RUNTIME_ASSERT(res_array->elements()->map() ==
7626 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007627 FixedArray* elms = FixedArray::cast(res_array->elements());
7628 RUNTIME_ASSERT(elms->length() == 3);
7629
7630 elms->set(0, Smi::FromInt(year));
7631 elms->set(1, Smi::FromInt(month));
7632 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007634 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007635}
7636
7637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007638RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007639 HandleScope scope(isolate);
7640 ASSERT(args.length() == 3);
7641
7642 Handle<JSFunction> callee = args.at<JSFunction>(0);
7643 Object** parameters = reinterpret_cast<Object**>(args[1]);
7644 const int argument_count = Smi::cast(args[2])->value();
7645
7646 Handle<JSObject> result =
7647 isolate->factory()->NewArgumentsObject(callee, argument_count);
7648 // Allocate the elements if needed.
7649 int parameter_count = callee->shared()->formal_parameter_count();
7650 if (argument_count > 0) {
7651 if (parameter_count > 0) {
7652 int mapped_count = Min(argument_count, parameter_count);
7653 Handle<FixedArray> parameter_map =
7654 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7655 parameter_map->set_map(
7656 isolate->heap()->non_strict_arguments_elements_map());
7657
7658 Handle<Map> old_map(result->map());
7659 Handle<Map> new_map =
7660 isolate->factory()->CopyMapDropTransitions(old_map);
7661 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7662
7663 result->set_map(*new_map);
7664 result->set_elements(*parameter_map);
7665
7666 // Store the context and the arguments array at the beginning of the
7667 // parameter map.
7668 Handle<Context> context(isolate->context());
7669 Handle<FixedArray> arguments =
7670 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7671 parameter_map->set(0, *context);
7672 parameter_map->set(1, *arguments);
7673
7674 // Loop over the actual parameters backwards.
7675 int index = argument_count - 1;
7676 while (index >= mapped_count) {
7677 // These go directly in the arguments array and have no
7678 // corresponding slot in the parameter map.
7679 arguments->set(index, *(parameters - index - 1));
7680 --index;
7681 }
7682
7683 ScopeInfo<> scope_info(callee->shared()->scope_info());
7684 while (index >= 0) {
7685 // Detect duplicate names to the right in the parameter list.
7686 Handle<String> name = scope_info.parameter_name(index);
7687 int context_slot_count = scope_info.number_of_context_slots();
7688 bool duplicate = false;
7689 for (int j = index + 1; j < parameter_count; ++j) {
7690 if (scope_info.parameter_name(j).is_identical_to(name)) {
7691 duplicate = true;
7692 break;
7693 }
7694 }
7695
7696 if (duplicate) {
7697 // This goes directly in the arguments array with a hole in the
7698 // parameter map.
7699 arguments->set(index, *(parameters - index - 1));
7700 parameter_map->set_the_hole(index + 2);
7701 } else {
7702 // The context index goes in the parameter map with a hole in the
7703 // arguments array.
7704 int context_index = -1;
7705 for (int j = Context::MIN_CONTEXT_SLOTS;
7706 j < context_slot_count;
7707 ++j) {
7708 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7709 context_index = j;
7710 break;
7711 }
7712 }
7713 ASSERT(context_index >= 0);
7714 arguments->set_the_hole(index);
7715 parameter_map->set(index + 2, Smi::FromInt(context_index));
7716 }
7717
7718 --index;
7719 }
7720 } else {
7721 // If there is no aliasing, the arguments object elements are not
7722 // special in any way.
7723 Handle<FixedArray> elements =
7724 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7725 result->set_elements(*elements);
7726 for (int i = 0; i < argument_count; ++i) {
7727 elements->set(i, *(parameters - i - 1));
7728 }
7729 }
7730 }
7731 return *result;
7732}
7733
7734
7735RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007736 NoHandleAllocation ha;
7737 ASSERT(args.length() == 3);
7738
7739 JSFunction* callee = JSFunction::cast(args[0]);
7740 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007741 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007742
lrn@chromium.org303ada72010-10-27 09:33:13 +00007743 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007744 { MaybeObject* maybe_result =
7745 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007746 if (!maybe_result->ToObject(&result)) return maybe_result;
7747 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007748 // Allocate the elements if needed.
7749 if (length > 0) {
7750 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007751 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007752 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007753 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7754 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007755
7756 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007757 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007758 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007759 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007760
7761 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007762 for (int i = 0; i < length; i++) {
7763 array->set(i, *--parameters, mode);
7764 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007765 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007766 }
7767 return result;
7768}
7769
7770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007771RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007772 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007773 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007774 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007775 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007776 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007777
whesse@chromium.org7b260152011-06-20 15:33:18 +00007778 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007779 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007780 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007781 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007782 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7783 context,
7784 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007785 return *result;
7786}
7787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007788
7789static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7790 int* total_argc) {
7791 // Find frame containing arguments passed to the caller.
7792 JavaScriptFrameIterator it;
7793 JavaScriptFrame* frame = it.frame();
7794 List<JSFunction*> functions(2);
7795 frame->GetFunctions(&functions);
7796 if (functions.length() > 1) {
7797 int inlined_frame_index = functions.length() - 1;
7798 JSFunction* inlined_function = functions[inlined_frame_index];
7799 int args_count = inlined_function->shared()->formal_parameter_count();
7800 ScopedVector<SlotRef> args_slots(args_count);
7801 SlotRef::ComputeSlotMappingForArguments(frame,
7802 inlined_frame_index,
7803 &args_slots);
7804
7805 *total_argc = bound_argc + args_count;
7806 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7807 for (int i = 0; i < args_count; i++) {
7808 Handle<Object> val = args_slots[i].GetValue();
7809 param_data[bound_argc + i] = val.location();
7810 }
7811 return param_data;
7812 } else {
7813 it.AdvanceToArgumentsFrame();
7814 frame = it.frame();
7815 int args_count = frame->ComputeParametersCount();
7816
7817 *total_argc = bound_argc + args_count;
7818 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7819 for (int i = 0; i < args_count; i++) {
7820 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7821 param_data[bound_argc + i] = val.location();
7822 }
7823 return param_data;
7824 }
7825}
7826
7827
7828RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007829 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007830 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007831 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007832 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007833
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007834 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007835 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007836 int bound_argc = 0;
7837 if (!args[1]->IsNull()) {
7838 CONVERT_ARG_CHECKED(JSArray, params, 1);
7839 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007840 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007841 bound_argc = Smi::cast(params->length())->value();
7842 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007844 int total_argc = 0;
7845 SmartPointer<Object**> param_data =
7846 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007847 for (int i = 0; i < bound_argc; i++) {
7848 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007849 param_data[i] = val.location();
7850 }
7851
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007852 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007853 Handle<Object> result =
7854 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007855 if (exception) {
7856 return Failure::Exception();
7857 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007858
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007859 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007860 return *result;
7861}
7862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007863
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007864static void TrySettingInlineConstructStub(Isolate* isolate,
7865 Handle<JSFunction> function) {
7866 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007867 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007868 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007869 }
7870 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007871 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007872 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007873 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007874 function->shared()->set_construct_stub(
7875 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007876 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007877 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007878}
7879
7880
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007881RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007882 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007883 ASSERT(args.length() == 1);
7884
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007885 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007886
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007887 // If the constructor isn't a proper function we throw a type error.
7888 if (!constructor->IsJSFunction()) {
7889 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7890 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007891 isolate->factory()->NewTypeError("not_constructor", arguments);
7892 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007893 }
7894
7895 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007896
7897 // If function should not have prototype, construction is not allowed. In this
7898 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007899 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007900 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7901 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007902 isolate->factory()->NewTypeError("not_constructor", arguments);
7903 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007904 }
7905
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007906#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007907 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007908 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007909 if (debug->StepInActive()) {
7910 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007911 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007912#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007913
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007914 if (function->has_initial_map()) {
7915 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916 // The 'Function' function ignores the receiver object when
7917 // called using 'new' and creates a new JSFunction object that
7918 // is returned. The receiver object is only used for error
7919 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007920 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007921 // allocate JSFunctions since it does not properly initialize
7922 // the shared part of the function. Since the receiver is
7923 // ignored anyway, we use the global object as the receiver
7924 // instead of a new JSFunction object. This way, errors are
7925 // reported the same way whether or not 'Function' is called
7926 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007927 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007928 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007929 }
7930
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007931 // The function should be compiled for the optimization hints to be
7932 // available. We cannot use EnsureCompiled because that forces a
7933 // compilation through the shared function info which makes it
7934 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007935 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007936 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007937
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007938 if (!function->has_initial_map() &&
7939 shared->IsInobjectSlackTrackingInProgress()) {
7940 // The tracking is already in progress for another function. We can only
7941 // track one initial_map at a time, so we force the completion before the
7942 // function is called as a constructor for the first time.
7943 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007944 }
7945
7946 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007947 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7948 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007949 // Delay setting the stub if inobject slack tracking is in progress.
7950 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007951 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007952 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007953
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007954 isolate->counters()->constructed_objects()->Increment();
7955 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007956
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007957 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007958}
7959
7960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007961RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007962 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007963 ASSERT(args.length() == 1);
7964
7965 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7966 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007967 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007968
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007969 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007970}
7971
7972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007973RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007974 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007975 ASSERT(args.length() == 1);
7976
7977 Handle<JSFunction> function = args.at<JSFunction>(0);
7978#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007979 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007980 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007981 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007982 PrintF("]\n");
7983 }
7984#endif
7985
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007986 // Compile the target function. Here we compile using CompileLazyInLoop in
7987 // order to get the optimized version. This helps code like delta-blue
7988 // that calls performance-critical routines through constructors. A
7989 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7990 // direct call. Since the in-loop tracking takes place through CallICs
7991 // this means that things called through constructors are never known to
7992 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007993 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007994 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007995 return Failure::Exception();
7996 }
7997
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007998 // All done. Return the compiled code.
7999 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008000 return function->code();
8001}
8002
8003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008004RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008005 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008006 ASSERT(args.length() == 1);
8007 Handle<JSFunction> function = args.at<JSFunction>(0);
8008 // If the function is not optimizable or debugger is active continue using the
8009 // code from the full compiler.
8010 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008011 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008012 if (FLAG_trace_opt) {
8013 PrintF("[failed to optimize ");
8014 function->PrintName();
8015 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8016 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008017 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008018 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008019 function->ReplaceCode(function->shared()->code());
8020 return function->code();
8021 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008022 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008023 return function->code();
8024 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008025 if (FLAG_trace_opt) {
8026 PrintF("[failed to optimize ");
8027 function->PrintName();
8028 PrintF(": optimized compilation failed]\n");
8029 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008030 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008031 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008032}
8033
8034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008035RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008036 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008037 ASSERT(args.length() == 1);
8038 RUNTIME_ASSERT(args[0]->IsSmi());
8039 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008040 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008041 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8042 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008043 int frames = deoptimizer->output_count();
8044
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008045 deoptimizer->MaterializeHeapNumbers();
8046 delete deoptimizer;
8047
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008048 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008049 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008050 for (int i = 0; i < frames - 1; i++) it.Advance();
8051 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008052
8053 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008054 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008055 Handle<Object> arguments;
8056 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008057 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008058 if (arguments.is_null()) {
8059 // FunctionGetArguments can't throw an exception, so cast away the
8060 // doubt with an assert.
8061 arguments = Handle<Object>(
8062 Accessors::FunctionGetArguments(*function,
8063 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008064 ASSERT(*arguments != isolate->heap()->null_value());
8065 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008066 }
8067 frame->SetExpression(i, *arguments);
8068 }
8069 }
8070
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008071 if (type == Deoptimizer::EAGER) {
8072 RUNTIME_ASSERT(function->IsOptimized());
8073 } else {
8074 RUNTIME_ASSERT(!function->IsOptimized());
8075 }
8076
8077 // Avoid doing too much work when running with --always-opt and keep
8078 // the optimized code around.
8079 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008080 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008081 }
8082
8083 // Count the number of optimized activations of the function.
8084 int activations = 0;
8085 while (!it.done()) {
8086 JavaScriptFrame* frame = it.frame();
8087 if (frame->is_optimized() && frame->function() == *function) {
8088 activations++;
8089 }
8090 it.Advance();
8091 }
8092
8093 // TODO(kasperl): For now, we cannot support removing the optimized
8094 // code when we have recursive invocations of the same function.
8095 if (activations == 0) {
8096 if (FLAG_trace_deopt) {
8097 PrintF("[removing optimized code for: ");
8098 function->PrintName();
8099 PrintF("]\n");
8100 }
8101 function->ReplaceCode(function->shared()->code());
8102 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008103 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008104}
8105
8106
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008107RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008108 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008109 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008110 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008111}
8112
8113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008114RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008115 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008116 ASSERT(args.length() == 1);
8117 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008118 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008119
8120 Deoptimizer::DeoptimizeFunction(*function);
8121
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008122 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008123}
8124
8125
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008126RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8127#if defined(USE_SIMULATOR)
8128 return isolate->heap()->true_value();
8129#else
8130 return isolate->heap()->false_value();
8131#endif
8132}
8133
8134
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008135RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8136 HandleScope scope(isolate);
8137 ASSERT(args.length() == 1);
8138 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8139 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8140 function->MarkForLazyRecompilation();
8141 return isolate->heap()->undefined_value();
8142}
8143
8144
lrn@chromium.org1c092762011-05-09 09:42:16 +00008145RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8146 HandleScope scope(isolate);
8147 ASSERT(args.length() == 1);
8148 if (!V8::UseCrankshaft()) {
8149 return Smi::FromInt(4); // 4 == "never".
8150 }
8151 if (FLAG_always_opt) {
8152 return Smi::FromInt(3); // 3 == "always".
8153 }
8154 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8155 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8156 : Smi::FromInt(2); // 2 == "no".
8157}
8158
8159
8160RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8161 HandleScope scope(isolate);
8162 ASSERT(args.length() == 1);
8163 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8164 return Smi::FromInt(function->shared()->opt_count());
8165}
8166
8167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008168RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008169 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008170 ASSERT(args.length() == 1);
8171 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8172
8173 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008174 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008175
8176 // We have hit a back edge in an unoptimized frame for a function that was
8177 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008178 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 // Keep track of whether we've succeeded in optimizing.
8180 bool succeeded = unoptimized->optimizable();
8181 if (succeeded) {
8182 // If we are trying to do OSR when there are already optimized
8183 // activations of the function, it means (a) the function is directly or
8184 // indirectly recursive and (b) an optimized invocation has been
8185 // deoptimized so that we are currently in an unoptimized activation.
8186 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008187 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008188 while (succeeded && !it.done()) {
8189 JavaScriptFrame* frame = it.frame();
8190 succeeded = !frame->is_optimized() || frame->function() != *function;
8191 it.Advance();
8192 }
8193 }
8194
8195 int ast_id = AstNode::kNoNumber;
8196 if (succeeded) {
8197 // The top JS function is this one, the PC is somewhere in the
8198 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008199 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008200 JavaScriptFrame* frame = it.frame();
8201 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008202 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008203 ASSERT(unoptimized->contains(frame->pc()));
8204
8205 // Use linear search of the unoptimized code's stack check table to find
8206 // the AST id matching the PC.
8207 Address start = unoptimized->instruction_start();
8208 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008209 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008210 uint32_t table_length = Memory::uint32_at(table_cursor);
8211 table_cursor += kIntSize;
8212 for (unsigned i = 0; i < table_length; ++i) {
8213 // Table entries are (AST id, pc offset) pairs.
8214 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8215 if (pc_offset == target_pc_offset) {
8216 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8217 break;
8218 }
8219 table_cursor += 2 * kIntSize;
8220 }
8221 ASSERT(ast_id != AstNode::kNoNumber);
8222 if (FLAG_trace_osr) {
8223 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8224 function->PrintName();
8225 PrintF("]\n");
8226 }
8227
8228 // Try to compile the optimized code. A true return value from
8229 // CompileOptimized means that compilation succeeded, not necessarily
8230 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008231 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8232 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008233 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8234 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008235 if (data->OsrPcOffset()->value() >= 0) {
8236 if (FLAG_trace_osr) {
8237 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008238 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008239 }
8240 ASSERT(data->OsrAstId()->value() == ast_id);
8241 } else {
8242 // We may never generate the desired OSR entry if we emit an
8243 // early deoptimize.
8244 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008245 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008246 } else {
8247 succeeded = false;
8248 }
8249 }
8250
8251 // Revert to the original stack checks in the original unoptimized code.
8252 if (FLAG_trace_osr) {
8253 PrintF("[restoring original stack checks in ");
8254 function->PrintName();
8255 PrintF("]\n");
8256 }
8257 StackCheckStub check_stub;
8258 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008259 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008260 Deoptimizer::RevertStackCheckCode(*unoptimized,
8261 *check_code,
8262 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008263
8264 // Allow OSR only at nesting level zero again.
8265 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8266
8267 // If the optimization attempt succeeded, return the AST id tagged as a
8268 // smi. This tells the builtin that we need to translate the unoptimized
8269 // frame to an optimized one.
8270 if (succeeded) {
8271 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8272 return Smi::FromInt(ast_id);
8273 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008274 if (function->IsMarkedForLazyRecompilation()) {
8275 function->ReplaceCode(function->shared()->code());
8276 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008277 return Smi::FromInt(-1);
8278 }
8279}
8280
8281
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008282RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8283 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8284 return isolate->heap()->undefined_value();
8285}
8286
8287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008288RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290 ASSERT(args.length() == 1);
8291 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8292 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8293}
8294
8295
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008296RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008297 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008298 ASSERT(args.length() == 1);
8299 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8300 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8301}
8302
8303
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008304RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008306 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008307
kasper.lund7276f142008-07-30 08:49:36 +00008308 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008309 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008310 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008311 { MaybeObject* maybe_result =
8312 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008313 if (!maybe_result->ToObject(&result)) return maybe_result;
8314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008316 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317
kasper.lund7276f142008-07-30 08:49:36 +00008318 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319}
8320
lrn@chromium.org303ada72010-10-27 09:33:13 +00008321
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008322RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8323 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008324 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008325 JSObject* extension_object;
8326 if (args[0]->IsJSObject()) {
8327 extension_object = JSObject::cast(args[0]);
8328 } else {
8329 // Convert the object to a proper JavaScript object.
8330 MaybeObject* maybe_js_object = args[0]->ToObject();
8331 if (!maybe_js_object->To(&extension_object)) {
8332 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8333 HandleScope scope(isolate);
8334 Handle<Object> handle = args.at<Object>(0);
8335 Handle<Object> result =
8336 isolate->factory()->NewTypeError("with_expression",
8337 HandleVector(&handle, 1));
8338 return isolate->Throw(*result);
8339 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008340 return maybe_js_object;
8341 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008342 }
8343 }
8344
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008345 JSFunction* function;
8346 if (args[1]->IsSmi()) {
8347 // A smi sentinel indicates a context nested inside global code rather
8348 // than some function. There is a canonical empty function that can be
8349 // gotten from the global context.
8350 function = isolate->context()->global_context()->closure();
8351 } else {
8352 function = JSFunction::cast(args[1]);
8353 }
8354
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008355 Context* context;
8356 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008357 isolate->heap()->AllocateWithContext(function,
8358 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008359 extension_object);
8360 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008361 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008362 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008363}
8364
8365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008366RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008367 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008368 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008369 String* name = String::cast(args[0]);
8370 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008371 JSFunction* function;
8372 if (args[2]->IsSmi()) {
8373 // A smi sentinel indicates a context nested inside global code rather
8374 // than some function. There is a canonical empty function that can be
8375 // gotten from the global context.
8376 function = isolate->context()->global_context()->closure();
8377 } else {
8378 function = JSFunction::cast(args[2]);
8379 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008380 Context* context;
8381 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008382 isolate->heap()->AllocateCatchContext(function,
8383 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008384 name,
8385 thrown_object);
8386 if (!maybe_context->To(&context)) return maybe_context;
8387 isolate->set_context(context);
8388 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008389}
8390
8391
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008392RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8393 NoHandleAllocation ha;
8394 ASSERT(args.length() == 2);
8395 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8396 JSFunction* function;
8397 if (args[1]->IsSmi()) {
8398 // A smi sentinel indicates a context nested inside global code rather
8399 // than some function. There is a canonical empty function that can be
8400 // gotten from the global context.
8401 function = isolate->context()->global_context()->closure();
8402 } else {
8403 function = JSFunction::cast(args[1]);
8404 }
8405 Context* context;
8406 MaybeObject* maybe_context =
8407 isolate->heap()->AllocateBlockContext(function,
8408 isolate->context(),
8409 scope_info);
8410 if (!maybe_context->To(&context)) return maybe_context;
8411 isolate->set_context(context);
8412 return context;
8413}
8414
8415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008416RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008418 ASSERT(args.length() == 2);
8419
8420 CONVERT_ARG_CHECKED(Context, context, 0);
8421 CONVERT_ARG_CHECKED(String, name, 1);
8422
8423 int index;
8424 PropertyAttributes attributes;
8425 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008426 BindingFlags binding_flags;
8427 Handle<Object> holder = context->Lookup(name,
8428 flags,
8429 &index,
8430 &attributes,
8431 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008432
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008433 // If the slot was not found the result is true.
8434 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008435 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008436 }
8437
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008438 // If the slot was found in a context, it should be DONT_DELETE.
8439 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008441 }
8442
8443 // The slot was found in a JSObject, either a context extension object,
8444 // the global object, or an arguments object. Try to delete it
8445 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8446 // which allows deleting all parameters in functions that mention
8447 // 'arguments', we do this even for the case of slots found on an
8448 // arguments object. The slot was found on an arguments object if the
8449 // index is non-negative.
8450 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8451 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008452 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008453 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008454 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008455 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008456}
8457
8458
ager@chromium.orga1645e22009-09-09 19:27:10 +00008459// A mechanism to return a pair of Object pointers in registers (if possible).
8460// How this is achieved is calling convention-dependent.
8461// All currently supported x86 compiles uses calling conventions that are cdecl
8462// variants where a 64-bit value is returned in two 32-bit registers
8463// (edx:eax on ia32, r1:r0 on ARM).
8464// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8465// In Win64 calling convention, a struct of two pointers is returned in memory,
8466// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008467#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008468struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008469 MaybeObject* x;
8470 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008471};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008472
lrn@chromium.org303ada72010-10-27 09:33:13 +00008473static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008474 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008475 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8476 // In Win64 they are assigned to a hidden first argument.
8477 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008478}
8479#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008480typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008481static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008482 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008483 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008484}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008485#endif
8486
8487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008488static inline MaybeObject* Unhole(Heap* heap,
8489 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008490 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008491 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8492 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008493 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008494}
8495
8496
danno@chromium.org40cb8782011-05-25 07:58:50 +00008497static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8498 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008499 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008501 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008502 JSFunction* context_extension_function =
8503 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008504 // If the holder isn't a context extension object, we just return it
8505 // as the receiver. This allows arguments objects to be used as
8506 // receivers, but only if they are put in the context scope chain
8507 // explicitly via a with-statement.
8508 Object* constructor = holder->map()->constructor();
8509 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008510 // Fall back to using the global object as the implicit receiver if
8511 // the property turns out to be a local variable allocated in a
8512 // context extension object - introduced via eval. Implicit global
8513 // receivers are indicated with the hole value.
8514 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008515}
8516
8517
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008518static ObjectPair LoadContextSlotHelper(Arguments args,
8519 Isolate* isolate,
8520 bool throw_error) {
8521 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008522 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008523
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008524 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008525 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008526 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008527 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008528 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529
8530 int index;
8531 PropertyAttributes attributes;
8532 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008533 BindingFlags binding_flags;
8534 Handle<Object> holder = context->Lookup(name,
8535 flags,
8536 &index,
8537 &attributes,
8538 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008539
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008540 // If the index is non-negative, the slot has been found in a local
8541 // variable or a parameter. Read it from the context object or the
8542 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008543 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008544 // If the "property" we were looking for is a local variable or an
8545 // argument in a context, the receiver is the global object; see
8546 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008547 //
8548 // Use the hole as the receiver to signal that the receiver is
8549 // implicit and that the global receiver should be used.
8550 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008551 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008552 ? Context::cast(*holder)->get(index)
8553 : JSObject::cast(*holder)->GetElement(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008554 // Check for uninitialized bindings.
8555 if (holder->IsContext() &&
8556 binding_flags == MUTABLE_CHECK_INITIALIZED &&
8557 value->IsTheHole()) {
8558 Handle<Object> reference_error =
8559 isolate->factory()->NewReferenceError("not_defined",
8560 HandleVector(&name, 1));
8561 return MakePair(isolate->Throw(*reference_error), NULL);
8562 } else {
8563 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8564 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008565 }
8566
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008567 // If the holder is found, we read the property from it.
8568 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008569 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008570 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008571 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008572 if (object->IsGlobalObject()) {
8573 receiver = GlobalObject::cast(object)->global_receiver();
8574 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008575 // Use the hole as the receiver to signal that the receiver is
8576 // implicit and that the global receiver should be used.
8577 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008578 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008579 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008580 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008581
8582 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008583 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008584
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008585 // No need to unhole the value here. This is taken care of by the
8586 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008587 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008588 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589 }
8590
8591 if (throw_error) {
8592 // The property doesn't exist - throw exception.
8593 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008594 isolate->factory()->NewReferenceError("not_defined",
8595 HandleVector(&name, 1));
8596 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008597 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008598 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008599 return MakePair(isolate->heap()->undefined_value(),
8600 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008601 }
8602}
8603
8604
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008605RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008606 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607}
8608
8609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008610RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008611 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008612}
8613
8614
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008615RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008616 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008617 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008618
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008619 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008620 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008621 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008622 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008623 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8624 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008625 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008626
8627 int index;
8628 PropertyAttributes attributes;
8629 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008630 BindingFlags binding_flags;
8631 Handle<Object> holder = context->Lookup(name,
8632 flags,
8633 &index,
8634 &attributes,
8635 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008636
8637 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008638 if (holder->IsContext()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008639 Handle<Context> context = Handle<Context>::cast(holder);
8640 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8641 context->get(index)->IsTheHole()) {
8642 Handle<Object> error =
8643 isolate->factory()->NewReferenceError("not_defined",
8644 HandleVector(&name, 1));
8645 return isolate->Throw(*error);
8646 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008647 // Ignore if read_only variable.
8648 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008649 // Context is a fixed array and set cannot fail.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008650 context->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008651 } else if (strict_mode == kStrictMode) {
8652 // Setting read only property in strict mode.
8653 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008654 isolate->factory()->NewTypeError("strict_cannot_assign",
8655 HandleVector(&name, 1));
8656 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008657 }
8658 } else {
8659 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008660 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008661 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008662 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008663 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008664 return Failure::Exception();
8665 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008666 }
8667 return *value;
8668 }
8669
8670 // Slow case: The property is not in a FixedArray context.
8671 // It is either in an JSObject extension context or it was not found.
8672 Handle<JSObject> context_ext;
8673
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008674 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008675 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008676 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008677 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008678 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008680
8681 if (strict_mode == kStrictMode) {
8682 // Throw in strict mode (assignment to undefined variable).
8683 Handle<Object> error =
8684 isolate->factory()->NewReferenceError(
8685 "not_defined", HandleVector(&name, 1));
8686 return isolate->Throw(*error);
8687 }
8688 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008689 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008690 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691 }
8692
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008693 // Set the property, but ignore if read_only variable on the context
8694 // extension object itself.
8695 if ((attributes & READ_ONLY) == 0 ||
8696 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008697 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008698 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008699 SetProperty(context_ext, name, value, NONE, strict_mode));
8700 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008701 // Setting read only property in strict mode.
8702 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008703 isolate->factory()->NewTypeError(
8704 "strict_cannot_assign", HandleVector(&name, 1));
8705 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008706 }
8707 return *value;
8708}
8709
8710
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008711RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008712 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008713 ASSERT(args.length() == 1);
8714
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008715 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008716}
8717
8718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008719RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008720 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008721 ASSERT(args.length() == 1);
8722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008723 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008724}
8725
8726
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008727RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008728 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008729 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008730}
8731
8732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008733RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008734 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008735 ASSERT(args.length() == 1);
8736
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008737 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008738 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008739 isolate->factory()->NewReferenceError("not_defined",
8740 HandleVector(&name, 1));
8741 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008742}
8743
8744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008745RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008746 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008747
8748 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008749 if (isolate->stack_guard()->IsStackOverflow()) {
8750 NoHandleAllocation na;
8751 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008752 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008753
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008754 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008755}
8756
8757
8758// NOTE: These PrintXXX functions are defined for all builds (not just
8759// DEBUG builds) because we may want to be able to trace function
8760// calls in all modes.
8761static void PrintString(String* str) {
8762 // not uncommon to have empty strings
8763 if (str->length() > 0) {
8764 SmartPointer<char> s =
8765 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8766 PrintF("%s", *s);
8767 }
8768}
8769
8770
8771static void PrintObject(Object* obj) {
8772 if (obj->IsSmi()) {
8773 PrintF("%d", Smi::cast(obj)->value());
8774 } else if (obj->IsString() || obj->IsSymbol()) {
8775 PrintString(String::cast(obj));
8776 } else if (obj->IsNumber()) {
8777 PrintF("%g", obj->Number());
8778 } else if (obj->IsFailure()) {
8779 PrintF("<failure>");
8780 } else if (obj->IsUndefined()) {
8781 PrintF("<undefined>");
8782 } else if (obj->IsNull()) {
8783 PrintF("<null>");
8784 } else if (obj->IsTrue()) {
8785 PrintF("<true>");
8786 } else if (obj->IsFalse()) {
8787 PrintF("<false>");
8788 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008789 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790 }
8791}
8792
8793
8794static int StackSize() {
8795 int n = 0;
8796 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8797 return n;
8798}
8799
8800
8801static void PrintTransition(Object* result) {
8802 // indentation
8803 { const int nmax = 80;
8804 int n = StackSize();
8805 if (n <= nmax)
8806 PrintF("%4d:%*s", n, n, "");
8807 else
8808 PrintF("%4d:%*s", n, nmax, "...");
8809 }
8810
8811 if (result == NULL) {
8812 // constructor calls
8813 JavaScriptFrameIterator it;
8814 JavaScriptFrame* frame = it.frame();
8815 if (frame->IsConstructor()) PrintF("new ");
8816 // function name
8817 Object* fun = frame->function();
8818 if (fun->IsJSFunction()) {
8819 PrintObject(JSFunction::cast(fun)->shared()->name());
8820 } else {
8821 PrintObject(fun);
8822 }
8823 // function arguments
8824 // (we are intentionally only printing the actually
8825 // supplied parameters, not all parameters required)
8826 PrintF("(this=");
8827 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008828 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008829 for (int i = 0; i < length; i++) {
8830 PrintF(", ");
8831 PrintObject(frame->GetParameter(i));
8832 }
8833 PrintF(") {\n");
8834
8835 } else {
8836 // function result
8837 PrintF("} -> ");
8838 PrintObject(result);
8839 PrintF("\n");
8840 }
8841}
8842
8843
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008844RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008845 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008846 NoHandleAllocation ha;
8847 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008848 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008849}
8850
8851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008852RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008853 NoHandleAllocation ha;
8854 PrintTransition(args[0]);
8855 return args[0]; // return TOS
8856}
8857
8858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008859RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008860 NoHandleAllocation ha;
8861 ASSERT(args.length() == 1);
8862
8863#ifdef DEBUG
8864 if (args[0]->IsString()) {
8865 // If we have a string, assume it's a code "marker"
8866 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008867 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008868 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008869 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8870 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008871 } else {
8872 PrintF("DebugPrint: ");
8873 }
8874 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008875 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008876 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008877 HeapObject::cast(args[0])->map()->Print();
8878 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008879#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008880 // ShortPrint is available in release mode. Print is not.
8881 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882#endif
8883 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008884 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008885
8886 return args[0]; // return TOS
8887}
8888
8889
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008890RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008891 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008892 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008893 isolate->PrintStack();
8894 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008895}
8896
8897
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008898RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008899 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008900 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008901
8902 // According to ECMA-262, section 15.9.1, page 117, the precision of
8903 // the number in a Date object representing a particular instant in
8904 // time is milliseconds. Therefore, we floor the result of getting
8905 // the OS time.
8906 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008908}
8909
8910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008911RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008913 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008914
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008915 CONVERT_ARG_CHECKED(String, str, 0);
8916 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008917
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008918 CONVERT_ARG_CHECKED(JSArray, output, 1);
8919 RUNTIME_ASSERT(output->HasFastElements());
8920
8921 AssertNoAllocation no_allocation;
8922
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008923 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008924 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8925 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008926 String::FlatContent str_content = str->GetFlatContent();
8927 if (str_content.IsAscii()) {
8928 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008929 output_array,
8930 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008931 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008932 ASSERT(str_content.IsTwoByte());
8933 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008934 output_array,
8935 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008936 }
8937
8938 if (result) {
8939 return *output;
8940 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008942 }
8943}
8944
8945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008946RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008947 NoHandleAllocation ha;
8948 ASSERT(args.length() == 1);
8949
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008950 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008951 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008953}
8954
8955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008956RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008958 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008960 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008961}
8962
8963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008964RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008965 NoHandleAllocation ha;
8966 ASSERT(args.length() == 1);
8967
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008968 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008970}
8971
8972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008973RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008974 ASSERT(args.length() == 1);
8975 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008976 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008977 return JSGlobalObject::cast(global)->global_receiver();
8978}
8979
8980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008981RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008982 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008983 ASSERT_EQ(1, args.length());
8984 CONVERT_ARG_CHECKED(String, source, 0);
8985
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008986 source = Handle<String>(source->TryFlattenGetString());
8987 // Optimized fast case where we only have ascii characters.
8988 Handle<Object> result;
8989 if (source->IsSeqAsciiString()) {
8990 result = JsonParser<true>::Parse(source);
8991 } else {
8992 result = JsonParser<false>::Parse(source);
8993 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008994 if (result.is_null()) {
8995 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008996 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008997 return Failure::Exception();
8998 }
8999 return *result;
9000}
9001
9002
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009003bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9004 Handle<Context> context) {
9005 if (context->allow_code_gen_from_strings()->IsFalse()) {
9006 // Check with callback if set.
9007 AllowCodeGenerationFromStringsCallback callback =
9008 isolate->allow_code_gen_callback();
9009 if (callback == NULL) {
9010 // No callback set and code generation disallowed.
9011 return false;
9012 } else {
9013 // Callback set. Let it decide if code generation is allowed.
9014 VMState state(isolate, EXTERNAL);
9015 return callback(v8::Utils::ToLocal(context));
9016 }
9017 }
9018 return true;
9019}
9020
9021
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009022RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009023 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009024 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009025 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009026
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009027 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009028 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009029
9030 // Check if global context allows code generation from
9031 // strings. Throw an exception if it doesn't.
9032 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9033 return isolate->Throw(*isolate->factory()->NewError(
9034 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9035 }
9036
9037 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009038 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9039 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009040 true,
9041 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009042 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009043 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009044 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9045 context,
9046 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047 return *fun;
9048}
9049
9050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009051static ObjectPair CompileGlobalEval(Isolate* isolate,
9052 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009053 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009054 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009055 Handle<Context> context = Handle<Context>(isolate->context());
9056 Handle<Context> global_context = Handle<Context>(context->global_context());
9057
9058 // Check if global context allows code generation from
9059 // strings. Throw an exception if it doesn't.
9060 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9061 isolate->Throw(*isolate->factory()->NewError(
9062 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9063 return MakePair(Failure::Exception(), NULL);
9064 }
9065
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009066 // Deal with a normal eval call with a string argument. Compile it
9067 // and return the compiled function bound in the local context.
9068 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9069 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009070 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009071 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009072 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009073 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009074 Handle<JSFunction> compiled =
9075 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009076 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009077 return MakePair(*compiled, *receiver);
9078}
9079
9080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009081RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009082 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009083
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009084 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009085 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009086 Handle<Object> receiver; // Will be overwritten.
9087
9088 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009089 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009090#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009091 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009092 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009093 StackFrameLocator locator;
9094 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009095 ASSERT(Context::cast(frame->context()) == *context);
9096#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009097
9098 // Find where the 'eval' symbol is bound. It is unaliased only if
9099 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009100 int index = -1;
9101 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009102 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009103 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9105 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009106 &index,
9107 &attributes,
9108 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009109 // Stop search when eval is found or when the global context is
9110 // reached.
9111 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009112 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009113 }
9114
iposva@chromium.org245aa852009-02-10 00:49:54 +00009115 // If eval could not be resolved, it has been deleted and we need to
9116 // throw a reference error.
9117 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009118 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009119 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009120 isolate->factory()->NewReferenceError("not_defined",
9121 HandleVector(&name, 1));
9122 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009123 }
9124
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009125 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009126 // 'eval' is not bound in the global context. Just call the function
9127 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009128 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009129 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009130 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009131 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009132 }
9133
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009134 // 'eval' is bound in the global context, but it may have been overwritten.
9135 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009137 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009138 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009139 }
9140
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009141 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009142 return CompileGlobalEval(isolate,
9143 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009144 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009145 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009146}
9147
9148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009149RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009150 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009151
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009152 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009153 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009154
9155 // 'eval' is bound in the global context, but it may have been overwritten.
9156 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009157 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009158 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009159 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009160 }
9161
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009162 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009163 return CompileGlobalEval(isolate,
9164 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009165 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009166 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009167}
9168
9169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009170RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 // This utility adjusts the property attributes for newly created Function
9172 // object ("new Function(...)") by changing the map.
9173 // All it does is changing the prototype property to enumerable
9174 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009175 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176 ASSERT(args.length() == 1);
9177 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009178
9179 Handle<Map> map = func->shared()->strict_mode()
9180 ? isolate->strict_mode_function_instance_map()
9181 : isolate->function_instance_map();
9182
9183 ASSERT(func->map()->instance_type() == map->instance_type());
9184 ASSERT(func->map()->instance_size() == map->instance_size());
9185 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009186 return *func;
9187}
9188
9189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009190RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009191 // Allocate a block of memory in NewSpace (filled with a filler).
9192 // Use as fallback for allocation in generated code when NewSpace
9193 // is full.
9194 ASSERT(args.length() == 1);
9195 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9196 int size = size_smi->value();
9197 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9198 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009199 Heap* heap = isolate->heap();
9200 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009201 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009202 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009203 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009204 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009205 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009206 }
9207 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009208 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009209}
9210
9211
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009212// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009213// array. Returns true if the element was pushed on the stack and
9214// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009215RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009216 ASSERT(args.length() == 2);
9217 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009218 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009219 RUNTIME_ASSERT(array->HasFastElements());
9220 int length = Smi::cast(array->length())->value();
9221 FixedArray* elements = FixedArray::cast(array->elements());
9222 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009224 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009225 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009226 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009227 { MaybeObject* maybe_obj =
9228 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009229 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9230 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009231 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009232}
9233
9234
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009235/**
9236 * A simple visitor visits every element of Array's.
9237 * The backend storage can be a fixed array for fast elements case,
9238 * or a dictionary for sparse array. Since Dictionary is a subtype
9239 * of FixedArray, the class can be used by both fast and slow cases.
9240 * The second parameter of the constructor, fast_elements, specifies
9241 * whether the storage is a FixedArray or Dictionary.
9242 *
9243 * An index limit is used to deal with the situation that a result array
9244 * length overflows 32-bit non-negative integer.
9245 */
9246class ArrayConcatVisitor {
9247 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009248 ArrayConcatVisitor(Isolate* isolate,
9249 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009250 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009251 isolate_(isolate),
9252 storage_(Handle<FixedArray>::cast(
9253 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009254 index_offset_(0u),
9255 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009256
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009257 ~ArrayConcatVisitor() {
9258 clear_storage();
9259 }
9260
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009261 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009262 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009263 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009264
9265 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009266 if (index < static_cast<uint32_t>(storage_->length())) {
9267 storage_->set(index, *elm);
9268 return;
9269 }
9270 // Our initial estimate of length was foiled, possibly by
9271 // getters on the arrays increasing the length of later arrays
9272 // during iteration.
9273 // This shouldn't happen in anything but pathological cases.
9274 SetDictionaryMode(index);
9275 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009276 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009277 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009278 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009279 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009280 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009281 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009282 // Dictionary needed to grow.
9283 clear_storage();
9284 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009285 }
9286}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009287
9288 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009289 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9290 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009291 } else {
9292 index_offset_ += delta;
9293 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009294 }
9295
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009296 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009297 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009298 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009299 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009300 Handle<Map> map;
9301 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009302 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009303 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009304 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009305 }
9306 array->set_map(*map);
9307 array->set_length(*length);
9308 array->set_elements(*storage_);
9309 return array;
9310 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009311
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009312 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009313 // Convert storage to dictionary mode.
9314 void SetDictionaryMode(uint32_t index) {
9315 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009316 Handle<FixedArray> current_storage(*storage_);
9317 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009318 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009319 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9320 for (uint32_t i = 0; i < current_length; i++) {
9321 HandleScope loop_scope;
9322 Handle<Object> element(current_storage->get(i));
9323 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009324 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009325 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009326 if (!new_storage.is_identical_to(slow_storage)) {
9327 slow_storage = loop_scope.CloseAndEscape(new_storage);
9328 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009329 }
9330 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009331 clear_storage();
9332 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009333 fast_elements_ = false;
9334 }
9335
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009336 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009337 isolate_->global_handles()->Destroy(
9338 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009339 }
9340
9341 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009342 storage_ = Handle<FixedArray>::cast(
9343 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009344 }
9345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009346 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009347 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009348 // Index after last seen index. Always less than or equal to
9349 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009350 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009351 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009352};
9353
9354
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009355static uint32_t EstimateElementCount(Handle<JSArray> array) {
9356 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9357 int element_count = 0;
9358 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009359 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009360 // Fast elements can't have lengths that are not representable by
9361 // a 32-bit signed integer.
9362 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9363 int fast_length = static_cast<int>(length);
9364 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9365 for (int i = 0; i < fast_length; i++) {
9366 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009367 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009368 break;
9369 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009370 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009371 Handle<NumberDictionary> dictionary(
9372 NumberDictionary::cast(array->elements()));
9373 int capacity = dictionary->Capacity();
9374 for (int i = 0; i < capacity; i++) {
9375 Handle<Object> key(dictionary->KeyAt(i));
9376 if (dictionary->IsKey(*key)) {
9377 element_count++;
9378 }
9379 }
9380 break;
9381 }
9382 default:
9383 // External arrays are always dense.
9384 return length;
9385 }
9386 // As an estimate, we assume that the prototype doesn't contain any
9387 // inherited elements.
9388 return element_count;
9389}
9390
9391
9392
9393template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009394static void IterateExternalArrayElements(Isolate* isolate,
9395 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009396 bool elements_are_ints,
9397 bool elements_are_guaranteed_smis,
9398 ArrayConcatVisitor* visitor) {
9399 Handle<ExternalArrayClass> array(
9400 ExternalArrayClass::cast(receiver->elements()));
9401 uint32_t len = static_cast<uint32_t>(array->length());
9402
9403 ASSERT(visitor != NULL);
9404 if (elements_are_ints) {
9405 if (elements_are_guaranteed_smis) {
9406 for (uint32_t j = 0; j < len; j++) {
9407 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009408 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009409 visitor->visit(j, e);
9410 }
9411 } else {
9412 for (uint32_t j = 0; j < len; j++) {
9413 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009414 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009415 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9416 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9417 visitor->visit(j, e);
9418 } else {
9419 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009420 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009421 visitor->visit(j, e);
9422 }
9423 }
9424 }
9425 } else {
9426 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009427 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009428 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009429 visitor->visit(j, e);
9430 }
9431 }
9432}
9433
9434
9435// Used for sorting indices in a List<uint32_t>.
9436static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9437 uint32_t a = *ap;
9438 uint32_t b = *bp;
9439 return (a == b) ? 0 : (a < b) ? -1 : 1;
9440}
9441
9442
9443static void CollectElementIndices(Handle<JSObject> object,
9444 uint32_t range,
9445 List<uint32_t>* indices) {
9446 JSObject::ElementsKind kind = object->GetElementsKind();
9447 switch (kind) {
9448 case JSObject::FAST_ELEMENTS: {
9449 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9450 uint32_t length = static_cast<uint32_t>(elements->length());
9451 if (range < length) length = range;
9452 for (uint32_t i = 0; i < length; i++) {
9453 if (!elements->get(i)->IsTheHole()) {
9454 indices->Add(i);
9455 }
9456 }
9457 break;
9458 }
9459 case JSObject::DICTIONARY_ELEMENTS: {
9460 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009461 uint32_t capacity = dict->Capacity();
9462 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009463 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009464 Handle<Object> k(dict->KeyAt(j));
9465 if (dict->IsKey(*k)) {
9466 ASSERT(k->IsNumber());
9467 uint32_t index = static_cast<uint32_t>(k->Number());
9468 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009469 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009470 }
9471 }
9472 }
9473 break;
9474 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009475 default: {
9476 int dense_elements_length;
9477 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009478 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009479 dense_elements_length =
9480 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009481 break;
9482 }
9483 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009484 dense_elements_length =
9485 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009486 break;
9487 }
9488 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009489 dense_elements_length =
9490 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009491 break;
9492 }
9493 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009494 dense_elements_length =
9495 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009496 break;
9497 }
9498 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009499 dense_elements_length =
9500 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009501 break;
9502 }
9503 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009504 dense_elements_length =
9505 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009506 break;
9507 }
9508 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009509 dense_elements_length =
9510 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009511 break;
9512 }
9513 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009514 dense_elements_length =
9515 ExternalFloatArray::cast(object->elements())->length();
9516 break;
9517 }
9518 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9519 dense_elements_length =
9520 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009521 break;
9522 }
9523 default:
9524 UNREACHABLE();
9525 dense_elements_length = 0;
9526 break;
9527 }
9528 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9529 if (range <= length) {
9530 length = range;
9531 // We will add all indices, so we might as well clear it first
9532 // and avoid duplicates.
9533 indices->Clear();
9534 }
9535 for (uint32_t i = 0; i < length; i++) {
9536 indices->Add(i);
9537 }
9538 if (length == range) return; // All indices accounted for already.
9539 break;
9540 }
9541 }
9542
9543 Handle<Object> prototype(object->GetPrototype());
9544 if (prototype->IsJSObject()) {
9545 // The prototype will usually have no inherited element indices,
9546 // but we have to check.
9547 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9548 }
9549}
9550
9551
9552/**
9553 * A helper function that visits elements of a JSArray in numerical
9554 * order.
9555 *
9556 * The visitor argument called for each existing element in the array
9557 * with the element index and the element's value.
9558 * Afterwards it increments the base-index of the visitor by the array
9559 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009560 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009561 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009562static bool IterateElements(Isolate* isolate,
9563 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009564 ArrayConcatVisitor* visitor) {
9565 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9566 switch (receiver->GetElementsKind()) {
9567 case JSObject::FAST_ELEMENTS: {
9568 // Run through the elements FixedArray and use HasElement and GetElement
9569 // to check the prototype for missing elements.
9570 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9571 int fast_length = static_cast<int>(length);
9572 ASSERT(fast_length <= elements->length());
9573 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009574 HandleScope loop_scope(isolate);
9575 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009576 if (!element_value->IsTheHole()) {
9577 visitor->visit(j, element_value);
9578 } else if (receiver->HasElement(j)) {
9579 // Call GetElement on receiver, not its prototype, or getters won't
9580 // have the correct receiver.
9581 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009582 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009583 visitor->visit(j, element_value);
9584 }
9585 }
9586 break;
9587 }
9588 case JSObject::DICTIONARY_ELEMENTS: {
9589 Handle<NumberDictionary> dict(receiver->element_dictionary());
9590 List<uint32_t> indices(dict->Capacity() / 2);
9591 // Collect all indices in the object and the prototypes less
9592 // than length. This might introduce duplicates in the indices list.
9593 CollectElementIndices(receiver, length, &indices);
9594 indices.Sort(&compareUInt32);
9595 int j = 0;
9596 int n = indices.length();
9597 while (j < n) {
9598 HandleScope loop_scope;
9599 uint32_t index = indices[j];
9600 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009601 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009602 visitor->visit(index, element);
9603 // Skip to next different index (i.e., omit duplicates).
9604 do {
9605 j++;
9606 } while (j < n && indices[j] == index);
9607 }
9608 break;
9609 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009610 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9611 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9612 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009613 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009614 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009615 visitor->visit(j, e);
9616 }
9617 break;
9618 }
9619 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9620 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009622 break;
9623 }
9624 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9625 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009626 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009627 break;
9628 }
9629 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9630 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009631 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009632 break;
9633 }
9634 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9635 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009636 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009637 break;
9638 }
9639 case JSObject::EXTERNAL_INT_ELEMENTS: {
9640 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009641 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009642 break;
9643 }
9644 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9645 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009646 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009647 break;
9648 }
9649 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9650 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009651 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009652 break;
9653 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009654 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9655 IterateExternalArrayElements<ExternalDoubleArray, double>(
9656 isolate, receiver, false, false, visitor);
9657 break;
9658 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009659 default:
9660 UNREACHABLE();
9661 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009662 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009663 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009664 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009665}
9666
9667
9668/**
9669 * Array::concat implementation.
9670 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009672 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009673 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009674RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009675 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009676 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009677
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009678 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9679 int argument_count = static_cast<int>(arguments->length()->Number());
9680 RUNTIME_ASSERT(arguments->HasFastElements());
9681 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009682
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009683 // Pass 1: estimate the length and number of elements of the result.
9684 // The actual length can be larger if any of the arguments have getters
9685 // that mutate other arguments (but will otherwise be precise).
9686 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009687
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009688 uint32_t estimate_result_length = 0;
9689 uint32_t estimate_nof_elements = 0;
9690 {
9691 for (int i = 0; i < argument_count; i++) {
9692 HandleScope loop_scope;
9693 Handle<Object> obj(elements->get(i));
9694 uint32_t length_estimate;
9695 uint32_t element_estimate;
9696 if (obj->IsJSArray()) {
9697 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9698 length_estimate =
9699 static_cast<uint32_t>(array->length()->Number());
9700 element_estimate =
9701 EstimateElementCount(array);
9702 } else {
9703 length_estimate = 1;
9704 element_estimate = 1;
9705 }
9706 // Avoid overflows by capping at kMaxElementCount.
9707 if (JSObject::kMaxElementCount - estimate_result_length <
9708 length_estimate) {
9709 estimate_result_length = JSObject::kMaxElementCount;
9710 } else {
9711 estimate_result_length += length_estimate;
9712 }
9713 if (JSObject::kMaxElementCount - estimate_nof_elements <
9714 element_estimate) {
9715 estimate_nof_elements = JSObject::kMaxElementCount;
9716 } else {
9717 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009718 }
9719 }
9720 }
9721
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009722 // If estimated number of elements is more than half of length, a
9723 // fixed array (fast case) is more time and space-efficient than a
9724 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009725 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009726
9727 Handle<FixedArray> storage;
9728 if (fast_case) {
9729 // The backing storage array must have non-existing elements to
9730 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009731 storage = isolate->factory()->NewFixedArrayWithHoles(
9732 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009733 } else {
9734 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9735 uint32_t at_least_space_for = estimate_nof_elements +
9736 (estimate_nof_elements >> 2);
9737 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009738 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009739 }
9740
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009741 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009742
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009743 for (int i = 0; i < argument_count; i++) {
9744 Handle<Object> obj(elements->get(i));
9745 if (obj->IsJSArray()) {
9746 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009747 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009748 return Failure::Exception();
9749 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009750 } else {
9751 visitor.visit(0, obj);
9752 visitor.increase_index_offset(1);
9753 }
9754 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009755
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009756 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009757}
9758
9759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009760// This will not allocate (flatten the string), but it may run
9761// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009762RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009763 NoHandleAllocation ha;
9764 ASSERT(args.length() == 1);
9765
9766 CONVERT_CHECKED(String, string, args[0]);
9767 StringInputBuffer buffer(string);
9768 while (buffer.has_more()) {
9769 uint16_t character = buffer.GetNext();
9770 PrintF("%c", character);
9771 }
9772 return string;
9773}
9774
ager@chromium.org5ec48922009-05-05 07:25:34 +00009775// Moves all own elements of an object, that are below a limit, to positions
9776// starting at zero. All undefined values are placed after non-undefined values,
9777// and are followed by non-existing element. Does not change the length
9778// property.
9779// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009780RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009781 ASSERT(args.length() == 2);
9782 CONVERT_CHECKED(JSObject, object, args[0]);
9783 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9784 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009785}
9786
9787
9788// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009789RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009790 ASSERT(args.length() == 2);
9791 CONVERT_CHECKED(JSArray, from, args[0]);
9792 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009793 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009794 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009795 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9796 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009797 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009798 } else if (new_elements->map() ==
9799 isolate->heap()->fixed_double_array_map()) {
9800 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009801 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009802 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009803 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009804 Object* new_map;
9805 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009806 to->set_map(Map::cast(new_map));
9807 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009809 Object* obj;
9810 { MaybeObject* maybe_obj = from->ResetElements();
9811 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9812 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009813 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009814 return to;
9815}
9816
9817
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009818// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009819RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009820 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009821 CONVERT_CHECKED(JSObject, object, args[0]);
9822 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009823 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009824 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009825 } else if (object->IsJSArray()) {
9826 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009827 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009828 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009829 }
9830}
9831
9832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009833RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009834 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009835
9836 ASSERT_EQ(3, args.length());
9837
ager@chromium.orgac091b72010-05-05 07:34:42 +00009838 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009839 Handle<Object> key1 = args.at<Object>(1);
9840 Handle<Object> key2 = args.at<Object>(2);
9841
9842 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009843 if (!key1->ToArrayIndex(&index1)
9844 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009845 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009846 }
9847
ager@chromium.orgac091b72010-05-05 07:34:42 +00009848 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9849 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009850 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009851 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009852 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009854 RETURN_IF_EMPTY_HANDLE(isolate,
9855 SetElement(jsobject, index1, tmp2, kStrictMode));
9856 RETURN_IF_EMPTY_HANDLE(isolate,
9857 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009859 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009860}
9861
9862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009863// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009864// might have elements. Can either return keys (positive integers) or
9865// intervals (pair of a negative integer (-start-1) followed by a
9866// positive (length)) or undefined values.
9867// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009868RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009869 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009870 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009871 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009872 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009873 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009874 // Create an array and get all the keys into it, then remove all the
9875 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009876 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877 int keys_length = keys->length();
9878 for (int i = 0; i < keys_length; i++) {
9879 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009880 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009881 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882 // Zap invalid keys.
9883 keys->set_undefined(i);
9884 }
9885 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009886 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009887 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009888 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009889 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009890 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009891 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009892 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009893 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009894 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009895 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009896 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009897 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009898 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009899 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009900 }
9901}
9902
9903
9904// DefineAccessor takes an optional final argument which is the
9905// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9906// to the way accessors are implemented, it is set for both the getter
9907// and setter on the first call to DefineAccessor and ignored on
9908// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009909RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9911 // Compute attributes.
9912 PropertyAttributes attributes = NONE;
9913 if (args.length() == 5) {
9914 CONVERT_CHECKED(Smi, attrs, args[4]);
9915 int value = attrs->value();
9916 // Only attribute bits should be set.
9917 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9918 attributes = static_cast<PropertyAttributes>(value);
9919 }
9920
9921 CONVERT_CHECKED(JSObject, obj, args[0]);
9922 CONVERT_CHECKED(String, name, args[1]);
9923 CONVERT_CHECKED(Smi, flag, args[2]);
9924 CONVERT_CHECKED(JSFunction, fun, args[3]);
9925 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9926}
9927
9928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009929RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009930 ASSERT(args.length() == 3);
9931 CONVERT_CHECKED(JSObject, obj, args[0]);
9932 CONVERT_CHECKED(String, name, args[1]);
9933 CONVERT_CHECKED(Smi, flag, args[2]);
9934 return obj->LookupAccessor(name, flag->value() == 0);
9935}
9936
9937
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009938#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009939RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009940 ASSERT(args.length() == 0);
9941 return Execution::DebugBreakHelper();
9942}
9943
9944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009945// Helper functions for wrapping and unwrapping stack frame ids.
9946static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009947 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948 return Smi::FromInt(id >> 2);
9949}
9950
9951
9952static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9953 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9954}
9955
9956
9957// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009958// args[0]: debug event listener function to set or null or undefined for
9959// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009960// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009961RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009962 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009963 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9964 args[0]->IsUndefined() ||
9965 args[0]->IsNull());
9966 Handle<Object> callback = args.at<Object>(0);
9967 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009968 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009970 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971}
9972
9973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009974RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009975 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009976 isolate->stack_guard()->DebugBreak();
9977 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978}
9979
9980
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009981static MaybeObject* DebugLookupResultValue(Heap* heap,
9982 Object* receiver,
9983 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009984 LookupResult* result,
9985 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009986 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009987 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009988 case NORMAL:
9989 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009990 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009992 }
9993 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009994 case FIELD:
9995 value =
9996 JSObject::cast(
9997 result->holder())->FastPropertyAt(result->GetFieldIndex());
9998 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009999 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010000 }
10001 return value;
10002 case CONSTANT_FUNCTION:
10003 return result->GetConstantFunction();
10004 case CALLBACKS: {
10005 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010006 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010007 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010008 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010009 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010010 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010011 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010012 maybe_value = heap->isolate()->pending_exception();
10013 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010014 if (caught_exception != NULL) {
10015 *caught_exception = true;
10016 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010017 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010018 }
10019 return value;
10020 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010022 }
10023 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010024 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010025 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010026 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010027 case CONSTANT_TRANSITION:
10028 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010030 default:
10031 UNREACHABLE();
10032 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010033 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010034 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035}
10036
10037
ager@chromium.org32912102009-01-16 10:38:43 +000010038// Get debugger related details for an object property.
10039// args[0]: object holding property
10040// args[1]: name of the property
10041//
10042// The array returned contains the following information:
10043// 0: Property value
10044// 1: Property details
10045// 2: Property value is exception
10046// 3: Getter function if defined
10047// 4: Setter function if defined
10048// Items 2-4 are only filled if the property has either a getter or a setter
10049// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010050RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010052
10053 ASSERT(args.length() == 2);
10054
10055 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10056 CONVERT_ARG_CHECKED(String, name, 1);
10057
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010058 // Make sure to set the current context to the context before the debugger was
10059 // entered (if the debugger is entered). The reason for switching context here
10060 // is that for some property lookups (accessors and interceptors) callbacks
10061 // into the embedding application can occour, and the embedding application
10062 // could have the assumption that its own global context is the current
10063 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010064 SaveContext save(isolate);
10065 if (isolate->debug()->InDebugger()) {
10066 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010067 }
10068
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010069 // Skip the global proxy as it has no properties and always delegates to the
10070 // real global object.
10071 if (obj->IsJSGlobalProxy()) {
10072 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10073 }
10074
10075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010076 // Check if the name is trivially convertible to an index and get the element
10077 // if so.
10078 uint32_t index;
10079 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010080 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010081 Object* element_or_char;
10082 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010083 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010084 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10085 return maybe_element_or_char;
10086 }
10087 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010088 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010089 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010090 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010091 }
10092
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010093 // Find the number of objects making up this.
10094 int length = LocalPrototypeChainLength(*obj);
10095
10096 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010097 Handle<JSObject> jsproto = obj;
10098 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010099 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010100 jsproto->LocalLookup(*name, &result);
10101 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010102 // LookupResult is not GC safe as it holds raw object pointers.
10103 // GC can happen later in this code so put the required fields into
10104 // local variables using handles when required for later use.
10105 PropertyType result_type = result.type();
10106 Handle<Object> result_callback_obj;
10107 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010108 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10109 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010110 }
10111 Smi* property_details = result.GetPropertyDetails().AsSmi();
10112 // DebugLookupResultValue can cause GC so details from LookupResult needs
10113 // to be copied to handles before this.
10114 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010115 Object* raw_value;
10116 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010117 DebugLookupResultValue(isolate->heap(), *obj, *name,
10118 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010119 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10120 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010121 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010122
10123 // If the callback object is a fixed array then it contains JavaScript
10124 // getter and/or setter.
10125 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10126 result_callback_obj->IsFixedArray();
10127 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010128 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010129 details->set(0, *value);
10130 details->set(1, property_details);
10131 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010132 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010133 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10134 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10135 }
10136
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010137 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010138 }
10139 if (i < length - 1) {
10140 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10141 }
10142 }
10143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010144 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010145}
10146
10147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010148RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010149 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010150
10151 ASSERT(args.length() == 2);
10152
10153 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10154 CONVERT_ARG_CHECKED(String, name, 1);
10155
10156 LookupResult result;
10157 obj->Lookup(*name, &result);
10158 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010159 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010161 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162}
10163
10164
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165// Return the property type calculated from the property details.
10166// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010167RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168 ASSERT(args.length() == 1);
10169 CONVERT_CHECKED(Smi, details, args[0]);
10170 PropertyType type = PropertyDetails(details).type();
10171 return Smi::FromInt(static_cast<int>(type));
10172}
10173
10174
10175// Return the property attribute calculated from the property details.
10176// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010177RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010178 ASSERT(args.length() == 1);
10179 CONVERT_CHECKED(Smi, details, args[0]);
10180 PropertyAttributes attributes = PropertyDetails(details).attributes();
10181 return Smi::FromInt(static_cast<int>(attributes));
10182}
10183
10184
10185// Return the property insertion index calculated from the property details.
10186// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010187RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 ASSERT(args.length() == 1);
10189 CONVERT_CHECKED(Smi, details, args[0]);
10190 int index = PropertyDetails(details).index();
10191 return Smi::FromInt(index);
10192}
10193
10194
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010195// Return property value from named interceptor.
10196// args[0]: object
10197// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010198RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200 ASSERT(args.length() == 2);
10201 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10202 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10203 CONVERT_ARG_CHECKED(String, name, 1);
10204
10205 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010206 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010207}
10208
10209
10210// Return element value from indexed interceptor.
10211// args[0]: object
10212// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010213RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010214 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010215 ASSERT(args.length() == 2);
10216 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10217 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10218 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10219
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010220 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010221}
10222
10223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010224RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010225 ASSERT(args.length() >= 1);
10226 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010227 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010228 if (isolate->debug()->break_id() == 0 ||
10229 break_id != isolate->debug()->break_id()) {
10230 return isolate->Throw(
10231 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232 }
10233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010234 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235}
10236
10237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010238RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010239 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 ASSERT(args.length() == 1);
10241
10242 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010243 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010244 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10245 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010246 if (!maybe_result->ToObject(&result)) return maybe_result;
10247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248
10249 // Count all frames which are relevant to debugging stack trace.
10250 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010251 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010252 if (id == StackFrame::NO_ID) {
10253 // If there is no JavaScript stack frame count is 0.
10254 return Smi::FromInt(0);
10255 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010256
10257 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10258 n += it.frame()->GetInlineCount();
10259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010260 return Smi::FromInt(n);
10261}
10262
10263
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010264class FrameInspector {
10265 public:
10266 FrameInspector(JavaScriptFrame* frame,
10267 int inlined_frame_index,
10268 Isolate* isolate)
10269 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10270 // Calculate the deoptimized frame.
10271 if (frame->is_optimized()) {
10272 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10273 frame, inlined_frame_index, isolate);
10274 }
10275 has_adapted_arguments_ = frame_->has_adapted_arguments();
10276 is_optimized_ = frame_->is_optimized();
10277 }
10278
10279 ~FrameInspector() {
10280 // Get rid of the calculated deoptimized frame if any.
10281 if (deoptimized_frame_ != NULL) {
10282 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10283 isolate_);
10284 }
10285 }
10286
10287 int GetParametersCount() {
10288 return is_optimized_
10289 ? deoptimized_frame_->parameters_count()
10290 : frame_->ComputeParametersCount();
10291 }
10292 int expression_count() { return deoptimized_frame_->expression_count(); }
10293 Object* GetFunction() {
10294 return is_optimized_
10295 ? deoptimized_frame_->GetFunction()
10296 : frame_->function();
10297 }
10298 Object* GetParameter(int index) {
10299 return is_optimized_
10300 ? deoptimized_frame_->GetParameter(index)
10301 : frame_->GetParameter(index);
10302 }
10303 Object* GetExpression(int index) {
10304 return is_optimized_
10305 ? deoptimized_frame_->GetExpression(index)
10306 : frame_->GetExpression(index);
10307 }
10308
10309 // To inspect all the provided arguments the frame might need to be
10310 // replaced with the arguments frame.
10311 void SetArgumentsFrame(JavaScriptFrame* frame) {
10312 ASSERT(has_adapted_arguments_);
10313 frame_ = frame;
10314 is_optimized_ = frame_->is_optimized();
10315 ASSERT(!is_optimized_);
10316 }
10317
10318 private:
10319 JavaScriptFrame* frame_;
10320 DeoptimizedFrameInfo* deoptimized_frame_;
10321 Isolate* isolate_;
10322 bool is_optimized_;
10323 bool has_adapted_arguments_;
10324
10325 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10326};
10327
10328
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010329static const int kFrameDetailsFrameIdIndex = 0;
10330static const int kFrameDetailsReceiverIndex = 1;
10331static const int kFrameDetailsFunctionIndex = 2;
10332static const int kFrameDetailsArgumentCountIndex = 3;
10333static const int kFrameDetailsLocalCountIndex = 4;
10334static const int kFrameDetailsSourcePositionIndex = 5;
10335static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010336static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010337static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010338static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339
10340// Return an array with frame details
10341// args[0]: number: break id
10342// args[1]: number: frame index
10343//
10344// The array returned contains the following information:
10345// 0: Frame id
10346// 1: Receiver
10347// 2: Function
10348// 3: Argument count
10349// 4: Local count
10350// 5: Source position
10351// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010352// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010353// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354// Arguments name, value
10355// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010356// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010357RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010358 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010359 ASSERT(args.length() == 2);
10360
10361 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010362 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010363 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10364 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010365 if (!maybe_check->ToObject(&check)) return maybe_check;
10366 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010367 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010368 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010369
10370 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010371 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010372 if (id == StackFrame::NO_ID) {
10373 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010374 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010375 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010376
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010377 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010378
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010379 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010380 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010381 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010382 if (index < count + it.frame()->GetInlineCount()) break;
10383 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010385 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010387 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010388 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010389 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010390 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010391 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010392
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393 // Traverse the saved contexts chain to find the active context for the
10394 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010395 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010396 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397 save = save->prev();
10398 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010399 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400
10401 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010402 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010403
10404 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010405 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010406 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010408 // Check for constructor frame. Inlined frames cannot be construct calls.
10409 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010410 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010411 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010413 // Get scope info and read from it for local variable information.
10414 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010415 Handle<SharedFunctionInfo> shared(function->shared());
10416 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010417 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010418 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420 // Get the locals names and values into a temporary array.
10421 //
10422 // TODO(1240907): Hide compiler-introduced stack variables
10423 // (e.g. .result)? For users of the debugger, they will probably be
10424 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010425 Handle<FixedArray> locals =
10426 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010427
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010428 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010429 int i = 0;
10430 for (; i < info.number_of_stack_slots(); ++i) {
10431 // Use the value from the stack.
10432 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010433 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010434 }
10435 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010436 // Get the context containing declarations.
10437 Handle<Context> context(
10438 Context::cast(it.frame()->context())->declaration_context());
10439 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010440 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010441 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010442 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010443 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010444 }
10445 }
10446
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010447 // Check whether this frame is positioned at return. If not top
10448 // frame or if the frame is optimized it cannot be at a return.
10449 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010450 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010451 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010452 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010453
10454 // If positioned just before return find the value to be returned and add it
10455 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010456 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010457 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010458 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010459 Address internal_frame_sp = NULL;
10460 while (!it2.done()) {
10461 if (it2.frame()->is_internal()) {
10462 internal_frame_sp = it2.frame()->sp();
10463 } else {
10464 if (it2.frame()->is_java_script()) {
10465 if (it2.frame()->id() == it.frame()->id()) {
10466 // The internal frame just before the JavaScript frame contains the
10467 // value to return on top. A debug break at return will create an
10468 // internal frame to store the return value (eax/rax/r0) before
10469 // entering the debug break exit frame.
10470 if (internal_frame_sp != NULL) {
10471 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010472 Handle<Object>(Memory::Object_at(internal_frame_sp),
10473 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010474 break;
10475 }
10476 }
10477 }
10478
10479 // Indicate that the previous frame was not an internal frame.
10480 internal_frame_sp = NULL;
10481 }
10482 it2.Advance();
10483 }
10484 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485
10486 // Now advance to the arguments adapter frame (if any). It contains all
10487 // the provided parameters whereas the function frame always have the number
10488 // of arguments matching the functions parameters. The rest of the
10489 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010490 if (it.frame()->has_adapted_arguments()) {
10491 it.AdvanceToArgumentsFrame();
10492 frame_inspector.SetArgumentsFrame(it.frame());
10493 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010494
10495 // Find the number of arguments to fill. At least fill the number of
10496 // parameters for the function and fill more if more parameters are provided.
10497 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010498 if (argument_count < frame_inspector.GetParametersCount()) {
10499 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010500 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010501#ifdef DEBUG
10502 if (it.frame()->is_optimized()) {
10503 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10504 }
10505#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506
10507 // Calculate the size of the result.
10508 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010509 2 * (argument_count + info.NumberOfLocals()) +
10510 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010511 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010512
10513 // Add the frame id.
10514 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10515
10516 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010517 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518
10519 // Add the arguments count.
10520 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10521
10522 // Add the locals count
10523 details->set(kFrameDetailsLocalCountIndex,
10524 Smi::FromInt(info.NumberOfLocals()));
10525
10526 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010527 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010528 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10529 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010530 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531 }
10532
10533 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010534 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010535
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010536 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010537 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010538
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010539 // Add flags to indicate information on whether this frame is
10540 // bit 0: invoked in the debugger context.
10541 // bit 1: optimized frame.
10542 // bit 2: inlined in optimized frame
10543 int flags = 0;
10544 if (*save->context() == *isolate->debug()->debug_context()) {
10545 flags |= 1 << 0;
10546 }
10547 if (it.frame()->is_optimized()) {
10548 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010549 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010550 }
10551 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010552
10553 // Fill the dynamic part.
10554 int details_index = kFrameDetailsFirstDynamicIndex;
10555
10556 // Add arguments name and value.
10557 for (int i = 0; i < argument_count; i++) {
10558 // Name of the argument.
10559 if (i < info.number_of_parameters()) {
10560 details->set(details_index++, *info.parameter_name(i));
10561 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010562 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563 }
10564
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010565 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010566 if (i < it.frame()->ComputeParametersCount()) {
10567 // Get the value from the stack.
10568 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010569 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010570 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010571 }
10572 }
10573
10574 // Add locals name and value from the temporary copy from the function frame.
10575 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10576 details->set(details_index++, locals->get(i));
10577 }
10578
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010579 // Add the value being returned.
10580 if (at_return) {
10581 details->set(details_index++, *return_value);
10582 }
10583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 // Add the receiver (same as in function frame).
10585 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10586 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010587 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010588 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10589 // If the receiver is not a JSObject and the function is not a
10590 // builtin or strict-mode we have hit an optimization where a
10591 // value object is not converted into a wrapped JS objects. To
10592 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593 // by creating correct wrapper object based on the calling frame's
10594 // global context.
10595 it.Advance();
10596 Handle<Context> calling_frames_global_context(
10597 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010598 receiver =
10599 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600 }
10601 details->set(kFrameDetailsReceiverIndex, *receiver);
10602
10603 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010604 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010605}
10606
10607
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010608// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010609static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010610 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010611 Handle<SerializedScopeInfo> serialized_scope_info,
10612 ScopeInfo<>& scope_info,
10613 Handle<Context> context,
10614 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010615 // Fill all context locals to the context extension.
10616 for (int i = Context::MIN_CONTEXT_SLOTS;
10617 i < scope_info.number_of_context_slots();
10618 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010619 int context_index = serialized_scope_info->ContextSlotIndex(
10620 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010621
whesse@chromium.org7b260152011-06-20 15:33:18 +000010622 RETURN_IF_EMPTY_HANDLE_VALUE(
10623 isolate,
10624 SetProperty(scope_object,
10625 scope_info.context_slot_name(i),
10626 Handle<Object>(context->get(context_index), isolate),
10627 NONE,
10628 kNonStrictMode),
10629 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010630 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010631
10632 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010633}
10634
10635
10636// Create a plain JSObject which materializes the local scope for the specified
10637// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010638static Handle<JSObject> MaterializeLocalScope(
10639 Isolate* isolate,
10640 JavaScriptFrame* frame,
10641 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010642 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010643 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010644 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10645 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010646 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010647
10648 // Allocate and initialize a JSObject with all the arguments, stack locals
10649 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010650 Handle<JSObject> local_scope =
10651 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010652
10653 // First fill all parameters.
10654 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010655 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010656 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010657 SetProperty(local_scope,
10658 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010659 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010660 NONE,
10661 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010662 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010663 }
10664
10665 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010666 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010667 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010668 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010669 SetProperty(local_scope,
10670 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010671 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010672 NONE,
10673 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010674 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010675 }
10676
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010677 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10678 // Third fill all context locals.
10679 Handle<Context> frame_context(Context::cast(frame->context()));
10680 Handle<Context> function_context(frame_context->declaration_context());
10681 if (!CopyContextLocalsToScopeObject(isolate,
10682 serialized_scope_info, scope_info,
10683 function_context, local_scope)) {
10684 return Handle<JSObject>();
10685 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010686
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010687 // Finally copy any properties from the function context extension.
10688 // These will be variables introduced by eval.
10689 if (function_context->closure() == *function) {
10690 if (function_context->has_extension() &&
10691 !function_context->IsGlobalContext()) {
10692 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10693 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10694 for (int i = 0; i < keys->length(); i++) {
10695 // Names of variables introduced by eval are strings.
10696 ASSERT(keys->get(i)->IsString());
10697 Handle<String> key(String::cast(keys->get(i)));
10698 RETURN_IF_EMPTY_HANDLE_VALUE(
10699 isolate,
10700 SetProperty(local_scope,
10701 key,
10702 GetProperty(ext, key),
10703 NONE,
10704 kNonStrictMode),
10705 Handle<JSObject>());
10706 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010707 }
10708 }
10709 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010710
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010711 return local_scope;
10712}
10713
10714
10715// Create a plain JSObject which materializes the closure content for the
10716// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010717static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10718 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010719 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010720
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010721 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010722 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10723 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010724
10725 // Allocate and initialize a JSObject with all the content of theis function
10726 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010727 Handle<JSObject> closure_scope =
10728 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010729
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010730 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010731 if (!CopyContextLocalsToScopeObject(isolate,
10732 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010733 context, closure_scope)) {
10734 return Handle<JSObject>();
10735 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010736
10737 // Finally copy any properties from the function context extension. This will
10738 // be variables introduced by eval.
10739 if (context->has_extension()) {
10740 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010741 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010742 for (int i = 0; i < keys->length(); i++) {
10743 // Names of variables introduced by eval are strings.
10744 ASSERT(keys->get(i)->IsString());
10745 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010746 RETURN_IF_EMPTY_HANDLE_VALUE(
10747 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010748 SetProperty(closure_scope,
10749 key,
10750 GetProperty(ext, key),
10751 NONE,
10752 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010753 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010754 }
10755 }
10756
10757 return closure_scope;
10758}
10759
10760
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010761// Create a plain JSObject which materializes the scope for the specified
10762// catch context.
10763static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10764 Handle<Context> context) {
10765 ASSERT(context->IsCatchContext());
10766 Handle<String> name(String::cast(context->extension()));
10767 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10768 Handle<JSObject> catch_scope =
10769 isolate->factory()->NewJSObject(isolate->object_function());
10770 RETURN_IF_EMPTY_HANDLE_VALUE(
10771 isolate,
10772 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10773 Handle<JSObject>());
10774 return catch_scope;
10775}
10776
10777
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010778// Create a plain JSObject which materializes the block scope for the specified
10779// block context.
10780static Handle<JSObject> MaterializeBlockScope(
10781 Isolate* isolate,
10782 Handle<Context> context) {
10783 ASSERT(context->IsBlockContext());
10784 Handle<SerializedScopeInfo> serialized_scope_info(
10785 SerializedScopeInfo::cast(context->extension()));
10786 ScopeInfo<> scope_info(*serialized_scope_info);
10787
10788 // Allocate and initialize a JSObject with all the arguments, stack locals
10789 // heap locals and extension properties of the debugged function.
10790 Handle<JSObject> block_scope =
10791 isolate->factory()->NewJSObject(isolate->object_function());
10792
10793 // Fill all context locals.
10794 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10795 if (!CopyContextLocalsToScopeObject(isolate,
10796 serialized_scope_info, scope_info,
10797 context, block_scope)) {
10798 return Handle<JSObject>();
10799 }
10800 }
10801
10802 return block_scope;
10803}
10804
10805
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010806// Iterate over the actual scopes visible from a stack frame. All scopes are
10807// backed by an actual context except the local scope, which is inserted
10808// "artifically" in the context chain.
10809class ScopeIterator {
10810 public:
10811 enum ScopeType {
10812 ScopeTypeGlobal = 0,
10813 ScopeTypeLocal,
10814 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010815 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010816 ScopeTypeCatch,
10817 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010818 };
10819
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010820 ScopeIterator(Isolate* isolate,
10821 JavaScriptFrame* frame,
10822 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010823 : isolate_(isolate),
10824 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010825 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010826 function_(JSFunction::cast(frame->function())),
10827 context_(Context::cast(frame->context())),
10828 local_done_(false),
10829 at_local_(false) {
10830
10831 // Check whether the first scope is actually a local scope.
10832 if (context_->IsGlobalContext()) {
10833 // If there is a stack slot for .result then this local scope has been
10834 // created for evaluating top level code and it is not a real local scope.
10835 // Checking for the existence of .result seems fragile, but the scope info
10836 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010837 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010839 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010840 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010841 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010842 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010843 // The context_ is a block or with or catch block from the outer function.
10844 ASSERT(context_->IsWithContext() ||
10845 context_->IsCatchContext() ||
10846 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010847 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010848 }
10849 }
10850
10851 // More scopes?
10852 bool Done() { return context_.is_null(); }
10853
10854 // Move to the next scope.
10855 void Next() {
10856 // If at a local scope mark the local scope as passed.
10857 if (at_local_) {
10858 at_local_ = false;
10859 local_done_ = true;
10860
10861 // If the current context is not associated with the local scope the
10862 // current context is the next real scope, so don't move to the next
10863 // context in this case.
10864 if (context_->closure() != *function_) {
10865 return;
10866 }
10867 }
10868
10869 // The global scope is always the last in the chain.
10870 if (context_->IsGlobalContext()) {
10871 context_ = Handle<Context>();
10872 return;
10873 }
10874
10875 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010876 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010877
10878 // If passing the local scope indicate that the current scope is now the
10879 // local scope.
10880 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010881 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010882 at_local_ = true;
10883 }
10884 }
10885
10886 // Return the type of the current scope.
10887 int Type() {
10888 if (at_local_) {
10889 return ScopeTypeLocal;
10890 }
10891 if (context_->IsGlobalContext()) {
10892 ASSERT(context_->global()->IsGlobalObject());
10893 return ScopeTypeGlobal;
10894 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010895 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010896 return ScopeTypeClosure;
10897 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010898 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010899 return ScopeTypeCatch;
10900 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010901 if (context_->IsBlockContext()) {
10902 return ScopeTypeBlock;
10903 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010904 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010905 return ScopeTypeWith;
10906 }
10907
10908 // Return the JavaScript object with the content of the current scope.
10909 Handle<JSObject> ScopeObject() {
10910 switch (Type()) {
10911 case ScopeIterator::ScopeTypeGlobal:
10912 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010913 case ScopeIterator::ScopeTypeLocal:
10914 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010915 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010916 case ScopeIterator::ScopeTypeWith:
10917 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010918 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10919 case ScopeIterator::ScopeTypeCatch:
10920 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010921 case ScopeIterator::ScopeTypeClosure:
10922 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010923 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010924 case ScopeIterator::ScopeTypeBlock:
10925 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010926 }
10927 UNREACHABLE();
10928 return Handle<JSObject>();
10929 }
10930
10931 // Return the context for this scope. For the local context there might not
10932 // be an actual context.
10933 Handle<Context> CurrentContext() {
10934 if (at_local_ && context_->closure() != *function_) {
10935 return Handle<Context>();
10936 }
10937 return context_;
10938 }
10939
10940#ifdef DEBUG
10941 // Debug print of the content of the current scope.
10942 void DebugPrint() {
10943 switch (Type()) {
10944 case ScopeIterator::ScopeTypeGlobal:
10945 PrintF("Global:\n");
10946 CurrentContext()->Print();
10947 break;
10948
10949 case ScopeIterator::ScopeTypeLocal: {
10950 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010951 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010952 scope_info.Print();
10953 if (!CurrentContext().is_null()) {
10954 CurrentContext()->Print();
10955 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010956 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010957 if (extension->IsJSContextExtensionObject()) {
10958 extension->Print();
10959 }
10960 }
10961 }
10962 break;
10963 }
10964
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010965 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010966 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010967 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010968 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010969
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010970 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010971 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010972 CurrentContext()->extension()->Print();
10973 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010974 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010975
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010976 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010977 PrintF("Closure:\n");
10978 CurrentContext()->Print();
10979 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010980 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010981 if (extension->IsJSContextExtensionObject()) {
10982 extension->Print();
10983 }
10984 }
10985 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010986
10987 default:
10988 UNREACHABLE();
10989 }
10990 PrintF("\n");
10991 }
10992#endif
10993
10994 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010995 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010996 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010997 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010998 Handle<JSFunction> function_;
10999 Handle<Context> context_;
11000 bool local_done_;
11001 bool at_local_;
11002
11003 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11004};
11005
11006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011007RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011008 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011009 ASSERT(args.length() == 2);
11010
11011 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011012 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011013 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11014 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011015 if (!maybe_check->ToObject(&check)) return maybe_check;
11016 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11018
11019 // Get the frame where the debugging is performed.
11020 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011021 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011022 JavaScriptFrame* frame = it.frame();
11023
11024 // Count the visible scopes.
11025 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011026 for (ScopeIterator it(isolate, frame, 0);
11027 !it.Done();
11028 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011029 n++;
11030 }
11031
11032 return Smi::FromInt(n);
11033}
11034
11035
11036static const int kScopeDetailsTypeIndex = 0;
11037static const int kScopeDetailsObjectIndex = 1;
11038static const int kScopeDetailsSize = 2;
11039
11040// Return an array with scope details
11041// args[0]: number: break id
11042// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011043// args[2]: number: inlined frame index
11044// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011045//
11046// The array returned contains the following information:
11047// 0: Scope type
11048// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011049RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011050 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011051 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011052
11053 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011054 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011055 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11056 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011057 if (!maybe_check->ToObject(&check)) return maybe_check;
11058 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011059 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011060 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11061 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011062
11063 // Get the frame where the debugging is performed.
11064 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011065 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011066 JavaScriptFrame* frame = frame_it.frame();
11067
11068 // Find the requested scope.
11069 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011070 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011071 for (; !it.Done() && n < index; it.Next()) {
11072 n++;
11073 }
11074 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011075 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011076 }
11077
11078 // Calculate the size of the result.
11079 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011080 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011081
11082 // Fill in scope details.
11083 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011084 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011085 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011086 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011087
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011088 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011089}
11090
11091
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011092RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011093 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011094 ASSERT(args.length() == 0);
11095
11096#ifdef DEBUG
11097 // Print the scopes for the top frame.
11098 StackFrameLocator locator;
11099 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011100 for (ScopeIterator it(isolate, frame, 0);
11101 !it.Done();
11102 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011103 it.DebugPrint();
11104 }
11105#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011107}
11108
11109
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011110RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011111 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011112 ASSERT(args.length() == 1);
11113
11114 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011115 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011116 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11117 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011118 if (!maybe_result->ToObject(&result)) return maybe_result;
11119 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011120
11121 // Count all archived V8 threads.
11122 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011123 for (ThreadState* thread =
11124 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011125 thread != NULL;
11126 thread = thread->Next()) {
11127 n++;
11128 }
11129
11130 // Total number of threads is current thread and archived threads.
11131 return Smi::FromInt(n + 1);
11132}
11133
11134
11135static const int kThreadDetailsCurrentThreadIndex = 0;
11136static const int kThreadDetailsThreadIdIndex = 1;
11137static const int kThreadDetailsSize = 2;
11138
11139// Return an array with thread details
11140// args[0]: number: break id
11141// args[1]: number: thread index
11142//
11143// The array returned contains the following information:
11144// 0: Is current thread?
11145// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011146RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011147 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011148 ASSERT(args.length() == 2);
11149
11150 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011151 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011152 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11153 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011154 if (!maybe_check->ToObject(&check)) return maybe_check;
11155 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011156 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11157
11158 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011159 Handle<FixedArray> details =
11160 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011161
11162 // Thread index 0 is current thread.
11163 if (index == 0) {
11164 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011165 details->set(kThreadDetailsCurrentThreadIndex,
11166 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011167 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011168 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011169 } else {
11170 // Find the thread with the requested index.
11171 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011172 ThreadState* thread =
11173 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011174 while (index != n && thread != NULL) {
11175 thread = thread->Next();
11176 n++;
11177 }
11178 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011179 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011180 }
11181
11182 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011183 details->set(kThreadDetailsCurrentThreadIndex,
11184 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011185 details->set(kThreadDetailsThreadIdIndex,
11186 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011187 }
11188
11189 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011190 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011191}
11192
11193
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011194// Sets the disable break state
11195// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011196RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011197 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011198 ASSERT(args.length() == 1);
11199 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011200 isolate->debug()->set_disable_break(disable_break);
11201 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011202}
11203
11204
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011205RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011206 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011207 ASSERT(args.length() == 1);
11208
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011209 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11210 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011211 // Find the number of break points
11212 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011213 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011214 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011215 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011216 Handle<FixedArray>::cast(break_locations));
11217}
11218
11219
11220// Set a break point in a function
11221// args[0]: function
11222// args[1]: number: break source position (within the function source)
11223// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011224RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011225 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011226 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011227 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11228 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011229 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11230 RUNTIME_ASSERT(source_position >= 0);
11231 Handle<Object> break_point_object_arg = args.at<Object>(2);
11232
11233 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011234 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11235 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011236
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011237 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011238}
11239
11240
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011241Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11242 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011243 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011244 // Iterate the heap looking for SharedFunctionInfo generated from the
11245 // script. The inner most SharedFunctionInfo containing the source position
11246 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011247 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011248 // which is found is not compiled it is compiled and the heap is iterated
11249 // again as the compilation might create inner functions from the newly
11250 // compiled function and the actual requested break point might be in one of
11251 // these functions.
11252 bool done = false;
11253 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011254 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011256 while (!done) {
11257 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011258 for (HeapObject* obj = iterator.next();
11259 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011260 if (obj->IsSharedFunctionInfo()) {
11261 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11262 if (shared->script() == *script) {
11263 // If the SharedFunctionInfo found has the requested script data and
11264 // contains the source position it is a candidate.
11265 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011266 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011267 start_position = shared->start_position();
11268 }
11269 if (start_position <= position &&
11270 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011271 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011272 // candidate this is the new candidate.
11273 if (target.is_null()) {
11274 target_start_position = start_position;
11275 target = shared;
11276 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011277 if (target_start_position == start_position &&
11278 shared->end_position() == target->end_position()) {
11279 // If a top-level function contain only one function
11280 // declartion the source for the top-level and the function is
11281 // the same. In that case prefer the non top-level function.
11282 if (!shared->is_toplevel()) {
11283 target_start_position = start_position;
11284 target = shared;
11285 }
11286 } else if (target_start_position <= start_position &&
11287 shared->end_position() <= target->end_position()) {
11288 // This containment check includes equality as a function inside
11289 // a top-level function can share either start or end position
11290 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011291 target_start_position = start_position;
11292 target = shared;
11293 }
11294 }
11295 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011296 }
11297 }
11298 }
11299
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011300 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011301 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011302 }
11303
11304 // If the candidate found is compiled we are done. NOTE: when lazy
11305 // compilation of inner functions is introduced some additional checking
11306 // needs to be done here to compile inner functions.
11307 done = target->is_compiled();
11308 if (!done) {
11309 // If the candidate is not compiled compile it to reveal any inner
11310 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011311 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011312 }
11313 }
11314
11315 return *target;
11316}
11317
11318
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011319// Changes the state of a break point in a script and returns source position
11320// where break point was set. NOTE: Regarding performance see the NOTE for
11321// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011322// args[0]: script to set break point in
11323// args[1]: number: break source position (within the script source)
11324// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011325RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011326 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011327 ASSERT(args.length() == 3);
11328 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11329 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11330 RUNTIME_ASSERT(source_position >= 0);
11331 Handle<Object> break_point_object_arg = args.at<Object>(2);
11332
11333 // Get the script from the script wrapper.
11334 RUNTIME_ASSERT(wrapper->value()->IsScript());
11335 Handle<Script> script(Script::cast(wrapper->value()));
11336
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011337 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011338 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011339 if (!result->IsUndefined()) {
11340 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11341 // Find position within function. The script position might be before the
11342 // source position of the first function.
11343 int position;
11344 if (shared->start_position() > source_position) {
11345 position = 0;
11346 } else {
11347 position = source_position - shared->start_position();
11348 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011349 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011350 position += shared->start_position();
11351 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011352 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011353 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011354}
11355
11356
11357// Clear a break point
11358// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011359RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011360 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011361 ASSERT(args.length() == 1);
11362 Handle<Object> break_point_object_arg = args.at<Object>(0);
11363
11364 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011365 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011367 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011368}
11369
11370
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011371// Change the state of break on exceptions.
11372// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11373// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011374RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011375 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011376 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011377 RUNTIME_ASSERT(args[0]->IsNumber());
11378 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011379
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011380 // If the number doesn't match an enum value, the ChangeBreakOnException
11381 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011382 ExceptionBreakType type =
11383 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011384 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011385 isolate->debug()->ChangeBreakOnException(type, enable);
11386 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011387}
11388
11389
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011390// Returns the state of break on exceptions
11391// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011392RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011393 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011394 ASSERT(args.length() == 1);
11395 RUNTIME_ASSERT(args[0]->IsNumber());
11396
11397 ExceptionBreakType type =
11398 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011399 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011400 return Smi::FromInt(result);
11401}
11402
11403
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011404// Prepare for stepping
11405// args[0]: break id for checking execution state
11406// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011407// args[2]: number of times to perform the step, for step out it is the number
11408// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011409RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011410 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011411 ASSERT(args.length() == 3);
11412 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011413 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011414 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11415 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011416 if (!maybe_check->ToObject(&check)) return maybe_check;
11417 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011418 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011419 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011420 }
11421
11422 // Get the step action and check validity.
11423 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11424 if (step_action != StepIn &&
11425 step_action != StepNext &&
11426 step_action != StepOut &&
11427 step_action != StepInMin &&
11428 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011429 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011430 }
11431
11432 // Get the number of steps.
11433 int step_count = NumberToInt32(args[2]);
11434 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011435 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011436 }
11437
ager@chromium.orga1645e22009-09-09 19:27:10 +000011438 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011439 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011441 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011442 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11443 step_count);
11444 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011445}
11446
11447
11448// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011449RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011450 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011451 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011452 isolate->debug()->ClearStepping();
11453 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011454}
11455
11456
11457// Creates a copy of the with context chain. The copy of the context chain is
11458// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011459static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011460 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011461 Handle<Context> current,
11462 Handle<Context> base) {
11463 // At the end of the chain. Return the base context to link to.
11464 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11465 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011466 }
11467
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011468 // Recursively copy the with and catch contexts.
11469 HandleScope scope(isolate);
11470 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011471 Handle<Context> new_previous =
11472 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011473 Handle<Context> new_current;
11474 if (current->IsCatchContext()) {
11475 Handle<String> name(String::cast(current->extension()));
11476 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11477 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011478 isolate->factory()->NewCatchContext(function,
11479 new_previous,
11480 name,
11481 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011482 } else if (current->IsBlockContext()) {
11483 Handle<SerializedScopeInfo> scope_info(
11484 SerializedScopeInfo::cast(current->extension()));
11485 new_current =
11486 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011487 // Copy context slots.
11488 int num_context_slots = scope_info->NumberOfContextSlots();
11489 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11490 new_current->set(i, current->get(i));
11491 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011492 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011493 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011494 Handle<JSObject> extension(JSObject::cast(current->extension()));
11495 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011496 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011497 }
11498 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011499}
11500
11501
11502// Helper function to find or create the arguments object for
11503// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011504static Handle<Object> GetArgumentsObject(Isolate* isolate,
11505 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011506 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011507 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011508 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011509 const ScopeInfo<>* sinfo,
11510 Handle<Context> function_context) {
11511 // Try to find the value of 'arguments' to pass as parameter. If it is not
11512 // found (that is the debugged function does not reference 'arguments' and
11513 // does not support eval) then create an 'arguments' object.
11514 int index;
11515 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011516 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011517 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011518 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011519 }
11520 }
11521
11522 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011523 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11524 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011525 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527 }
11528 }
11529
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011530 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11531
11532 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011533 Handle<JSObject> arguments =
11534 isolate->factory()->NewArgumentsObject(function, length);
11535 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011536
11537 AssertNoAllocation no_gc;
11538 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011539 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011540 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011541 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011542 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011543 return arguments;
11544}
11545
11546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011547static const char kSourceStr[] =
11548 "(function(arguments,__source__){return eval(__source__);})";
11549
11550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011551// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011552// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011553// extension part has all the parameters and locals of the function on the
11554// stack frame. A function which calls eval with the code to evaluate is then
11555// compiled in this context and called in this context. As this context
11556// replaces the context of the function on the stack frame a new (empty)
11557// function is created as well to be used as the closure for the context.
11558// This function and the context acts as replacements for the function on the
11559// stack frame presenting the same view of the values of parameters and
11560// local variables as if the piece of JavaScript was evaluated at the point
11561// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011562RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011563 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011564
11565 // Check the execution state and decode arguments frame and source to be
11566 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011567 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011568 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011569 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11570 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011571 if (!maybe_check_result->ToObject(&check_result)) {
11572 return maybe_check_result;
11573 }
11574 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011575 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011576 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11577 CONVERT_ARG_CHECKED(String, source, 3);
11578 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11579 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011580
11581 // Handle the processing of break.
11582 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011583
11584 // Get the frame where the debugging is performed.
11585 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011586 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011587 JavaScriptFrame* frame = it.frame();
11588 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011589 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011590 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011591
11592 // Traverse the saved contexts chain to find the active context for the
11593 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011594 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011595 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011596 save = save->prev();
11597 }
11598 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011599 SaveContext savex(isolate);
11600 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601
11602 // Create the (empty) function replacing the function on the stack frame for
11603 // the purpose of evaluating in the context created below. It is important
11604 // that this function does not describe any parameters and local variables
11605 // in the context. If it does then this will cause problems with the lookup
11606 // in Context::Lookup, where context slots for parameters and local variables
11607 // are looked at before the extension object.
11608 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011609 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11610 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011611 go_between->set_context(function->context());
11612#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011613 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011614 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11615 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11616#endif
11617
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011618 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011619 Handle<JSObject> local_scope = MaterializeLocalScope(
11620 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011622
11623 // Allocate a new context for the debug evaluation and set the extension
11624 // object build.
11625 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11627 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011628 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011629 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011630 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011631 Handle<Context> function_context;
11632 // Get the function's context if it has one.
11633 if (scope_info->HasHeapAllocatedLocals()) {
11634 function_context = Handle<Context>(frame_context->declaration_context());
11635 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011636 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011638 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011639 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011640 context =
11641 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011642 }
11643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011644 // Wrap the evaluation statement in a new function compiled in the newly
11645 // created context. The function has one parameter which has to be called
11646 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011647 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011648 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011650 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011651 isolate->factory()->NewStringFromAscii(
11652 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011653
11654 // Currently, the eval code will be executed in non-strict mode,
11655 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011656 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011657 Compiler::CompileEval(function_source,
11658 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011659 context->IsGlobalContext(),
11660 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011661 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011662 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011663 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011664
11665 // Invoke the result of the compilation to get the evaluation function.
11666 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011668 Handle<Object> evaluation_function =
11669 Execution::Call(compiled_function, receiver, 0, NULL,
11670 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011671 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011673 Handle<Object> arguments = GetArgumentsObject(isolate,
11674 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011676 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011677
11678 // Invoke the evaluation function and return the result.
11679 const int argc = 2;
11680 Object** argv[argc] = { arguments.location(),
11681 Handle<Object>::cast(source).location() };
11682 Handle<Object> result =
11683 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11684 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011685 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011686
11687 // Skip the global proxy as it has no properties and always delegates to the
11688 // real global object.
11689 if (result->IsJSGlobalProxy()) {
11690 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11691 }
11692
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011693 return *result;
11694}
11695
11696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011697RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011698 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011699
11700 // Check the execution state and decode arguments frame and source to be
11701 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011702 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011703 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011704 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11705 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011706 if (!maybe_check_result->ToObject(&check_result)) {
11707 return maybe_check_result;
11708 }
11709 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011710 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011711 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011712 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011713
11714 // Handle the processing of break.
11715 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011716
11717 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011719 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011720 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011721 top = top->prev();
11722 }
11723 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011725 }
11726
11727 // Get the global context now set to the top context from before the
11728 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011730
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011731 bool is_global = true;
11732
11733 if (additional_context->IsJSObject()) {
11734 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011735 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11736 isolate->factory()->empty_string(),
11737 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011738 go_between->set_context(*context);
11739 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011740 isolate->factory()->NewFunctionContext(
11741 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011742 context->set_extension(JSObject::cast(*additional_context));
11743 is_global = false;
11744 }
11745
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011746 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011747 // Currently, the eval code will be executed in non-strict mode,
11748 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011749 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011750 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011751 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011752 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011753 Handle<JSFunction>(
11754 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11755 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756
11757 // Invoke the result of the compilation to get the evaluation function.
11758 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011759 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 Handle<Object> result =
11761 Execution::Call(compiled_function, receiver, 0, NULL,
11762 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011763 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764 return *result;
11765}
11766
11767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011768RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011769 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011770 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011771
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774
11775 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011776 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011777 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11778 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11779 // because using
11780 // instances->set(i, *GetScriptWrapper(script))
11781 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11782 // already have deferenced the instances handle.
11783 Handle<JSValue> wrapper = GetScriptWrapper(script);
11784 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011785 }
11786
11787 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011788 Handle<JSObject> result =
11789 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790 Handle<JSArray>::cast(result)->SetContent(*instances);
11791 return *result;
11792}
11793
11794
11795// Helper function used by Runtime_DebugReferencedBy below.
11796static int DebugReferencedBy(JSObject* target,
11797 Object* instance_filter, int max_references,
11798 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011799 JSFunction* arguments_function) {
11800 NoHandleAllocation ha;
11801 AssertNoAllocation no_alloc;
11802
11803 // Iterate the heap.
11804 int count = 0;
11805 JSObject* last = NULL;
11806 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011807 HeapObject* heap_obj = NULL;
11808 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011809 (max_references == 0 || count < max_references)) {
11810 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011811 if (heap_obj->IsJSObject()) {
11812 // Skip context extension objects and argument arrays as these are
11813 // checked in the context of functions using them.
11814 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011815 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816 obj->map()->constructor() == arguments_function) {
11817 continue;
11818 }
11819
11820 // Check if the JS object has a reference to the object looked for.
11821 if (obj->ReferencesObject(target)) {
11822 // Check instance filter if supplied. This is normally used to avoid
11823 // references from mirror objects (see Runtime_IsInPrototypeChain).
11824 if (!instance_filter->IsUndefined()) {
11825 Object* V = obj;
11826 while (true) {
11827 Object* prototype = V->GetPrototype();
11828 if (prototype->IsNull()) {
11829 break;
11830 }
11831 if (instance_filter == prototype) {
11832 obj = NULL; // Don't add this object.
11833 break;
11834 }
11835 V = prototype;
11836 }
11837 }
11838
11839 if (obj != NULL) {
11840 // Valid reference found add to instance array if supplied an update
11841 // count.
11842 if (instances != NULL && count < instances_size) {
11843 instances->set(count, obj);
11844 }
11845 last = obj;
11846 count++;
11847 }
11848 }
11849 }
11850 }
11851
11852 // Check for circular reference only. This can happen when the object is only
11853 // referenced from mirrors and has a circular reference in which case the
11854 // object is not really alive and would have been garbage collected if not
11855 // referenced from the mirror.
11856 if (count == 1 && last == target) {
11857 count = 0;
11858 }
11859
11860 // Return the number of referencing objects found.
11861 return count;
11862}
11863
11864
11865// Scan the heap for objects with direct references to an object
11866// args[0]: the object to find references to
11867// args[1]: constructor function for instances to exclude (Mirror)
11868// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011869RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011870 ASSERT(args.length() == 3);
11871
11872 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011873 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011874
11875 // Check parameters.
11876 CONVERT_CHECKED(JSObject, target, args[0]);
11877 Object* instance_filter = args[1];
11878 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11879 instance_filter->IsJSObject());
11880 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11881 RUNTIME_ASSERT(max_references >= 0);
11882
11883 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011884 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011885 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011886 JSFunction* arguments_function =
11887 JSFunction::cast(arguments_boilerplate->map()->constructor());
11888
11889 // Get the number of referencing objects.
11890 int count;
11891 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011892 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893
11894 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011895 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011896 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011897 if (!maybe_object->ToObject(&object)) return maybe_object;
11898 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011899 FixedArray* instances = FixedArray::cast(object);
11900
11901 // Fill the referencing objects.
11902 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011903 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904
11905 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011906 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011907 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11908 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011909 if (!maybe_result->ToObject(&result)) return maybe_result;
11910 }
11911 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011912 return result;
11913}
11914
11915
11916// Helper function used by Runtime_DebugConstructedBy below.
11917static int DebugConstructedBy(JSFunction* constructor, int max_references,
11918 FixedArray* instances, int instances_size) {
11919 AssertNoAllocation no_alloc;
11920
11921 // Iterate the heap.
11922 int count = 0;
11923 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011924 HeapObject* heap_obj = NULL;
11925 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011926 (max_references == 0 || count < max_references)) {
11927 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928 if (heap_obj->IsJSObject()) {
11929 JSObject* obj = JSObject::cast(heap_obj);
11930 if (obj->map()->constructor() == constructor) {
11931 // Valid reference found add to instance array if supplied an update
11932 // count.
11933 if (instances != NULL && count < instances_size) {
11934 instances->set(count, obj);
11935 }
11936 count++;
11937 }
11938 }
11939 }
11940
11941 // Return the number of referencing objects found.
11942 return count;
11943}
11944
11945
11946// Scan the heap for objects constructed by a specific function.
11947// args[0]: the constructor to find instances of
11948// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011949RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011950 ASSERT(args.length() == 2);
11951
11952 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011953 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011954
11955 // Check parameters.
11956 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11957 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11958 RUNTIME_ASSERT(max_references >= 0);
11959
11960 // Get the number of referencing objects.
11961 int count;
11962 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11963
11964 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011965 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011966 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011967 if (!maybe_object->ToObject(&object)) return maybe_object;
11968 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969 FixedArray* instances = FixedArray::cast(object);
11970
11971 // Fill the referencing objects.
11972 count = DebugConstructedBy(constructor, max_references, instances, count);
11973
11974 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011975 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011976 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11977 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011978 if (!maybe_result->ToObject(&result)) return maybe_result;
11979 }
11980 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011981 return result;
11982}
11983
11984
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011985// Find the effective prototype object as returned by __proto__.
11986// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011987RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988 ASSERT(args.length() == 1);
11989
11990 CONVERT_CHECKED(JSObject, obj, args[0]);
11991
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011992 // Use the __proto__ accessor.
11993 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011994}
11995
11996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011997RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011998 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011999 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012000 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012001}
12002
12003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012004RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012005#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012006 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012007 ASSERT(args.length() == 1);
12008 // Get the function and make sure it is compiled.
12009 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012010 Handle<SharedFunctionInfo> shared(func->shared());
12011 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012012 return Failure::Exception();
12013 }
12014 func->code()->PrintLn();
12015#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012016 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012017}
ager@chromium.org9085a012009-05-11 19:22:57 +000012018
12019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012020RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012021#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012022 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012023 ASSERT(args.length() == 1);
12024 // Get the function and make sure it is compiled.
12025 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012026 Handle<SharedFunctionInfo> shared(func->shared());
12027 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012028 return Failure::Exception();
12029 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012030 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012031#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012032 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012033}
12034
12035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012036RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012037 NoHandleAllocation ha;
12038 ASSERT(args.length() == 1);
12039
12040 CONVERT_CHECKED(JSFunction, f, args[0]);
12041 return f->shared()->inferred_name();
12042}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012043
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012044
12045static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012046 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012047 AssertNoAllocation no_allocations;
12048
12049 int counter = 0;
12050 int buffer_size = buffer->length();
12051 HeapIterator iterator;
12052 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
12053 ASSERT(obj != NULL);
12054 if (!obj->IsSharedFunctionInfo()) {
12055 continue;
12056 }
12057 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12058 if (shared->script() != script) {
12059 continue;
12060 }
12061 if (counter < buffer_size) {
12062 buffer->set(counter, shared);
12063 }
12064 counter++;
12065 }
12066 return counter;
12067}
12068
12069// For a script finds all SharedFunctionInfo's in the heap that points
12070// to this script. Returns JSArray of SharedFunctionInfo wrapped
12071// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012072RUNTIME_FUNCTION(MaybeObject*,
12073 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012074 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012075 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012076 CONVERT_CHECKED(JSValue, script_value, args[0]);
12077
12078 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12079
12080 const int kBufferSize = 32;
12081
12082 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012083 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012084 int number = FindSharedFunctionInfosForScript(*script, *array);
12085 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012086 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012087 FindSharedFunctionInfosForScript(*script, *array);
12088 }
12089
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012090 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012091 result->set_length(Smi::FromInt(number));
12092
12093 LiveEdit::WrapSharedFunctionInfos(result);
12094
12095 return *result;
12096}
12097
12098// For a script calculates compilation information about all its functions.
12099// The script source is explicitly specified by the second argument.
12100// The source of the actual script is not used, however it is important that
12101// all generated code keeps references to this particular instance of script.
12102// Returns a JSArray of compilation infos. The array is ordered so that
12103// each function with all its descendant is always stored in a continues range
12104// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012105RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012106 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012107 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012108 CONVERT_CHECKED(JSValue, script, args[0]);
12109 CONVERT_ARG_CHECKED(String, source, 1);
12110 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12111
12112 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012114 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012115 return Failure::Exception();
12116 }
12117
12118 return result;
12119}
12120
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012121// Changes the source of the script to a new_source.
12122// If old_script_name is provided (i.e. is a String), also creates a copy of
12123// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012124RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012125 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012126 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012127 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12128 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012129 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012130
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012131 CONVERT_CHECKED(Script, original_script_pointer,
12132 original_script_value->value());
12133 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012134
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012135 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12136 new_source,
12137 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012138
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012139 if (old_script->IsScript()) {
12140 Handle<Script> script_handle(Script::cast(old_script));
12141 return *(GetScriptWrapper(script_handle));
12142 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012143 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012144 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012145}
12146
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012148RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012149 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012150 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012151 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12152 return LiveEdit::FunctionSourceUpdated(shared_info);
12153}
12154
12155
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012156// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012157RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012158 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012159 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012160 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12161 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12162
ager@chromium.orgac091b72010-05-05 07:34:42 +000012163 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012164}
12165
12166// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012167RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012168 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012169 HandleScope scope(isolate);
12170 Handle<Object> function_object(args[0], isolate);
12171 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012172
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012173 if (function_object->IsJSValue()) {
12174 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12175 if (script_object->IsJSValue()) {
12176 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012177 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012178 }
12179
12180 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12181 } else {
12182 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12183 // and we check it in this function.
12184 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012185
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012186 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012187}
12188
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012189
12190// In a code of a parent function replaces original function as embedded object
12191// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012192RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012193 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012194 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012195
12196 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12197 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12198 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12199
12200 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12201 subst_wrapper);
12202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012203 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012204}
12205
12206
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012207// Updates positions of a shared function info (first parameter) according
12208// to script source change. Text change is described in second parameter as
12209// array of groups of 3 numbers:
12210// (change_begin, change_end, change_end_new_position).
12211// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012212RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012213 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012214 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012215 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12216 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12217
ager@chromium.orgac091b72010-05-05 07:34:42 +000012218 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012219}
12220
12221
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012222// For array of SharedFunctionInfo's (each wrapped in JSValue)
12223// checks that none of them have activations on stacks (of any thread).
12224// Returns array of the same length with corresponding results of
12225// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012226RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012227 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012228 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012229 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012230 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012231
ager@chromium.org357bf652010-04-12 11:30:10 +000012232 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012233}
12234
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012235// Compares 2 strings line-by-line, then token-wise and returns diff in form
12236// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12237// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012238RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012239 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012240 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012241 CONVERT_ARG_CHECKED(String, s1, 0);
12242 CONVERT_ARG_CHECKED(String, s2, 1);
12243
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012244 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012245}
12246
12247
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012248// A testing entry. Returns statement position which is the closest to
12249// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012250RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012251 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012252 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012253 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12254 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12255
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012256 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012257
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012258 if (code->kind() != Code::FUNCTION &&
12259 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012260 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012261 }
12262
12263 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012264 int closest_pc = 0;
12265 int distance = kMaxInt;
12266 while (!it.done()) {
12267 int statement_position = static_cast<int>(it.rinfo()->data());
12268 // Check if this break point is closer that what was previously found.
12269 if (source_position <= statement_position &&
12270 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012271 closest_pc =
12272 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012273 distance = statement_position - source_position;
12274 // Check whether we can't get any closer.
12275 if (distance == 0) break;
12276 }
12277 it.next();
12278 }
12279
12280 return Smi::FromInt(closest_pc);
12281}
12282
12283
ager@chromium.org357bf652010-04-12 11:30:10 +000012284// Calls specified function with or without entering the debugger.
12285// This is used in unit tests to run code as if debugger is entered or simply
12286// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012287RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012288 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012289 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012290 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12291 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12292
12293 Handle<Object> result;
12294 bool pending_exception;
12295 {
12296 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012297 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012298 &pending_exception);
12299 } else {
12300 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012301 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012302 &pending_exception);
12303 }
12304 }
12305 if (!pending_exception) {
12306 return *result;
12307 } else {
12308 return Failure::Exception();
12309 }
12310}
12311
12312
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012313// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012314RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012315 CONVERT_CHECKED(String, arg, args[0]);
12316 SmartPointer<char> flags =
12317 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12318 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012319 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012320}
12321
12322
12323// Performs a GC.
12324// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012325RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012326 isolate->heap()->CollectAllGarbage(true);
12327 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012328}
12329
12330
12331// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012332RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012333 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012334 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012335 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012336 }
12337 return Smi::FromInt(usage);
12338}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012339
12340
12341// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012342RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012343#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012344 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012345#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012346 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012347#endif
12348}
12349
12350
12351// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012352RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012353#ifdef LIVE_OBJECT_LIST
12354 return LiveObjectList::Capture();
12355#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012356 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012357#endif
12358}
12359
12360
12361// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012362RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012363#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012364 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012365 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012366 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012367#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012368 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012369#endif
12370}
12371
12372
12373// Generates the response to a debugger request for a dump of the objects
12374// contained in the difference between the captured live object lists
12375// specified by id1 and id2.
12376// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12377// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012378RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012379#ifdef LIVE_OBJECT_LIST
12380 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012381 CONVERT_SMI_ARG_CHECKED(id1, 0);
12382 CONVERT_SMI_ARG_CHECKED(id2, 1);
12383 CONVERT_SMI_ARG_CHECKED(start, 2);
12384 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012385 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12386 EnterDebugger enter_debugger;
12387 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12388#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012389 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012390#endif
12391}
12392
12393
12394// Gets the specified object as requested by the debugger.
12395// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012396RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012397#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012398 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012399 Object* result = LiveObjectList::GetObj(obj_id);
12400 return result;
12401#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012402 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012403#endif
12404}
12405
12406
12407// Gets the obj id for the specified address if valid.
12408// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012409RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012410#ifdef LIVE_OBJECT_LIST
12411 HandleScope scope;
12412 CONVERT_ARG_CHECKED(String, address, 0);
12413 Object* result = LiveObjectList::GetObjId(address);
12414 return result;
12415#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012416 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012417#endif
12418}
12419
12420
12421// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012422RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012423#ifdef LIVE_OBJECT_LIST
12424 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012425 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012426 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12427 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12428 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12429 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12430 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12431
12432 Handle<JSObject> instance_filter;
12433 if (args[1]->IsJSObject()) {
12434 instance_filter = args.at<JSObject>(1);
12435 }
12436 bool verbose = false;
12437 if (args[2]->IsBoolean()) {
12438 verbose = args[2]->IsTrue();
12439 }
12440 int start = 0;
12441 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012442 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012443 }
12444 int limit = Smi::kMaxValue;
12445 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012446 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012447 }
12448
12449 return LiveObjectList::GetObjRetainers(obj_id,
12450 instance_filter,
12451 verbose,
12452 start,
12453 limit,
12454 filter_obj);
12455#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012456 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012457#endif
12458}
12459
12460
12461// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012462RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012463#ifdef LIVE_OBJECT_LIST
12464 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012465 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12466 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012467 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12468
12469 Handle<JSObject> instance_filter;
12470 if (args[2]->IsJSObject()) {
12471 instance_filter = args.at<JSObject>(2);
12472 }
12473
12474 Object* result =
12475 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12476 return result;
12477#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012478 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012479#endif
12480}
12481
12482
12483// Generates the response to a debugger request for a list of all
12484// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012485RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012486#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012487 CONVERT_SMI_ARG_CHECKED(start, 0);
12488 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012489 return LiveObjectList::Info(start, count);
12490#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012491 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012492#endif
12493}
12494
12495
12496// Gets a dump of the specified object as requested by the debugger.
12497// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012498RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012499#ifdef LIVE_OBJECT_LIST
12500 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012501 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012502 Object* result = LiveObjectList::PrintObj(obj_id);
12503 return result;
12504#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012505 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012506#endif
12507}
12508
12509
12510// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012511RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012512#ifdef LIVE_OBJECT_LIST
12513 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012514 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012515#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012516 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012517#endif
12518}
12519
12520
12521// Generates the response to a debugger request for a summary of the types
12522// of objects in the difference between the captured live object lists
12523// specified by id1 and id2.
12524// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12525// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012526RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012527#ifdef LIVE_OBJECT_LIST
12528 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012529 CONVERT_SMI_ARG_CHECKED(id1, 0);
12530 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012531 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12532
12533 EnterDebugger enter_debugger;
12534 return LiveObjectList::Summarize(id1, id2, filter_obj);
12535#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012536 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012537#endif
12538}
12539
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012540#endif // ENABLE_DEBUGGER_SUPPORT
12541
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012543RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012544 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012545 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012546 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012547}
12548
12549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012550RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012551 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012552 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012553 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012554}
12555
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012556
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012557// Finds the script object from the script data. NOTE: This operation uses
12558// heap traversal to find the function generated for the source position
12559// for the requested break point. For lazily compiled functions several heap
12560// traversals might be required rendering this operation as a rather slow
12561// operation. However for setting break points which is normally done through
12562// some kind of user interaction the performance is not crucial.
12563static Handle<Object> Runtime_GetScriptFromScriptName(
12564 Handle<String> script_name) {
12565 // Scan the heap for Script objects to find the script with the requested
12566 // script data.
12567 Handle<Script> script;
12568 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012569 HeapObject* obj = NULL;
12570 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012571 // If a script is found check if it has the script data requested.
12572 if (obj->IsScript()) {
12573 if (Script::cast(obj)->name()->IsString()) {
12574 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12575 script = Handle<Script>(Script::cast(obj));
12576 }
12577 }
12578 }
12579 }
12580
12581 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012582 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012583
12584 // Return the script found.
12585 return GetScriptWrapper(script);
12586}
12587
12588
12589// Get the script object from script data. NOTE: Regarding performance
12590// see the NOTE for GetScriptFromScriptData.
12591// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012592RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012593 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012594
12595 ASSERT(args.length() == 1);
12596
12597 CONVERT_CHECKED(String, script_name, args[0]);
12598
12599 // Find the requested script.
12600 Handle<Object> result =
12601 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12602 return *result;
12603}
12604
12605
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012606// Determines whether the given stack frame should be displayed in
12607// a stack trace. The caller is the error constructor that asked
12608// for the stack trace to be collected. The first time a construct
12609// call to this function is encountered it is skipped. The seen_caller
12610// in/out parameter is used to remember if the caller has been seen
12611// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012612static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12613 Object* caller,
12614 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012615 // Only display JS frames.
12616 if (!raw_frame->is_java_script())
12617 return false;
12618 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12619 Object* raw_fun = frame->function();
12620 // Not sure when this can happen but skip it just in case.
12621 if (!raw_fun->IsJSFunction())
12622 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012623 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012624 *seen_caller = true;
12625 return false;
12626 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012627 // Skip all frames until we've seen the caller.
12628 if (!(*seen_caller)) return false;
12629 // Also, skip the most obvious builtin calls. We recognize builtins
12630 // as (1) functions called with the builtins object as the receiver and
12631 // as (2) functions from native scripts called with undefined as the
12632 // receiver (direct calls to helper functions in the builtins
12633 // code). Some builtin calls (such as Number.ADD which is invoked
12634 // using 'call') are very difficult to recognize so we're leaving
12635 // them in for now.
12636 if (frame->receiver()->IsJSBuiltinsObject()) {
12637 return false;
12638 }
12639 JSFunction* fun = JSFunction::cast(raw_fun);
12640 Object* raw_script = fun->shared()->script();
12641 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12642 int script_type = Script::cast(raw_script)->type()->value();
12643 return script_type != Script::TYPE_NATIVE;
12644 }
12645 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012646}
12647
12648
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012649// Collect the raw data for a stack trace. Returns an array of 4
12650// element segments each containing a receiver, function, code and
12651// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012652RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012653 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012654 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012655 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12656
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012657 HandleScope scope(isolate);
12658 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012659
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012660 limit = Max(limit, 0); // Ensure that limit is not negative.
12661 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012662 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012663 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012664
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012665 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012666 // If the caller parameter is a function we skip frames until we're
12667 // under it before starting to collect.
12668 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012669 int cursor = 0;
12670 int frames_seen = 0;
12671 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012672 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012673 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012674 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012675 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012676 // Set initial size to the maximum inlining level + 1 for the outermost
12677 // function.
12678 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012679 frame->Summarize(&frames);
12680 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012681 if (cursor + 4 > elements->length()) {
12682 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12683 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012684 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012685 for (int i = 0; i < cursor; i++) {
12686 new_elements->set(i, elements->get(i));
12687 }
12688 elements = new_elements;
12689 }
12690 ASSERT(cursor + 4 <= elements->length());
12691
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012692 Handle<Object> recv = frames[i].receiver();
12693 Handle<JSFunction> fun = frames[i].function();
12694 Handle<Code> code = frames[i].code();
12695 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012696 elements->set(cursor++, *recv);
12697 elements->set(cursor++, *fun);
12698 elements->set(cursor++, *code);
12699 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012700 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012701 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012702 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012703 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012705 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012706 return *result;
12707}
12708
12709
ager@chromium.org3811b432009-10-28 14:53:37 +000012710// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012711RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012712 ASSERT_EQ(args.length(), 0);
12713
12714 NoHandleAllocation ha;
12715
12716 const char* version_string = v8::V8::GetVersion();
12717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012718 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12719 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012720}
12721
12722
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012723RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012724 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012725 OS::PrintError("abort: %s\n",
12726 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012727 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012728 OS::Abort();
12729 UNREACHABLE();
12730 return NULL;
12731}
12732
12733
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012734RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012735 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012736 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012737 Object* key = args[1];
12738
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012739 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012740 Object* o = cache->get(finger_index);
12741 if (o == key) {
12742 // The fastest case: hit the same place again.
12743 return cache->get(finger_index + 1);
12744 }
12745
12746 for (int i = finger_index - 2;
12747 i >= JSFunctionResultCache::kEntriesIndex;
12748 i -= 2) {
12749 o = cache->get(i);
12750 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012751 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012752 return cache->get(i + 1);
12753 }
12754 }
12755
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012756 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012757 ASSERT(size <= cache->length());
12758
12759 for (int i = size - 2; i > finger_index; i -= 2) {
12760 o = cache->get(i);
12761 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012762 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012763 return cache->get(i + 1);
12764 }
12765 }
12766
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012767 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012768 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012769
12770 Handle<JSFunctionResultCache> cache_handle(cache);
12771 Handle<Object> key_handle(key);
12772 Handle<Object> value;
12773 {
12774 Handle<JSFunction> factory(JSFunction::cast(
12775 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12776 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012777 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012778 // This handle is nor shared, nor used later, so it's safe.
12779 Object** argv[] = { key_handle.location() };
12780 bool pending_exception = false;
12781 value = Execution::Call(factory,
12782 receiver,
12783 1,
12784 argv,
12785 &pending_exception);
12786 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012787 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012788
12789#ifdef DEBUG
12790 cache_handle->JSFunctionResultCacheVerify();
12791#endif
12792
12793 // Function invocation may have cleared the cache. Reread all the data.
12794 finger_index = cache_handle->finger_index();
12795 size = cache_handle->size();
12796
12797 // If we have spare room, put new data into it, otherwise evict post finger
12798 // entry which is likely to be the least recently used.
12799 int index = -1;
12800 if (size < cache_handle->length()) {
12801 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12802 index = size;
12803 } else {
12804 index = finger_index + JSFunctionResultCache::kEntrySize;
12805 if (index == cache_handle->length()) {
12806 index = JSFunctionResultCache::kEntriesIndex;
12807 }
12808 }
12809
12810 ASSERT(index % 2 == 0);
12811 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12812 ASSERT(index < cache_handle->length());
12813
12814 cache_handle->set(index, *key_handle);
12815 cache_handle->set(index + 1, *value);
12816 cache_handle->set_finger_index(index);
12817
12818#ifdef DEBUG
12819 cache_handle->JSFunctionResultCacheVerify();
12820#endif
12821
12822 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012823}
12824
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012826RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012827 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012828 CONVERT_ARG_CHECKED(String, type, 0);
12829 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012830 return *isolate->factory()->NewJSMessageObject(
12831 type,
12832 arguments,
12833 0,
12834 0,
12835 isolate->factory()->undefined_value(),
12836 isolate->factory()->undefined_value(),
12837 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012838}
12839
12840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012841RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012842 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12843 return message->type();
12844}
12845
12846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012847RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012848 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12849 return message->arguments();
12850}
12851
12852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012853RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012854 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12855 return Smi::FromInt(message->start_position());
12856}
12857
12858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012859RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012860 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12861 return message->script();
12862}
12863
12864
kasper.lund44510672008-07-25 07:37:58 +000012865#ifdef DEBUG
12866// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12867// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012868RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012869 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012870 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012871#define COUNT_ENTRY(Name, argc, ressize) + 1
12872 int entry_count = 0
12873 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12874 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12875 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12876#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012877 Factory* factory = isolate->factory();
12878 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012879 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012880 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012881#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012882 { \
12883 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012884 Handle<String> name; \
12885 /* Inline runtime functions have an underscore in front of the name. */ \
12886 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012887 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012888 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12889 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012890 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012891 Vector<const char>(#Name, StrLength(#Name))); \
12892 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012893 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012894 pair_elements->set(0, *name); \
12895 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012896 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012897 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012898 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012899 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012900 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012901 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012902 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012903 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012904#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012905 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012906 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012907 return *result;
12908}
kasper.lund44510672008-07-25 07:37:58 +000012909#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012910
12911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012912RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012913 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012914 CONVERT_CHECKED(String, format, args[0]);
12915 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000012916 String::FlatContent format_content = format->GetFlatContent();
12917 RUNTIME_ASSERT(format_content.IsAscii());
12918 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012919 LOGGER->LogRuntime(chars, elms);
12920 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012921}
12922
12923
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012924RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012925 UNREACHABLE(); // implemented as macro in the parser
12926 return NULL;
12927}
12928
12929
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012930#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12931 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12932 CONVERT_CHECKED(JSObject, obj, args[0]); \
12933 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12934 }
12935
12936ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12937ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12938ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12939ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12940ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12941ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12942ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12943ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12944ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12945ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12946ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12947ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12948ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12949
12950#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12951
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012952// ----------------------------------------------------------------------------
12953// Implementation of Runtime
12954
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012955#define F(name, number_of_args, result_size) \
12956 { Runtime::k##name, Runtime::RUNTIME, #name, \
12957 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012958
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012959
12960#define I(name, number_of_args, result_size) \
12961 { Runtime::kInline##name, Runtime::INLINE, \
12962 "_" #name, NULL, number_of_args, result_size },
12963
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012964static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012965 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012966 INLINE_FUNCTION_LIST(I)
12967 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012968};
12969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012970
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012971MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12972 Object* dictionary) {
12973 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012974 ASSERT(dictionary != NULL);
12975 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12976 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012977 Object* name_symbol;
12978 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012979 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012980 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12981 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012982 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012983 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12984 String::cast(name_symbol),
12985 Smi::FromInt(i),
12986 PropertyDetails(NONE, NORMAL));
12987 if (!maybe_dictionary->ToObject(&dictionary)) {
12988 // Non-recoverable failure. Calling code must restart heap
12989 // initialization.
12990 return maybe_dictionary;
12991 }
12992 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012993 }
12994 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012995}
12996
12997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012998const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12999 Heap* heap = name->GetHeap();
13000 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013001 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013002 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013003 int function_index = Smi::cast(smi_index)->value();
13004 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013005 }
13006 return NULL;
13007}
13008
13009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013010const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013011 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13012}
13013
13014
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013015void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013016 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013017 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013018 if (failure->IsRetryAfterGC()) {
13019 // Try to do a garbage collection; ignore it if it fails. The C
13020 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013021 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013022 } else {
13023 // Handle last resort GC and make sure to allow future allocations
13024 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013025 isolate->counters()->gc_last_resort_from_js()->Increment();
13026 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013027 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013028}
13029
13030
13031} } // namespace v8::internal